Skip to content

Commit ea173e4

Browse files
committed
msglist: Handle update_message_flags events in model
After this, we'll be able to show a message's flags in the UI, such as unread markers (#79).
1 parent 29d4b58 commit ea173e4

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed

lib/model/message_list.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,35 @@ class MessageListView with ChangeNotifier, _MessageSequence {
420420
notifyListeners();
421421
}
422422

423+
void maybeUpdateMessageFlags(UpdateMessageFlagsEvent event) {
424+
final isAdd = switch (event) {
425+
UpdateMessageFlagsAddEvent() => true,
426+
UpdateMessageFlagsRemoveEvent() => false,
427+
};
428+
429+
bool didUpdateAny = false;
430+
if (isAdd && (event as UpdateMessageFlagsAddEvent).all) {
431+
for (final message in messages) {
432+
message.flags.add(event.flag);
433+
didUpdateAny = true;
434+
}
435+
} else {
436+
for (final messageId in event.messages) {
437+
final index = _findMessageWithId(messageId);
438+
if (index != -1) {
439+
final message = messages[index];
440+
isAdd ? message.flags.add(event.flag) : message.flags.remove(event.flag);
441+
didUpdateAny = true;
442+
}
443+
}
444+
}
445+
if (!didUpdateAny) {
446+
return;
447+
}
448+
449+
notifyListeners();
450+
}
451+
423452
void maybeUpdateMessageReactions(ReactionEvent event) {
424453
final index = _findMessageWithId(event.messageId);
425454
if (index == -1) {

lib/model/store.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ class PerAccountStore extends ChangeNotifier {
311311
// TODO handle
312312
} else if (event is UpdateMessageFlagsEvent) {
313313
assert(debugLog("server event: update_message_flags/${event.op} ${event.flag.toJson()}"));
314-
// TODO handle
314+
for (final view in _messageListViews) {
315+
view.maybeUpdateMessageFlags(event);
316+
}
315317
} else if (event is ReactionEvent) {
316318
assert(debugLog("server event: reaction/${event.op}"));
317319
for (final view in _messageListViews) {

test/model/message_list_test.dart

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,137 @@ void main() async {
439439
});
440440
});
441441

442+
group('maybeUpdateMessageFlags', () {
443+
UpdateMessageFlagsAddEvent mkAddEvent(
444+
MessageFlag flag,
445+
List<int> messageIds, {
446+
bool all = false,
447+
}) {
448+
return UpdateMessageFlagsAddEvent(
449+
id: 1,
450+
flag: flag,
451+
messages: messageIds,
452+
all: all,
453+
);
454+
}
455+
456+
UpdateMessageFlagsRemoveEvent mkRemoveEvent(MessageFlag flag, List<Message> messages) {
457+
final messageDetails = Map.fromEntries(messages.map((message) {
458+
final mentioned = message.flags.contains(MessageFlag.mentioned)
459+
|| message.flags.contains(MessageFlag.wildcardMentioned);
460+
return MapEntry(
461+
message.id,
462+
switch (message) {
463+
StreamMessage() => UpdateMessageFlagsMessageDetail(
464+
type: MessageType.stream,
465+
mentioned: mentioned,
466+
streamId: message.streamId,
467+
topic: message.subject,
468+
userIds: null,
469+
),
470+
DmMessage() => UpdateMessageFlagsMessageDetail(
471+
type: MessageType.private,
472+
mentioned: mentioned,
473+
streamId: null,
474+
topic: null,
475+
userIds: DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId).otherRecipientIds,
476+
),
477+
});
478+
}));
479+
480+
return UpdateMessageFlagsRemoveEvent(
481+
id: 1,
482+
flag: flag,
483+
messages: messages.map((m) => m.id).toList(),
484+
messageDetails: messageDetails,
485+
);
486+
}
487+
488+
group('add flag', () {
489+
test('not in list', () async {
490+
prepare();
491+
final message = eg.streamMessage(id: 1, flags: []);
492+
await prepareMessages(foundOldest: true, messages: [message]);
493+
model.maybeUpdateMessageFlags(mkAddEvent(MessageFlag.read, [2]));
494+
checkNotNotified();
495+
check(model).messages.single.flags.deepEquals([]);
496+
});
497+
498+
test('affected message, unaffected message, absent message', () async {
499+
prepare();
500+
final message1 = eg.streamMessage(id: 1, flags: []);
501+
final message2 = eg.streamMessage(id: 2, flags: []);
502+
await prepareMessages(foundOldest: true, messages: [message1, message2]);
503+
model.maybeUpdateMessageFlags(mkAddEvent(MessageFlag.read, [message2.id, 3]));
504+
checkNotifiedOnce();
505+
check(model).messages
506+
..[0].flags.deepEquals([])
507+
..[1].flags.deepEquals([MessageFlag.read]);
508+
});
509+
510+
test('all: true, list non-empty', () async {
511+
prepare();
512+
final message1 = eg.streamMessage(id: 1, flags: []);
513+
final message2 = eg.streamMessage(id: 2, flags: []);
514+
await prepareMessages(foundOldest: true, messages: [message1, message2]);
515+
model.maybeUpdateMessageFlags(mkAddEvent(MessageFlag.read, [], all: true));
516+
checkNotifiedOnce();
517+
check(model).messages
518+
..[0].flags.deepEquals([MessageFlag.read])
519+
..[1].flags.deepEquals([MessageFlag.read]);
520+
});
521+
522+
test('all: true, list empty', () async {
523+
prepare();
524+
await prepareMessages(foundOldest: true, messages: []);
525+
model.maybeUpdateMessageFlags(mkAddEvent(MessageFlag.read, [], all: true));
526+
checkNotNotified();
527+
});
528+
529+
test('other flags not clobbered', () async {
530+
final message = eg.streamMessage(flags: [MessageFlag.starred]);
531+
prepare();
532+
await prepareMessages(foundOldest: true, messages: [message]);
533+
model.maybeUpdateMessageFlags(mkAddEvent(MessageFlag.read, [message.id]));
534+
checkNotifiedOnce();
535+
check(model).messages.single.flags.deepEquals([MessageFlag.starred, MessageFlag.read]);
536+
});
537+
});
538+
539+
group('remove flag', () {
540+
test('not in list', () async {
541+
prepare();
542+
final message = eg.streamMessage(id: 1, flags: [MessageFlag.read]);
543+
await prepareMessages(foundOldest: true, messages: [message]);
544+
model.maybeUpdateMessageFlags(mkAddEvent(MessageFlag.read, [2]));
545+
checkNotNotified();
546+
check(model).messages.single.flags.deepEquals([MessageFlag.read]);
547+
});
548+
549+
test('affected message, unaffected message, absent message', () async {
550+
prepare();
551+
final message1 = eg.streamMessage(id: 1, flags: [MessageFlag.read]);
552+
final message2 = eg.streamMessage(id: 2, flags: [MessageFlag.read]);
553+
final message3 = eg.streamMessage(id: 3, flags: [MessageFlag.read]);
554+
await prepareMessages(foundOldest: true, messages: [message1, message2]);
555+
model.maybeUpdateMessageFlags(mkRemoveEvent(MessageFlag.read, [message2, message3]));
556+
checkNotifiedOnce();
557+
check(model).messages
558+
..[0].flags.deepEquals([MessageFlag.read])
559+
..[1].flags.deepEquals([]);
560+
});
561+
562+
test('other flags not affected', () async {
563+
final message = eg.streamMessage(flags: [MessageFlag.starred, MessageFlag.read]);
564+
prepare();
565+
await prepareMessages(foundOldest: true, messages: [message]);
566+
model.maybeUpdateMessageFlags(mkRemoveEvent(MessageFlag.read, [message]));
567+
checkNotifiedOnce();
568+
check(model).messages.single.flags.deepEquals([MessageFlag.starred]);
569+
});
570+
});
571+
});
572+
442573
test('reassemble', () async {
443574
final stream = eg.stream();
444575
prepare(narrow: StreamNarrow(stream.streamId));

0 commit comments

Comments
 (0)