Skip to content

Conversation

@sarafarajnasardi
Copy link

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

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
Copy link
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 +789
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
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
Author

Choose a reason for hiding this comment

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

@sarafarajnasardi
Copy link
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.

@gnprice
Copy link
Member

gnprice commented Jan 14, 2026

@sarafarajnasardi Do you think you'll have time to come back and finish addressing the feedback on this PR? It'd be great to have it completed.

@sarafarajnasardi
Copy link
Author

@gnprice Yes, I’ll get back to it and finish addressing the feedback shortly. I’ll update the PR once it’s done. Thanks for the reminder!

@sarafarajnasardi
Copy link
Author

Hi @gnprice and @chrisbobbe ,

Apologies for the delay in addressing the feedback. I encountered some personal matters that slowed my progress, and I accidentally closed the PR due to an incorrect force push while updating the changes.

I've now addressed all the review comments:

1.Fixed the duplicate flags issue for both all: true and all: false cases
2.Renamed variables to avoid abbreviations (message1, message2)
3.Used mkAddEvent helper and package:checks cascade shorthand
4.Updated commit message with proper prefix and formatting
The PR is now ready for review. Thank you for your patience and detailed feedback!

@gnprice
Copy link
Member

gnprice commented Jan 24, 2026

Thanks for the revision. This looks good, with two comments:

  • The second commit is messy: it leaves stray whitespace, and the commit message is just "--amend" which doesn't say anything clear.

    Fortunately this commit is unnecessary after a rebase, so I'll just drop it.

  • The commit message should have its summary line all on one line. Fixed that like so:

    -    message: Prevent duplicate flags when processing
    -    update_message_flags
    +    message: Prevent duplicate flags when processing update_message_flags

(It's fine for the summary line to go a bit long, like up to 80 columns, unlike the paragraphs that make up the body of the commit message which should stick to 68 columns.)

Merging with those two tweaks.

@gnprice gnprice force-pushed the fix-duplicate-message-flags branch from 484381e to 690a991 Compare January 24, 2026 01:45
@gnprice gnprice force-pushed the fix-duplicate-message-flags branch from 690a991 to f04a542 Compare January 24, 2026 02:04
@gnprice gnprice merged commit f04a542 into zulip:main Jan 24, 2026
1 check passed
@sarafarajnasardi
Copy link
Author

@gnprice thanks for the merge...I"ll keep your suggestions in mind next time...

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