Skip to content

Commit 5f22c99

Browse files
msglist: Fix channel header tap behaviour in multi-channel narrows
Set gesture detecter behavior of streamWidget to HitTestBehavior.opaque to handle taps in empty space around the header. Also added a test that checks if tapping empty space in channel header area correctly navigates to the channel feed. Fixes #1368.
1 parent a5af8d3 commit 5f22c99

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

lib/widgets/message_list.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,7 @@ class StreamMessageRecipientHeader extends StatelessWidget {
10831083
?? zulipLocalizations.unknownChannelName; // TODO(log)
10841084

10851085
streamWidget = GestureDetector(
1086+
behavior: HitTestBehavior.opaque,
10861087
onTap: () => Navigator.push(context,
10871088
MessageListPage.buildRoute(context: context,
10881089
narrow: ChannelNarrow(message.streamId))),

test/widgets/message_list_test.dart

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,4 +1470,113 @@ void main() {
14701470
..status.equals(AnimationStatus.dismissed);
14711471
});
14721472
});
1473+
1474+
group('channel header navigation in multi-channel narrows', () {
1475+
testWidgets("navigates to ChannelNarrow when tapping above or below stream name in recipient header", (tester) async {
1476+
final pushedRoutes = <Route<void>>[];
1477+
final navObserver = TestNavigatorObserver()
1478+
..onPushed = (route, prevRoute) => pushedRoutes.add(route);
1479+
final channel = eg.stream();
1480+
final message = eg.streamMessage(stream: channel);
1481+
await setupMessageListPage(tester,
1482+
narrow: const CombinedFeedNarrow(),
1483+
streams: [channel],
1484+
subscriptions: [eg.subscription(channel)],
1485+
messages: [message],
1486+
navObservers: [navObserver]);
1487+
1488+
assert(pushedRoutes.length == 1);
1489+
pushedRoutes.clear();
1490+
1491+
connection.prepare(json: eg.newestGetMessagesResult(
1492+
foundOldest: true, messages: [message]).toJson());
1493+
1494+
// Find the recepient header rect
1495+
final recipientHeaderFinder = find.byType(StreamMessageRecipientHeader);
1496+
final recipientHeaderRect = tester.getRect(recipientHeaderFinder);
1497+
1498+
1499+
// Find the stream name text
1500+
final streamNameFinder = find.descendant(
1501+
of: recipientHeaderFinder,
1502+
matching: find.text(channel.name));
1503+
final streamNameRect = tester.getRect(streamNameFinder);
1504+
1505+
// First tap: 1 px below the top of recepient header at streamName x coordinate
1506+
await tester.tapAt(Offset(streamNameRect.center.dx, recipientHeaderRect.top + 1));
1507+
1508+
await tester.pump();
1509+
check(pushedRoutes).single.isA<WidgetRoute>().page.isA<MessageListPage>()
1510+
.initNarrow.equals(ChannelNarrow(channel.streamId));
1511+
await tester.pumpAndSettle();
1512+
1513+
// Navigate back to original page and clear routes
1514+
await tester.pageBack();
1515+
await tester.pumpAndSettle();
1516+
pushedRoutes.clear();
1517+
1518+
connection.prepare(json: eg.newestGetMessagesResult(
1519+
foundOldest: true, messages: [message]).toJson());
1520+
1521+
// Second tap: 1 px above the bottom of the recipient header at streamName x coordinate
1522+
await tester.tapAt(Offset(streamNameRect.center.dx, streamNameRect.bottom - 1));
1523+
await tester.pump();
1524+
check(pushedRoutes).single.isA<WidgetRoute>().page.isA<MessageListPage>()
1525+
.initNarrow.equals(ChannelNarrow(channel.streamId));
1526+
await tester.pumpAndSettle();
1527+
});
1528+
1529+
testWidgets("navigates to TopicNarrow when tapping above or below topic name in recipient header", (tester) async {
1530+
final pushedRoutes = <Route<void>>[];
1531+
final navObserver = TestNavigatorObserver()
1532+
..onPushed = (route, prevRoute) => pushedRoutes.add(route);
1533+
final channel = eg.stream();
1534+
final message = eg.streamMessage(stream: channel, topic: 'testTopic');
1535+
await setupMessageListPage(tester,
1536+
narrow: const CombinedFeedNarrow(),
1537+
streams: [channel],
1538+
subscriptions: [eg.subscription(channel)],
1539+
messages: [message],
1540+
navObservers: [navObserver]);
1541+
1542+
assert(pushedRoutes.length == 1);
1543+
pushedRoutes.clear();
1544+
1545+
connection.prepare(json: eg.newestGetMessagesResult(
1546+
foundOldest: true, messages: [message]).toJson());
1547+
1548+
// Find the recepient header rect
1549+
final recipientHeaderFinder = find.byType(StreamMessageRecipientHeader);
1550+
final recipientHeaderRect = tester.getRect(recipientHeaderFinder);
1551+
1552+
// Find the topic name text
1553+
final topicNameFinder = find.descendant(
1554+
of: recipientHeaderFinder,
1555+
matching: find.text('testTopic'));
1556+
final topicNameRect = tester.getRect(topicNameFinder);
1557+
1558+
// First tap: 1 px below the top of recepient header at topicName x coordinate
1559+
await tester.tapAt(Offset(topicNameRect.center.dx, recipientHeaderRect.top + 1));
1560+
await tester.pump();
1561+
check(pushedRoutes).single.isA<WidgetRoute>().page.isA<MessageListPage>()
1562+
.initNarrow.equals(TopicNarrow(channel.streamId, message.topic));
1563+
await tester.pumpAndSettle();
1564+
1565+
// Navigate back to original page and clear routes
1566+
await tester.pageBack();
1567+
await tester.pumpAndSettle();
1568+
pushedRoutes.clear();
1569+
1570+
connection.prepare(json: eg.newestGetMessagesResult(
1571+
foundOldest: true, messages: [message]).toJson());
1572+
1573+
// Second tap: 1 px above the bottom of the recipient header at topicName x coordinate
1574+
await tester.tapAt(Offset(topicNameRect.center.dx, recipientHeaderRect.bottom - 1));
1575+
await tester.pump();
1576+
check(pushedRoutes).single.isA<WidgetRoute>().page.isA<MessageListPage>()
1577+
.initNarrow.equals(TopicNarrow(channel.streamId, message.topic));
1578+
await tester.pumpAndSettle();
1579+
});
1580+
}
1581+
);
14731582
}

0 commit comments

Comments
 (0)