diff --git a/lib/model/unreads.dart b/lib/model/unreads.dart index cb3476145f..ddd80af185 100644 --- a/lib/model/unreads.dart +++ b/lib/model/unreads.dart @@ -193,6 +193,25 @@ class Unreads extends ChangeNotifier { return c; } + /// The "broadest" unread count for this channel, + /// without doing any checking on visibility policy. + /// + /// This includes all topics that have regardless visibility policy, + /// even if the channel is muted. + /// + /// This is needed for one specific case, which is when the channel has + /// only muted unreads including a mention or more, in that case we show + /// total unread count including muted unreads. + int countAll(int streamId) { + final topics = streams[streamId]; + if (topics == null) return 0; + int c = 0; + for (final entry in topics.entries) { + c = c + entry.value.length; + } + return c; + } + int countInTopicNarrow(int streamId, String topic) { final topics = streams[streamId]; return topics?[topic]?.length ?? 0; diff --git a/lib/widgets/subscription_list.dart b/lib/widgets/subscription_list.dart index b8ffaf6c86..d7d5cdb985 100644 --- a/lib/widgets/subscription_list.dart +++ b/lib/widgets/subscription_list.dart @@ -198,8 +198,11 @@ class _SubscriptionList extends StatelessWidget { final hasOnlyMutedMentions = !subscription.isMuted && channelsWithMentions.contains(subscription.streamId) && !channelsWithUnmutedMentions.contains(subscription.streamId); + final mutedUnreadCount = hasOnlyMutedMentions && unreadCount == 0 ? + unreadsModel!.countAll(subscription.streamId) : 0; return SubscriptionItem(subscription: subscription, unreadCount: unreadCount, + mutedUnreadCount: mutedUnreadCount, showMutedUnreadBadge: showMutedUnreadBadge, hasMentions: hasMentions, hasOnlyMutedMentions: hasOnlyMutedMentions); @@ -213,6 +216,7 @@ class SubscriptionItem extends StatelessWidget { super.key, required this.subscription, required this.unreadCount, + required this.mutedUnreadCount, required this.showMutedUnreadBadge, required this.hasMentions, required this.hasOnlyMutedMentions, @@ -220,6 +224,7 @@ class SubscriptionItem extends StatelessWidget { final Subscription subscription; final int unreadCount; + final int mutedUnreadCount; final bool showMutedUnreadBadge; final bool hasMentions; final bool hasOnlyMutedMentions; @@ -230,7 +235,8 @@ class SubscriptionItem extends StatelessWidget { final swatch = colorSwatchFor(context, subscription); final hasUnreads = (unreadCount > 0); - final opacity = subscription.isMuted ? 0.55 : 1.0; + const mutedOpacity = 0.55; + final opacity = subscription.isMuted ? mutedOpacity : 1.0; return Material( // TODO(design) check if this is the right variable color: designVariables.background, @@ -277,6 +283,15 @@ class SubscriptionItem extends StatelessWidget { count: unreadCount, backgroundColor: swatch, bold: true)), + ] else if (hasOnlyMutedMentions && !subscription.isMuted) ...[ + const SizedBox(width: 12), + const AtMentionMarker(muted: true), + Opacity( + opacity: mutedOpacity, + child: UnreadCountBadge( + count: mutedUnreadCount, + backgroundColor: swatch, + bold: true)), ] else if (showMutedUnreadBadge) ...[ const SizedBox(width: 12), if (hasMentions) const AtMentionMarker(muted: true), diff --git a/test/widgets/subscription_list_test.dart b/test/widgets/subscription_list_test.dart index 25b4362b25..dad94aac56 100644 --- a/test/widgets/subscription_list_test.dart +++ b/test/widgets/subscription_list_test.dart @@ -188,6 +188,29 @@ void main() { check(find.byType(MutedUnreadBadge).evaluate().length).equals(0); }); + testWidgets('unread badge shows as faded when non-muted subscription has only muted mentions', (tester) async { + final stream = eg.stream(); + + await setupStreamListPage(tester, + subscriptions: [ + eg.subscription(stream), + ], + userTopics: [ + eg.userTopicItem(stream, 'a', UserTopicVisibilityPolicy.muted), + ], + unreadMsgs: eg.unreadMsgs( + mentions: [1, 2], + channels: [ + UnreadChannelSnapshot(streamId: stream.streamId, topic: 'a', unreadMessageIds: [1, 2]), + ]), + ); + + check(find.byType(AtMentionMarker).evaluate()).single; + check(tester.widget(find.descendant( + of: find.byType(UnreadCountBadge), matching: find.byType(Text)))) + .data.equals('2'); + }); + testWidgets('muted unread badge shows when unreads are visible in channel but not inbox', (tester) async { final stream = eg.stream(); final unreadMsgs = eg.unreadMsgs(channels: [