Skip to content

Commit

Permalink
msglist: In single-conversation view, make recipient headers not tapp…
Browse files Browse the repository at this point in the history
…able.

Fixes: #1171
  • Loading branch information
lakshya1goel committed Dec 31, 2024
1 parent 3ff7096 commit 2de1f1b
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 9 deletions.
27 changes: 18 additions & 9 deletions lib/widgets/message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -899,8 +899,9 @@ class RecipientHeader extends StatelessWidget {
final message = this.message;
return switch (message) {
StreamMessage() => StreamMessageRecipientHeader(message: message,
showStream: _containsDifferentChannels(narrow)),
DmMessage() => DmRecipientHeader(message: message),
showStream: _containsDifferentChannels(narrow),
inTopicNarrow: narrow is TopicNarrow),
DmMessage() => DmRecipientHeader(message: message, inDmNarrow: narrow is DmNarrow),
};
}
}
Expand Down Expand Up @@ -1015,10 +1016,12 @@ class StreamMessageRecipientHeader extends StatelessWidget {
super.key,
required this.message,
required this.showStream,
required this.inTopicNarrow,
});

final StreamMessage message;
final bool showStream;
final bool inTopicNarrow;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -1104,10 +1107,13 @@ class StreamMessageRecipientHeader extends StatelessWidget {
store.topicVisibilityPolicy(message.streamId, topic))),
]));

// Tap interaction is disabled when already in a topic narrow view to avoid redundant navigation.
// This behavior may be updated with improved UI patterns in issue #1039.
return GestureDetector(
onTap: () => Navigator.push(context,
MessageListPage.buildRoute(context: context,
narrow: TopicNarrow.ofMessage(message))),
onTap: !inTopicNarrow
? () => Navigator.push(context, MessageListPage.buildRoute(context: context,
narrow: TopicNarrow.ofMessage(message)))
: null,
onLongPress: () => showTopicActionSheet(context,
channelId: message.streamId, topic: topic),
child: ColoredBox(
Expand All @@ -1126,9 +1132,10 @@ class StreamMessageRecipientHeader extends StatelessWidget {
}

class DmRecipientHeader extends StatelessWidget {
const DmRecipientHeader({super.key, required this.message});
const DmRecipientHeader({super.key, required this.message, required this.inDmNarrow});

final DmMessage message;
final bool inDmNarrow;

@override
Widget build(BuildContext context) {
Expand All @@ -1148,10 +1155,12 @@ class DmRecipientHeader extends StatelessWidget {

final messageListTheme = MessageListTheme.of(context);

// Tap interaction is disabled when already in a DM narrow view to avoid redundant navigation.
return GestureDetector(
onTap: () => Navigator.push(context,
MessageListPage.buildRoute(context: context,
narrow: DmNarrow.ofMessage(message, selfUserId: store.selfUserId))),
onTap: !inDmNarrow
? () => Navigator.push(context, MessageListPage.buildRoute(context: context,
narrow: DmNarrow.ofMessage(message, selfUserId: store.selfUserId)))
: null,
child: ColoredBox(
color: messageListTheme.dmRecipientHeaderBg,
child: Padding(
Expand Down
149 changes: 149 additions & 0 deletions test/widgets/message_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,85 @@ void main() {
await tester.pump();
tester.widget(find.text('new stream name'));
});

testWidgets('navigates to TopicNarrow on tapping topic in CombinedFeedNarrow', (tester) async {
final pushedRoutes = <Route<void>>[];
final navObserver = TestNavigatorObserver()
..onPushed = (route, prevRoute) => pushedRoutes.add(route);

final stream = eg.stream(name: 'stream name');
final message = eg.streamMessage(stream: stream, topic: 'topic name');

await setupMessageListPage(
tester,
narrow: const CombinedFeedNarrow(),
messages: [message],
subscriptions: [eg.subscription(stream)],
navObservers: [navObserver],
);

assert(pushedRoutes.length == 1);
pushedRoutes.clear();

await tester.pump();
check(findInMessageList('stream name')).length.equals(1);
check(findInMessageList('topic name')).length.equals(1);

connection.prepare(json: eg.newestGetMessagesResult(
messages: [message],
foundOldest: true,
).toJson());

final topicFinder = find.descendant(
of: find.byType(StreamMessageRecipientHeader),
matching: find.text('topic name'),
);

check(topicFinder.evaluate()).length.equals(1);
await tester.tap(topicFinder);
await tester.pumpAndSettle();

check(pushedRoutes).length.equals(1);
final pushedRoute = pushedRoutes.first;
check(pushedRoute).isA<WidgetRoute>();
check((pushedRoute as WidgetRoute).page).isA<MessageListPage>();
final messageListPage = pushedRoute.page as MessageListPage;
check(messageListPage.initNarrow).isA<TopicNarrow>();
final topicNarrow = messageListPage.initNarrow as TopicNarrow;
check(topicNarrow.streamId).equals(stream.streamId);
check(topicNarrow.topic).equals('topic name');
});

testWidgets('does not navigate on tapping topic in TopicNarrow', (tester) async {
final pushedRoutes = <Route<void>>[];
final navObserver = TestNavigatorObserver()
..onPushed = (route, prevRoute) => pushedRoutes.add(route);

final channel = eg.stream(name: 'stream name');
final msg = eg.streamMessage(stream: channel, topic: 'topic name');

await setupMessageListPage(
tester,
narrow: TopicNarrow(channel.streamId, 'topic name'),
navObservers: [navObserver],
streams: [channel],
messages: [msg],
);

assert(pushedRoutes.length == 1);
pushedRoutes.clear();

final topicFinder = find.descendant(
of: find.byType(StreamMessageRecipientHeader),
matching: find.text('topic name'),
);

check(topicFinder.evaluate()).length.equals(1);
await tester.tap(topicFinder);
await tester.pumpAndSettle();

check(pushedRoutes).length.equals(0);
});
});

group('DmRecipientHeader', () {
Expand Down Expand Up @@ -987,6 +1066,76 @@ void main() {
tester.widget(find.textContaining(RegExp("Dec 1[89], 2022")));
tester.widget(find.textContaining(RegExp("Aug 2[23], 2022")));
});

testWidgets('navigates to DmNarrow on tapping recipient header in CombinedFeedNarrow', (tester) async {
final pushedRoutes = <Route<void>>[];
final navObserver = TestNavigatorObserver()
..onPushed = (route, prevRoute) {
pushedRoutes.add(route);
};

final dmMessage = eg.dmMessage(from: eg.selfUser, to: [eg.otherUser]);

await setupMessageListPage(
tester,
narrow: const CombinedFeedNarrow(),
messages: [dmMessage],
navObservers: [navObserver],
);

assert(pushedRoutes.length == 1);
pushedRoutes.clear();

await tester.pumpAndSettle();

connection.prepare(json: eg.newestGetMessagesResult(
messages: [dmMessage],
foundOldest: true,
).toJson());

final recipientHeaderFinder = find.byType(DmRecipientHeader);
check(recipientHeaderFinder.evaluate()).length.equals(1);

await tester.tap(recipientHeaderFinder);
await tester.pumpAndSettle();

check(pushedRoutes).length.equals(1);

final pushedRoute = pushedRoutes.first;
check(pushedRoute).isA<WidgetRoute>();
check((pushedRoute as WidgetRoute).page).isA<MessageListPage>();
final messageListPage = pushedRoute.page as MessageListPage;
check(messageListPage.initNarrow).isA<DmNarrow>();
final dmNarrow = messageListPage.initNarrow as DmNarrow;
check(dmNarrow.otherRecipientIds).contains(eg.otherUser.userId);
});

testWidgets('does not navigate on tapping recipient header in DmNarrow', (tester) async {
final pushedRoutes = <Route<void>>[];
final navObserver = TestNavigatorObserver()
..onPushed = (route, prevRoute) => pushedRoutes.add(route);

final dmMessage = eg.dmMessage(from: eg.selfUser, to: [eg.otherUser]);

await setupMessageListPage(
tester,
narrow: DmNarrow.withUser(eg.otherUser.userId, selfUserId: eg.selfUser.userId),
navObservers: [navObserver],
messages: [dmMessage],
);

assert(pushedRoutes.length == 1);
pushedRoutes.clear();

final recipientHeaderFinder = find.byType(DmRecipientHeader);

check(recipientHeaderFinder.evaluate()).length.equals(1);

await tester.tap(recipientHeaderFinder);
await tester.pumpAndSettle();

check(pushedRoutes).length.equals(0);
});
});

group('formatHeaderDate', () {
Expand Down

0 comments on commit 2de1f1b

Please sign in to comment.