Skip to content

Conversation

@sarafarajnasardi
Copy link
Contributor

Previously, the event handler would unconditionally add flags to the message's flag list. If a flag (like 'read') was already present, this created duplicates, which broke subsequent removal operations.

This commit adds a check to ensure the flag is not already present before adding it, making the operation idempotent.

Fixes #1986

@sarafarajnasardi sarafarajnasardi force-pushed the fix-duplicate-message-flags branch from 6570cf0 to 2197c45 Compare December 11, 2025 09:18
Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Small comments below.

Also some commit-message nits:

Please keep the body of your commit message word-wrapped to 68 columns.

In this case the Fixes line suffices to explain the change, so you don't need the two paragraphs above that.

Also the Fixes line should read Fixes #1986. (note the period).

Comment on lines 1714 to 1717
// Should verify no notifications since no actual change happened
// But current implementation might notify anyway if it doesn't check for change
// optimization. The main point is flags list shouldn't have duplicates.
// Let's check the flags first.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate wanting to explain this 🙂 but I think we can cut this comment; the test is about an edge case that should be rare (in the fetch-event race) and an extra notifyListeners isn't a significant concern here.

@chrisbobbe chrisbobbe self-assigned this Dec 12, 2025
@chrisbobbe chrisbobbe added the maintainer review PR ready for review by Zulip maintainers label Dec 12, 2025
@sarafarajnasardi sarafarajnasardi force-pushed the fix-duplicate-message-flags branch from 2197c45 to 9329d2f Compare December 12, 2025 03:05
@sarafarajnasardi
Copy link
Contributor Author

Thanks! I've removed the test comments and updated the commit message formatting

Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Small comments below, otherwise LGTM.

Comment on lines 737 to +741
if (isAdd && (event as UpdateMessageFlagsAddEvent).all) {
for (final message in messages.values) {
message.flags.add(event.flag);
if (!message.flags.contains(event.flag)) {
message.flags.add(event.flag);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also write a test exercising this case.

Comment on lines 1706 to 1708
test('avoid duplicate flags', () async {
await prepare();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
test('avoid duplicate flags', () async {
await prepare();
test('avoid duplicate flags', () async {
// Regression test for https://github.com/zulip/zulip-flutter/issues/1986
await prepare();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should I add this same comment in new test also?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so; it's applies equally there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sarafarajnasardi sarafarajnasardi force-pushed the fix-duplicate-message-flags branch from 9329d2f to 9e5f2e9 Compare December 12, 2025 03:39
@sarafarajnasardi
Copy link
Contributor Author

Done! I have added the new test and your suggested comment.

Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! One small comment below, and I'll also mark this for Greg's review.

check(store).messages.values.single.flags.deepEquals([MessageFlag.read]);
});

test('handle update_message_flags: add flag "all" is idempotent', () async {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to give the two new tests more similar descriptions, so it's more obvious that they're testing very similar logic. How about:

  • 'prevent duplicate flags, when all: false'
  • 'prevent duplicate flags, when all: true'

or similar.

@chrisbobbe chrisbobbe requested a review from gnprice December 15, 2025 19:53
@chrisbobbe chrisbobbe assigned gnprice and unassigned chrisbobbe Dec 15, 2025
@chrisbobbe chrisbobbe added integration review Added by maintainers when PR may be ready for integration and removed maintainer review PR ready for review by Zulip maintainers labels Dec 15, 2025
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sarafarajnasardi for taking care of this, and thanks @chrisbobbe for the previous reviews!

Generally this looks good. Some small comments, in addition to the one Chris makes above.

Comment on lines +1719 to +1720
final m1 = eg.streamMessage(flags: [MessageFlag.read]);
final m2 = eg.streamMessage(flags: []);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
final m1 = eg.streamMessage(flags: [MessageFlag.read]);
final m2 = eg.streamMessage(flags: []);
final message1 = eg.streamMessage(flags: [MessageFlag.read]);
final message2 = eg.streamMessage(flags: []);

This point about avoiding abbreviations, in the Flutter upstream style guide, applies equally in Zulip:
https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#avoid-abbreviations

(And not only in the mobile repo — in fact I think Tim applies it more strongly than I do, and we've been doing so since long before we used Flutter.)

Comment on lines +1730 to +1731
check(store.messages[m1.id]!.flags).deepEquals([MessageFlag.read]);
check(store.messages[m2.id]!.flags).deepEquals([MessageFlag.read]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Conversely, for making this a bit more compact again, see the test cases with "message1" and "message2" earlier in this group. Those give examples of how the package:checks API enables some handy shorthands.

Comment on lines +1723 to +1724
await store.handleEvent(UpdateMessageFlagsAddEvent(
id: 1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: like the other cases in this group, use mkAddEvent for brevity and clarity

@gnprice
Copy link
Member

gnprice commented Dec 15, 2025

Oh and a commit-message nit:

model: Prevent duplicate flags when processing update_message_flags.

This should have a more specific prefix (vs "model:" which is quite general). To see examples, try git log --oneline on this file.

Plus one very small nit: in this repo we don't use a period at the end of the summary line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration review Added by maintainers when PR may be ready for integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid duplicate message flag on redundant event

3 participants