Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/widgets/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ class _HomePageState extends State<HomePage> {
}
}

List<Widget>? 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 = [
Expand Down Expand Up @@ -120,7 +137,9 @@ class _HomePageState extends State<HomePage> {
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)
Expand Down
6 changes: 6 additions & 0 deletions lib/widgets/message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,12 @@ abstract class _MessageListAppBar {
List<Widget> 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():
Expand Down
18 changes: 17 additions & 1 deletion test/widgets/home_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,40 @@ 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);

// Helper to check if search button is present
bool hasSearchButton() {
final appBar = tester.widget<ZulipAppBar>(find.byType(ZulipAppBar));
final actions = appBar.actions ?? [];
return actions.any((widget) =>
widget is IconButton &&
widget.icon is Icon &&
(widget.icon as Icon).icon == ZulipIcons.search);
}

// Inbox tab: should have title "Inbox" and search button
check(find.descendant(
of: find.byType(ZulipAppBar),
matching: find.text('Inbox'))).findsOne();
check(hasSearchButton()).isTrue();

// Channels tab: should have title "Channels" and no search button
await tester.tap(find.byIcon(ZulipIcons.hash_italic));
await tester.pump();
check(find.descendant(
of: find.byType(ZulipAppBar),
matching: find.text('Channels'))).findsOne();
check(hasSearchButton()).isFalse();

// Direct messages tab: should have title "Direct messages" and no search button
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(hasSearchButton()).isFalse();
});

testWidgets('combined feed', (tester) async {
Expand Down
33 changes: 33 additions & 0 deletions test/widgets/inbox_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -649,5 +655,32 @@ void main() {
// reappear because you unmuted a conversation.)
});
});

testWidgets('tapping search button navigates to search page', (tester) async {
// Set up navigation tracking
final pushedRoutes = <Route<dynamic>>[];
final testNavObserver = TestNavigatorObserver()
..onPushed = (route, prevRoute) => pushedRoutes.add(route);

// Use existing setupPage function with navigation observer
await setupPage(tester,
unreadMessages: [],
navigatorObserver: testNavObserver);

// Clear the initial route
assert(pushedRoutes.length == 1);
pushedRoutes.clear();

// Tap the search button in the app bar
await tester.tap(find.descendant(
of: find.byType(ZulipAppBar),
matching: find.byIcon(ZulipIcons.search)));
await tester.pump();

// Verify that we navigated to the search page (MessageListPage with KeywordSearchNarrow)
check(pushedRoutes).single.isA<WidgetRoute>().page
.isA<MessageListPage>()
.initNarrow.equals(KeywordSearchNarrow(''));
});
});
}
36 changes: 36 additions & 0 deletions test/widgets/message_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,42 @@ 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 {
// Set up navigation tracking
final pushedRoutes = <Route<dynamic>>[];
final testNavObserver = TestNavigatorObserver()
..onPushed = (route, prevRoute) => pushedRoutes.add(route);

// Set up the combined feed view with navigation observer
await setupMessageListPage(tester,
narrow: const CombinedFeedNarrow(),
messages: [],
navObservers: [testNavObserver]);

// Verify that the search button is present in the app bar
final searchButtonFinder = find.descendant(
of: find.byType(ZulipAppBar),
matching: find.byIcon(ZulipIcons.search));
check(searchButtonFinder).findsOne();

// Clear any initial navigation that happened during setup
pushedRoutes.clear();

// Mock the API call for the search page
connection.prepare(json: eg.newestGetMessagesResult(
foundOldest: true, messages: []).toJson());

// Tap the search button in the app bar
await tester.tap(searchButtonFinder);
await tester.pump();

// Verify that we navigated to the search page with an empty search query
check(pushedRoutes).single.isA<WidgetRoute>().page
.isA<MessageListPage>()
.initNarrow.equals(KeywordSearchNarrow(''));
await tester.pump(Duration.zero); // Allow message list fetch to complete
});
});

group('no-messages placeholder', () {
Expand Down