diff --git a/lib/widgets/home.dart b/lib/widgets/home.dart index 62c09c0857..bca19170ac 100644 --- a/lib/widgets/home.dart +++ b/lib/widgets/home.dart @@ -84,6 +84,23 @@ class _HomePageState extends State { } } + List? get _currentTabAppBarActions { + switch(_tab.value) { + case _HomePageTab.inbox: + return [ + IconButton( + icon: const Icon(ZulipIcons.search), + tooltip: ZulipLocalizations.of(context).searchMessagesPageTitle, + onPressed: () => Navigator.of(context).push(MessageListPage.buildRoute( + context: context, narrow: KeywordSearchNarrow(''))), + ), + ]; + case _HomePageTab.channels: + case _HomePageTab.directMessages: + return null; + } + } + @override Widget build(BuildContext context) { const pageBodies = [ @@ -120,7 +137,9 @@ class _HomePageState extends State { final designVariables = DesignVariables.of(context); return Scaffold( appBar: ZulipAppBar(titleSpacing: 16, - title: Text(_currentTabTitle)), + title: Text(_currentTabTitle), + actions: _currentTabAppBarActions + ), body: Stack( children: [ for (final (tab, body) in pageBodies) diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index 77e2e8cb24..15cc761948 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -416,6 +416,12 @@ abstract class _MessageListAppBar { List actions = []; switch (narrow) { case CombinedFeedNarrow(): + actions.add(IconButton( + icon: const Icon(ZulipIcons.search), + tooltip: zulipLocalizations.searchMessagesPageTitle, + onPressed: () => Navigator.push(context, + MessageListPage.buildRoute(context: context, + narrow: KeywordSearchNarrow(''))))); case MentionsNarrow(): case StarredMessagesNarrow(): case KeywordSearchNarrow(): diff --git a/test/widgets/home_test.dart b/test/widgets/home_test.dart index 1ee0a0ae8e..43fed8fd23 100644 --- a/test/widgets/home_test.dart +++ b/test/widgets/home_test.dart @@ -111,24 +111,31 @@ void main () { check(find.byIcon(ZulipIcons.arrow_right)).findsExactly(2); }); - testWidgets('update app bar title when switching between views', (tester) async { + testWidgets('update app bar title and actions when switching between views', (tester) async { await prepare(tester); + final findSearchButton = find.descendant( + of: find.byType(ZulipAppBar), + matching: find.byIcon(ZulipIcons.search)); + check(find.descendant( of: find.byType(ZulipAppBar), matching: find.text('Inbox'))).findsOne(); + check(findSearchButton).findsOne(); await tester.tap(find.byIcon(ZulipIcons.hash_italic)); await tester.pump(); check(find.descendant( of: find.byType(ZulipAppBar), matching: find.text('Channels'))).findsOne(); + check(findSearchButton).findsNothing(); await tester.tap(find.byIcon(ZulipIcons.two_person)); await tester.pump(); check(find.descendant( of: find.byType(ZulipAppBar), matching: find.text('Direct messages'))).findsOne(); + check(findSearchButton).findsNothing(); }); testWidgets('combined feed', (tester) async { diff --git a/test/widgets/inbox_test.dart b/test/widgets/inbox_test.dart index fe96b427ab..ff8e0a32ee 100644 --- a/test/widgets/inbox_test.dart +++ b/test/widgets/inbox_test.dart @@ -4,17 +4,23 @@ import 'package:flutter_checks/flutter_checks.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:zulip/api/model/events.dart'; import 'package:zulip/api/model/model.dart'; +import 'package:zulip/model/narrow.dart'; import 'package:zulip/model/store.dart'; +import 'package:zulip/widgets/app_bar.dart'; import 'package:zulip/widgets/color.dart'; import 'package:zulip/widgets/home.dart'; import 'package:zulip/widgets/icons.dart'; import 'package:zulip/widgets/channel_colors.dart'; +import 'package:zulip/widgets/message_list.dart'; +import 'package:zulip/widgets/page.dart'; import 'package:zulip/widgets/unread_count_badge.dart'; import '../example_data.dart' as eg; import '../flutter_checks.dart'; import '../model/binding.dart'; import '../model/test_store.dart'; +import '../test_navigation.dart'; +import 'checks.dart'; import 'test_app.dart'; /// Repeatedly drags `view` by `moveStep` until `finder` is invisible. @@ -649,5 +655,27 @@ void main() { // reappear because you unmuted a conversation.) }); }); + + testWidgets('tapping search button navigates to search page', (tester) async { + final pushedRoutes = >[]; + final testNavObserver = TestNavigatorObserver() + ..onPushed = (route, prevRoute) => pushedRoutes.add(route); + + await setupPage(tester, + unreadMessages: [], + navigatorObserver: testNavObserver); + + assert(pushedRoutes.length == 1); + pushedRoutes.clear(); + + await tester.tap(find.descendant( + of: find.byType(ZulipAppBar), + matching: find.byIcon(ZulipIcons.search))); + await tester.pump(); + + check(pushedRoutes).single.isA().page + .isA() + .initNarrow.equals(KeywordSearchNarrow('')); + }); }); } diff --git a/test/widgets/message_list_test.dart b/test/widgets/message_list_test.dart index acdde3fd2c..360177fbef 100644 --- a/test/widgets/message_list_test.dart +++ b/test/widgets/message_list_test.dart @@ -363,6 +363,35 @@ void main() { check(find.text('DMs with Muted user, User 2, Muted user')).findsOne(); }); + + testWidgets('search button on combined feed navigates to search page', (tester) async { + final pushedRoutes = >[]; + final testNavObserver = TestNavigatorObserver() + ..onPushed = (route, prevRoute) => pushedRoutes.add(route); + + await setupMessageListPage(tester, + narrow: const CombinedFeedNarrow(), + messages: [], + navObservers: [testNavObserver]); + + final searchButtonFinder = find.descendant( + of: find.byType(ZulipAppBar), + matching: find.byIcon(ZulipIcons.search)); + check(searchButtonFinder).findsOne(); + + pushedRoutes.clear(); + + connection.prepare(json: eg.newestGetMessagesResult( + foundOldest: true, messages: []).toJson()); + + await tester.tap(searchButtonFinder); + await tester.pump(); + + check(pushedRoutes).single.isA().page + .isA() + .initNarrow.equals(KeywordSearchNarrow('')); + await tester.pump(Duration.zero); + }); }); group('no-messages placeholder', () {