Skip to content

Commit 1a80230

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. Fixes #1368.
1 parent e0df0ed commit 1a80230

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

lib/widgets/message_list.dart

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

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

test/widgets/message_list_test.dart

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

0 commit comments

Comments
 (0)