Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement stream and topic muting #423

Merged
merged 18 commits into from
Dec 20, 2023
Merged

Implement stream and topic muting #423

merged 18 commits into from
Dec 20, 2023

Conversation

gnprice
Copy link
Member

@gnprice gnprice commented Nov 29, 2023

Fixes: #346
Fixes: #395

This series also contains some refactoring of PerAccountStore, creating a new class StreamStore and new file lib/model/stream.dart as a home for the section of the data that's about streams and topics. There's probably a couple of other swathes of data that could benefit from a similar treatment.

Also, in order to let the Unreads instance have access to StreamStore:


store [nfc]: The event-poll loop has-a store, not is-a store

This seems to make more sense conceptually.

For its most immediate practical effect, this means
UpdateMachine.fromInitialSnapshot doesn't care whether
PerAccountStore.fromInitialSnapshot is a generative or a
factory constructor, which will give us the flexibility to
make it the latter.

This change will also probably be helpful for making other
decouplings of the polling and registerNotificationToken logic
from the data structures of PerAccountStore.


store [nfc]: Make fromInitialSnapshot a factory constructor

This will let us first construct the StreamStore, as a local of
the constructor, and then pass that to the Unreads constructor.

switch (subscriptions[streamId]?.isMuted) {
case false: return true;
case true: return false;
case null: return false; // not subscribed; treat like muted
Copy link
Member Author

Choose a reason for hiding this comment

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

The test failures are because I need to make this line more conditional — in some contexts (like the inbox), we want to treat a not-subscribed stream the same as a muted stream, but in others (like the message list), we want to treat it the same as a subscribed and not muted stream.

Marking as draft until I fix that, but in the meantime the rest of the code is ready to review.

@gnprice gnprice marked this pull request as draft November 29, 2023 02:37
@chrisbobbe
Copy link
Collaborator

chrisbobbe commented Nov 29, 2023

Very excited to see this!! Now my inbox view will be usable, since it won't have noise from all the stuff I've muted. 😅

Hmm. Take a look at how the "Mark X as read" button works in the all-messages narrow:

Narrow type Msglist includes muted messages? X in "Mark X as read" includes muted messages? Mark-as-read button marks muted messages?
Topic Yes Yes Yes
Stream Yes Not in muted topics Yes Not in muted topics Yes
All messages No No Yes

(edit: updated the "Stream" row for #423 (comment).)

Is that right?

That seems like a bug. Looking at my account now, it means I might click a button that says "Mark 28 messages as read", and instead, 5444 messages would get marked as read. That seems misleading.

Could maybe resolve by offering a dialog that asks the user if they want to mark everything as read, or just what's not muted / what they're seeing in the list?

@gnprice
Copy link
Member Author

gnprice commented Nov 29, 2023

That seems like a bug. Looking at my account now, it means I might click a button that says "Mark 28 messages as read", and instead, 5444 messages would get marked as read. That seems misleading.

Yeah, that does.

I believe the corresponding button in web has the same behavior — but it doesn't say the number of messages. So the fix might just be to not mention the number of unread messages. (After all, do you really need the number? You're already looking at the view where they appear… well unless they're muted, I guess.)

In zulip-mobile the corresponding banner has the number, but separately from the button so it doesn't have the same confusion. And the number serves somewhat more of a purpose there, because the banner appears even if you're scrolled up in history (so that it lets you know there's unreads below, e.g. if they came in while you were reading the old history). We probably should do something to serve that purpose, but this button at the bottom of the list doesn't anyway, so it can probably drop the number.

@gnprice
Copy link
Member Author

gnprice commented Nov 29, 2023

In the "Stream" row of your table, the intended behavior is that the messages shown and the count of unreads disregard any muting of the stream, but don't include muted topics. If you're seeing them include muted topics, that's a bug.

@chrisbobbe
Copy link
Collaborator

Ah right; I just confirmed that it works as expected. When looking at the web app, I had thought a particular topic was muted, when it was actually in the "default" policy (and the stream was muted). I updated the table.

I guess that means the stream-narrow mark-as-read button is also misleading, like the one in "All messages". There could be messages in muted topics that aren't shown in the list, and aren't represented in the unread-count number, but that would be affected by the mark-as-read button. Could do the same fix (removing the number from the mark-as-read button).

@chrisbobbe

This comment was marked as resolved.

@chrisbobbe
Copy link
Collaborator

chrisbobbe commented Nov 29, 2023

Apart from my comments above (and the failing test that you mentioned), this looks good. Thanks!

@gnprice
Copy link
Member Author

gnprice commented Dec 19, 2023

Thanks for the review! Back from vacation today, and just pushed a revision. PTAL.

@gnprice gnprice marked this pull request as ready for review December 19, 2023 05:37
@chrisbobbe
Copy link
Collaborator

LGTM, thanks! The CI failure should resolve after #447; would you review and merge that please? Then please merge this at will.

This gets us automatic checking for exhaustiveness when we
write switch statements on these.
This gives us more space to make this implementation more complex,
and to add more features, without overwhelming PerAccountStore
and lib/model/store.dart .
…that

This invariant should always be maintained by the server, so this
mostly serves to validate that our tests don't accidentally break it.
Instead just say "Mark all messages as read".
That's the same text used on web in the left-sidebar menus,
both for an individual stream and an individual topic.
Generally this file is ordered from general to specific:
realm-wide settings first, individual messages last.  In between,
a stream comes before a subscription, which is a particular user's
relationship to a stream.
This type is used in events, too, so it goes best in the
"model" library that's shared between those.
These getters are borrowed from muteModel.js in zulip-mobile.
This seems to make more sense conceptually.

For its most immediate practical effect, this means
UpdateMachine.fromInitialSnapshot doesn't care whether
PerAccountStore.fromInitialSnapshot is a generative or a
factory constructor, which will give us the flexibility to
make it the latter.

This change will also probably be helpful for making other
decouplings of the polling and registerNotificationToken logic
from the data structures of PerAccountStore.
This will let us first construct the StreamStore, as a local of
the constructor, and then pass that to the Unreads constructor.
This way setupMessageListPage takes care of putting the data in
place, which aligns with the structure of this file's other tests.
This is the last step for implementing stream and topic muting,
i.e. zulip#346.  (Except for what's been split off to follow-up issues,
notably zulip#421.)

Fixes: zulip#346
@gnprice gnprice merged commit 48f8cd8 into zulip:main Dec 20, 2023
1 check passed
@gnprice
Copy link
Member Author

gnprice commented Dec 20, 2023

Thanks for the review! Done.

@gnprice gnprice deleted the pr-mute branch December 20, 2023 22:37
chrisbobbe added a commit to chrisbobbe/zulip-flutter that referenced this pull request Apr 17, 2024
In zulip#423 "Implement stream and topic muting", the Unreads class did
start doing some filtering based in stream/topic muting,
specifically in these methods:
- countInStream
- countInAllMessagesNarrow

So, update the dartdoc so it doesn't claim that this filtering is an
entirely separate concern.
gnprice pushed a commit to chrisbobbe/zulip-flutter that referenced this pull request Apr 26, 2024
In zulip#423 "Implement stream and topic muting", the Unreads class did
start doing some filtering based in stream/topic muting,
specifically in these methods:
- countInStream
- countInAllMessagesNarrow

So, update the dartdoc so it doesn't claim that this filtering is an
entirely separate concern.
satyam372 pushed a commit to satyam372/zulip-flutter that referenced this pull request May 1, 2024
In zulip#423 "Implement stream and topic muting", the Unreads class did
start doing some filtering based in stream/topic muting,
specifically in these methods:
- countInStream
- countInAllMessagesNarrow

So, update the dartdoc so it doesn't claim that this filtering is an
entirely separate concern.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unify stream with subscription data Handle muted streams and topics
2 participants