Skip to content

Commit ec4cdd0

Browse files
gnpricegithub-actions[bot]
authored andcommitted
notif: Case-fold topics for grouping conversations
Fixes #1205.
1 parent 54d9d5b commit ec4cdd0

File tree

2 files changed

+49
-16
lines changed

2 files changed

+49
-16
lines changed

lib/notifications/display.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ class NotificationDisplayManager {
443443

444444
static String _conversationKey(MessageFcmMessage data, String groupKey) {
445445
final conversation = switch (data.recipient) {
446-
FcmMessageChannelRecipient(:var streamId, :var topic) => 'stream:$streamId:$topic',
446+
FcmMessageChannelRecipient(:var streamId, :var topic) => 'stream:$streamId:${topic.canonicalize()}',
447447
FcmMessageDmRecipient(:var allRecipientIds) => 'dm:${allRecipientIds.join(',')}',
448448
};
449449
return '$groupKey|$conversation';

test/notifications/display_test.dart

+48-15
Original file line numberDiff line numberDiff line change
@@ -540,21 +540,47 @@ void main() {
540540
messageStyleMessages: [data1],
541541
expectedIsGroupConversation: true,
542542
expectedTitle: '#${stream.name} > $topicA',
543-
expectedTagComponent: 'stream:${stream.streamId}:$topicA');
543+
expectedTagComponent: 'stream:${stream.streamId}:${topicA.toLowerCase()}');
544544

545545
receiveFcmMessage(async, data2);
546546
checkNotification(data2,
547547
messageStyleMessages: [data2],
548548
expectedIsGroupConversation: true,
549549
expectedTitle: '#${stream.name} > $topicB',
550-
expectedTagComponent: 'stream:${stream.streamId}:$topicB');
550+
expectedTagComponent: 'stream:${stream.streamId}:${topicB.toLowerCase()}');
551551

552552
receiveFcmMessage(async, data3);
553553
checkNotification(data3,
554554
messageStyleMessages: [data1, data3],
555555
expectedIsGroupConversation: true,
556556
expectedTitle: '#${stream.name} > $topicA',
557-
expectedTagComponent: 'stream:${stream.streamId}:$topicA');
557+
expectedTagComponent: 'stream:${stream.streamId}:${topicA.toLowerCase()}');
558+
})));
559+
560+
test('stream message: topic changes only case', () => runWithHttpClient(() => awaitFakeAsync((async) async {
561+
await init();
562+
final stream = eg.stream();
563+
const topic1 = 'A ToPic';
564+
const topic2 = 'a TOpic';
565+
final message1 = eg.streamMessage(topic: topic1, stream: stream);
566+
final data1 = messageFcmMessage(message1, streamName: stream.name);
567+
final message2 = eg.streamMessage(topic: topic2, stream: stream);
568+
final data2 = messageFcmMessage(message2, streamName: stream.name);
569+
570+
receiveFcmMessage(async, data1);
571+
checkNotification(data1,
572+
messageStyleMessages: [data1],
573+
expectedIsGroupConversation: true,
574+
expectedTitle: '#${stream.name} > $topic1',
575+
expectedTagComponent: 'stream:${stream.streamId}:a topic');
576+
577+
receiveFcmMessage(async, data2);
578+
checkNotification(data2,
579+
messageStyleMessages: [data1, data2],
580+
expectedIsGroupConversation: true,
581+
// Title updates with latest casing of topic.
582+
expectedTitle: '#${stream.name} > $topic2',
583+
expectedTagComponent: 'stream:${stream.streamId}:a topic');
558584
})));
559585

560586
test('stream message: conversation stays same when stream is renamed', () => runWithHttpClient(() => awaitFakeAsync((async) async {
@@ -781,6 +807,7 @@ void main() {
781807
final data2 = messageFcmMessage(message2, streamName: stream.name);
782808
final message3 = eg.streamMessage(stream: stream, topic: topicA);
783809
final data3 = messageFcmMessage(message3, streamName: stream.name);
810+
final conversationKey = 'stream:${stream.streamId}:${topicA.toLowerCase()}';
784811
final expectedGroupKey = '${data1.realmUrl}|${data1.userId}';
785812

786813
check(testBinding.androidNotificationHost.activeNotifications).isEmpty();
@@ -789,14 +816,14 @@ void main() {
789816
receiveFcmMessage(async, data2);
790817
receiveFcmMessage(async, data3);
791818
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
792-
conditionActiveNotif(data3, 'stream:${stream.streamId}:$topicA'),
819+
conditionActiveNotif(data3, conversationKey),
793820
conditionSummaryActiveNotif(expectedGroupKey),
794821
]);
795822

796823
// A RemoveFcmMessage for the first two messages; the notification stays.
797824
receiveFcmMessage(async, removeFcmMessage([message1, message2]));
798825
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
799-
conditionActiveNotif(data3, 'stream:${stream.streamId}:$topicA'),
826+
conditionActiveNotif(data3, conversationKey),
800827
conditionSummaryActiveNotif(expectedGroupKey),
801828
]);
802829

@@ -808,30 +835,34 @@ void main() {
808835
test('remove: clears summary notification only if all conversation notifications are cleared', () => runWithHttpClient(() => awaitFakeAsync((async) async {
809836
await init();
810837
final stream = eg.stream();
838+
811839
const topicA = 'Topic A';
812840
final message1 = eg.streamMessage(stream: stream, topic: topicA);
813841
final data1 = messageFcmMessage(message1, streamName: stream.name);
842+
final conversationKey1 = 'stream:${stream.streamId}:${topicA.toLowerCase()}';
843+
final expectedGroupKey = '${data1.realmUrl}|${data1.userId}';
844+
814845
const topicB = 'Topic B';
815846
final message2 = eg.streamMessage(stream: stream, topic: topicB);
816847
final data2 = messageFcmMessage(message2, streamName: stream.name);
817-
final expectedGroupKey = '${data1.realmUrl}|${data1.userId}';
848+
final conversationKey2 = 'stream:${stream.streamId}:${topicB.toLowerCase()}';
818849

819850
check(testBinding.androidNotificationHost.activeNotifications).isEmpty();
820851

821852
// Two notifications for different conversations; but same account.
822853
receiveFcmMessage(async, data1);
823854
receiveFcmMessage(async, data2);
824855
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
825-
conditionActiveNotif(data1, 'stream:${stream.streamId}:$topicA'),
856+
conditionActiveNotif(data1, conversationKey1),
826857
conditionSummaryActiveNotif(expectedGroupKey),
827-
conditionActiveNotif(data2, 'stream:${stream.streamId}:$topicB'),
858+
conditionActiveNotif(data2, conversationKey2),
828859
]);
829860

830861
// A RemoveFcmMessage for first conversation; only clears the first conversation notif.
831862
receiveFcmMessage(async, removeFcmMessage([message1]));
832863
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
833864
conditionSummaryActiveNotif(expectedGroupKey),
834-
conditionActiveNotif(data2, 'stream:${stream.streamId}:$topicB'),
865+
conditionActiveNotif(data2, conversationKey2),
835866
]);
836867

837868
// Then a RemoveFcmMessage for the only remaining conversation;
@@ -844,6 +875,7 @@ void main() {
844875
await init();
845876
final stream = eg.stream();
846877
const topic = 'Some Topic';
878+
final conversationKey = 'stream:${stream.streamId}:some topic';
847879

848880
final account1 = eg.account(
849881
realmUrl: Uri.parse('https://1.chat.example'),
@@ -868,15 +900,15 @@ void main() {
868900
receiveFcmMessage(async, data1);
869901
receiveFcmMessage(async, data2);
870902
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
871-
conditionActiveNotif(data1, 'stream:${stream.streamId}:$topic'),
903+
conditionActiveNotif(data1, conversationKey),
872904
conditionSummaryActiveNotif(groupKey1),
873-
conditionActiveNotif(data2, 'stream:${stream.streamId}:$topic'),
905+
conditionActiveNotif(data2, conversationKey),
874906
conditionSummaryActiveNotif(groupKey2),
875907
]);
876908

877909
receiveFcmMessage(async, removeFcmMessage([message1], account: account1));
878910
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
879-
conditionActiveNotif(data2, 'stream:${stream.streamId}:$topic'),
911+
conditionActiveNotif(data2, conversationKey),
880912
conditionSummaryActiveNotif(groupKey2),
881913
]);
882914

@@ -889,6 +921,7 @@ void main() {
889921
final realmUrl = eg.realmUrl;
890922
final stream = eg.stream();
891923
const topic = 'Some Topic';
924+
final conversationKey = 'stream:${stream.streamId}:some topic';
892925

893926
final account1 = eg.account(id: 1001, user: eg.user(userId: 1001), realmUrl: realmUrl);
894927
final message1 = eg.streamMessage(id: 1000, stream: stream, topic: topic);
@@ -907,15 +940,15 @@ void main() {
907940
receiveFcmMessage(async, data1);
908941
receiveFcmMessage(async, data2);
909942
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
910-
conditionActiveNotif(data1, 'stream:${stream.streamId}:$topic'),
943+
conditionActiveNotif(data1, conversationKey),
911944
conditionSummaryActiveNotif(groupKey1),
912-
conditionActiveNotif(data2, 'stream:${stream.streamId}:$topic'),
945+
conditionActiveNotif(data2, conversationKey),
913946
conditionSummaryActiveNotif(groupKey2),
914947
]);
915948

916949
receiveFcmMessage(async, removeFcmMessage([message1], account: account1));
917950
check(testBinding.androidNotificationHost.activeNotifications).deepEquals(<Condition<Object?>>[
918-
conditionActiveNotif(data2, 'stream:${stream.streamId}:$topic'),
951+
conditionActiveNotif(data2, conversationKey),
919952
conditionSummaryActiveNotif(groupKey2),
920953
]);
921954

0 commit comments

Comments
 (0)