-
Notifications
You must be signed in to change notification settings - Fork 315
Mute muted users (Chris's revision, 2 of 2) #1561
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
base: main
Are you sure you want to change the base?
Conversation
9c82301
to
0acc63b
Compare
Revision pushed; this one also excludes muted users from the new new-DM UI, which landed after my last revision. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I've read so far the first three commits:
8af150c recent-dms: Exclude DM conversations where all other recipients are muted
06937e2 msglist [nfc]: Place _allMessagesVisible
right after _messageVisible
8339c64 msglist [nfc]: s/VisibilityEffect/UserTopicVisibilityEffect/
and the next one except for its tests:
898a2ad msglist: In combined/mentions/starred, exclude DMs if all recipients muted
Generally all looks good; a few small comments below.
That leaves four more commits that I haven't read (though I've skimmed them):
619eb24 autocomplete: Exclude muted users from user-mention autocomplete
87df780 msglist [nfc]: Represent nobody-is-typing as null, not empty list
c40cb89 msglist: Exclude muted users from typing-status text
0acc63b new-dm: Exclude muted users
(false, true) => VisibilityEffect.unmuted, | ||
(true, false) => VisibilityEffect.muted, | ||
_ => VisibilityEffect.none, | ||
(false, true) => UserTopicVisibilityEffect.unmuted, | ||
(true, false) => UserTopicVisibilityEffect.muted, | ||
_ => UserTopicVisibilityEffect.none, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awkwardly verbose, but we're about to add another kind of
visibility effect, and I think the code will end up clearer if we
make a separate enum for it.
Yeah, agreed.
Some of the verbosity (like in these lines) will at least get resolved by the upcoming Dart feature of "dot shorthands", expected later this year:
https://github.com/dart-lang/language/blob/main/working/3616%20-%20enum%20value%20shorthand/proposal-simple-lrhn.md
I believe with that feature we'll be able to say just .unmuted
, .muted
, .none
here, without the name of the enum type.
lib/model/message_list.dart
Outdated
!store.shouldMuteDmConversation(DmNarrow( | ||
allRecipientIds: allRecipientIds, selfUserId: store.selfUserId)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make another DmNarrow constructor for this:
!store.shouldMuteDmConversation(DmNarrow( | |
allRecipientIds: allRecipientIds, selfUserId: store.selfUserId)), | |
!store.shouldMuteDmConversation(DmNarrow.ofConversation( | |
message.conversation, selfUserId: store.selfUserId)), |
Compare the comment at the top of that class:
// Zulip has many ways of representing a DM conversation; for example code
// handling many of them, see zulip-mobile:src/utils/recipient.js .
// Please add more constructors and getters here to handle any of those
// as we turn out to need them.
class DmNarrow extends Narrow implements SendableNarrow {
It'd be bad if this logic did something inefficient like copy the list of recipient IDs, because we're doing this for potentially a large fraction of the messages in this feed (if a user uses lots of DMs). I believe this in fact doesn't make such a copy — and a constructor on DmNarrow is a good place to centralize coming to that conclusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh…it looks like DmNarrow.ofMessage
, though, does copy the list of recipient IDs:
factory DmNarrow.ofMessage(MessageBase<DmConversation> message, {
required int selfUserId,
}) {
return DmNarrow(
allRecipientIds: List.unmodifiable(message.conversation.allRecipientIds),
selfUserId: selfUserId,
);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm indeed.
It looks like we don't currently call that one in any place that's as performance-sensitive as this. But it's a bit of a pitfall lying around.
lib/model/message_list.dart
Outdated
switch (narrow) { | ||
case CombinedFeedNarrow(): | ||
case ChannelNarrow(): | ||
case MentionsNarrow(): | ||
case StarredMessagesNarrow(): | ||
return false; | ||
|
||
case TopicNarrow(): | ||
case DmNarrow(): | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: let's keep these cases in the same order as in _messageVisible, for ease of comparing the logic. It's important that the two align (that's this method's job); and it's potentially a bit subtle to confirm that, so it's good to make it as easy as possible.
It's fine for this to have two separate groups of cases that return the same thing.
MutedUsersVisibilityEffect _mutedUsersEventCanAffectVisibility(MutedUsersEvent event) { | ||
switch(narrow) { | ||
case CombinedFeedNarrow(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similarly, put the cases in the same order as in _messageVisible
final union = setUnion(sortedOld, sortedNew); | ||
|
||
final willMuteSome = sortedOld.length < union.length; | ||
final willUnmuteSome = sortedNew.length < union.length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat, yeah, this logic works.
This is awkwardly verbose, but we're about to add another kind of visibility effect, and I think the code will end up clearer if we make a separate enum for it. Greg points out that an upcoming Dart feature "dot shorthands" should help with this verbosity: zulip#1561 (comment)
0acc63b
to
ceb4e0f
Compare
Thanks! Revision pushed. |
Thanks! Those changes look good. There's a CI failure in build_runner. (And there are parts of the branch I still need to read, per #1561 (review) .) |
ceb4e0f
to
f3f4df2
Compare
This is awkwardly verbose, but we're about to add another kind of visibility effect, and I think the code will end up clearer if we make a separate enum for it. Greg points out that an upcoming Dart feature "dot shorthands" should help with this verbosity: zulip#1561 (comment)
I just rebased atop current |
This is awkwardly verbose, but we're about to add another kind of visibility effect, and I think the code will end up clearer if we make a separate enum for it. Greg points out that an upcoming Dart feature "dot shorthands" should help with this verbosity: zulip#1561 (comment)
f3f4df2
to
5438a65
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, and read those remaining 4 commits. Just small comments below.
// TODO(#236) test email too, not just name | ||
if (!user.isActive) return false; | ||
if (store.isUserMuted(user.userId)) return false; | ||
|
||
return _testName(user, cache); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
// TODO(#236) test email too, not just name | |
if (!user.isActive) return false; | |
if (store.isUserMuted(user.userId)) return false; | |
return _testName(user, cache); | |
if (!user.isActive) return false; | |
if (store.isUserMuted(user.userId)) return false; | |
// TODO(#236) test email too, not just name | |
return _testName(user, cache); |
The comment was already a bit separated from what it applied to, so perhaps should have been moved down there sooner; but this would widen the separation, so let's fix it.
(Can stay in the same commit, no need to make a separate prep commit.)
final typistIds = model!.typistIdsInNarrow(narrow); | ||
if (typistIds.isEmpty) return const SizedBox(); | ||
final text = switch (typistIds.length) { | ||
if (typistIds == null) return const SizedBox(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
msglist [nfc]: Represent nobody-is-typing as null, not empty list
Just to skip the bit of extra work of creating new lists.
Hmm, this feels like the API gets a bit more complicated from the caller's perspective. What if typistIds
is empty, and why is there a different possibility which is that it's null?
(In reality I think it's never empty after this change — _removeTypist removes the sub-maps when empty. But that's not obvious from the outside.)
Iterable<int> typistIdsInNarrow(SendableNarrow narrow) => | ||
_timerMapsByNarrow[narrow]?.keys ?? []; | ||
Iterable<int>? typistIdsInNarrow(SendableNarrow narrow) => | ||
_timerMapsByNarrow[narrow]?.keys; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternate way of not creating new lists each time:
Iterable<int> typistIdsInNarrow(SendableNarrow narrow) =>
_timerMapsByNarrow[narrow]?.keys ?? const [];
final filteredTypistIds = typistIds | ||
.whereNot((userId) => store.isUserMuted(userId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can use a tear-off, which is shorter and I think here a bit easier to read:
final filteredTypistIds = typistIds | |
.whereNot((userId) => store.isUserMuted(userId)); | |
final filteredTypistIds = typistIds.whereNot(store.isUserMuted); |
expected: 'Third User and Fourth User are typing…'); | ||
await store.setMutedUsers([eg.thirdUser.userId]); | ||
await tester.pump(); | ||
check(tester.widget<Text>(finder)).data.equals('Fourth User is typing…'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's put this in a separate test case. This one (or this pair of them) is pretty long and a bit unfocused already.
The new test case can be for just a topic narrow; I don't think it needs to exercise both kinds of conversations.
final sansMuted = store.allUsers | ||
.whereNot((User user) => store.isUserMuted(user.userId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: omit boring types
final sansMuted = store.allUsers | |
.whereNot((User user) => store.isUserMuted(user.userId)); | |
final sansMuted = store.allUsers | |
.whereNot((user) => store.isUserMuted(user.userId)); |
…uted Co-authored-by: Sayed Mahmood Sayedi <[email protected]>
This is solely for a better order.
This is awkwardly verbose, but we're about to add another kind of visibility effect, and I think the code will end up clearer if we make a separate enum for it. Greg points out that an upcoming Dart feature "dot shorthands" should help with this verbosity: zulip#1561 (comment)
…muted In the future, this should apply to the ReactionsNarrow from the Web app too, once we have it. Co-authored-by: Sayed Mahmood Sayedi <[email protected]>
Co-authored-by: Sayed Mahmood Sayedi <[email protected]>
Just to skip the bit of extra work of creating new lists.
This completes the planned work for muting muted users (hooray!). Fixes: zulip#296
5438a65
to
79986a1
Compare
(Just rebased after merging #1560.) |
Stacked on #1560.
Many thanks again to @sm-sayedi for your work on this! As with #1560, this is meant to take #1429 across the finish line in time for the upcoming app launch. Thanks again for making sure I had your latest revision of #1429 before you left for vacation. 🙂
In these new commits:
Fixes: #296