Skip to content

Commit 9edefdb

Browse files
committed
unread_count_badge [nfc]: Encapsulate finding ChannelColorSwatch from ID
1 parent db04ee6 commit 9edefdb

File tree

7 files changed

+61
-38
lines changed

7 files changed

+61
-38
lines changed

lib/widgets/inbox.dart

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import '../model/narrow.dart';
66
import '../model/recent_dm_conversations.dart';
77
import '../model/unreads.dart';
88
import 'action_sheet.dart';
9-
import 'channel_colors.dart';
109
import 'icons.dart';
1110
import 'message_list.dart';
1211
import 'page.dart';
@@ -250,7 +249,9 @@ abstract class _HeaderItem extends StatelessWidget {
250249
Color collapsedIconColor(BuildContext context);
251250
Color uncollapsedIconColor(BuildContext context);
252251
Color uncollapsedBackgroundColor(BuildContext context);
253-
ChannelColorSwatch? unreadCountBadgeBackgroundColor(BuildContext context);
252+
253+
/// A channel ID, if this represents a channel, else null.
254+
int? get channelId;
254255

255256
Future<void> onCollapseButtonTap() async {
256257
if (!collapsed) {
@@ -308,7 +309,7 @@ abstract class _HeaderItem extends StatelessWidget {
308309
if (hasMention) const _IconMarker(icon: ZulipIcons.at_sign),
309310
Padding(padding: const EdgeInsetsDirectional.only(end: 16),
310311
child: UnreadCountBadge(
311-
backgroundColor: unreadCountBadgeBackgroundColor(context),
312+
channelIdForBackground: channelId,
312313
bold: true,
313314
count: count)),
314315
])));
@@ -333,7 +334,7 @@ class _AllDmsHeaderItem extends _HeaderItem {
333334
@override Color uncollapsedIconColor(context) => DesignVariables.of(context).labelMenuButton;
334335

335336
@override Color uncollapsedBackgroundColor(context) => DesignVariables.of(context).dmHeaderBg;
336-
@override ChannelColorSwatch? unreadCountBadgeBackgroundColor(context) => null;
337+
@override int? get channelId => null;
337338

338339
@override Future<void> onCollapseButtonTap() async {
339340
await super.onCollapseButtonTap();
@@ -430,8 +431,7 @@ class _DmItem extends StatelessWidget {
430431
const SizedBox(width: 12),
431432
if (hasMention) const _IconMarker(icon: ZulipIcons.at_sign),
432433
Padding(padding: const EdgeInsetsDirectional.only(end: 16),
433-
child: UnreadCountBadge(backgroundColor: null,
434-
count: count)),
434+
child: UnreadCountBadge(count: count)),
435435
]))));
436436
}
437437
}
@@ -463,8 +463,7 @@ class _StreamHeaderItem extends _HeaderItem with _LongPressable {
463463
colorSwatchFor(context, subscription).iconOnBarBackground;
464464
@override Color uncollapsedBackgroundColor(context) =>
465465
colorSwatchFor(context, subscription).barBackground;
466-
@override ChannelColorSwatch? unreadCountBadgeBackgroundColor(context) =>
467-
colorSwatchFor(context, subscription);
466+
@override int? get channelId => subscription.streamId;
468467

469468
@override Future<void> onCollapseButtonTap() async {
470469
await super.onCollapseButtonTap();
@@ -527,7 +526,6 @@ class _TopicItem extends StatelessWidget {
527526
:topic, :count, :hasMention, :lastUnreadId) = data;
528527

529528
final store = PerAccountStoreWidget.of(context);
530-
final subscription = store.subscriptions[streamId]!;
531529

532530
final designVariables = DesignVariables.of(context);
533531
final visibilityIcon = iconDataForTopicVisibilityPolicy(
@@ -567,7 +565,7 @@ class _TopicItem extends StatelessWidget {
567565
if (visibilityIcon != null) _IconMarker(icon: visibilityIcon),
568566
Padding(padding: const EdgeInsetsDirectional.only(end: 16),
569567
child: UnreadCountBadge(
570-
backgroundColor: colorSwatchFor(context, subscription),
568+
channelIdForBackground: streamId,
571569
count: count)),
572570
]))));
573571
}

lib/widgets/recent_dm_conversations.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,7 @@ class RecentDmConversationsItem extends StatelessWidget {
233233
const SizedBox(width: 12),
234234
unreadCount > 0
235235
? Padding(padding: const EdgeInsetsDirectional.only(end: 16),
236-
child: UnreadCountBadge(backgroundColor: null,
237-
count: unreadCount))
236+
child: UnreadCountBadge(count: unreadCount))
238237
: const SizedBox(),
239238
]))));
240239
}

lib/widgets/subscription_list.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ class SubscriptionItem extends StatelessWidget {
337337
opacity: opacity,
338338
child: UnreadCountBadge(
339339
count: unreadCount,
340-
backgroundColor: swatch,
340+
channelIdForBackground: subscription.streamId,
341341
bold: true)),
342342
] else if (showMutedUnreadBadge) ...[
343343
const SizedBox(width: 12),

lib/widgets/unread_count_badge.dart

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/widgets.dart';
22

3-
import 'channel_colors.dart';
3+
import 'store.dart';
44
import 'text.dart';
55
import 'theme.dart';
66

@@ -12,33 +12,42 @@ class UnreadCountBadge extends StatelessWidget {
1212
const UnreadCountBadge({
1313
super.key,
1414
required this.count,
15-
required this.backgroundColor,
15+
this.channelIdForBackground,
1616
this.bold = false,
1717
});
1818

1919
final int count;
2020
final bool bold;
2121

22-
/// An optional [ChannelColorSwatch], to override the default color scheme
23-
/// with a channel-colorized one.
22+
/// An optional [Subscription.streamId], for a channel-colorized background.
2423
///
25-
/// Pass this if the badge represents messages in one specific stream.
26-
/// The appropriate color from the swatch will be used.
27-
final ChannelColorSwatch? backgroundColor;
24+
/// Useful when this badge represents messages in one specific channel.
25+
///
26+
/// If null, the default neutral background will be used.
27+
final int? channelIdForBackground;
2828

2929
@override
3030
Widget build(BuildContext context) {
31+
final store = PerAccountStoreWidget.of(context);
3132
final designVariables = DesignVariables.of(context);
3233

33-
final effectiveBackgroundColor = switch (backgroundColor) {
34-
ChannelColorSwatch(unreadCountBadgeBackground: var color) => color,
35-
null => designVariables.bgCounterUnread,
36-
};
34+
final Color textColor;
35+
final Color backgroundColor;
36+
if (channelIdForBackground != null) {
37+
textColor = designVariables.unreadCountBadgeTextForChannel;
38+
39+
final subscription = store.subscriptions[channelIdForBackground!];
40+
final swatch = colorSwatchFor(context, subscription);
41+
backgroundColor = swatch.unreadCountBadgeBackground;
42+
} else {
43+
textColor = designVariables.labelCounterUnread;
44+
backgroundColor = designVariables.bgCounterUnread;
45+
}
3746

3847
return DecoratedBox(
3948
decoration: BoxDecoration(
4049
borderRadius: BorderRadius.circular(3),
41-
color: effectiveBackgroundColor,
50+
color: backgroundColor,
4251
),
4352
child: Padding(
4453
padding: const EdgeInsets.fromLTRB(4, 0, 4, 1),
@@ -47,9 +56,7 @@ class UnreadCountBadge extends StatelessWidget {
4756
fontSize: 16,
4857
height: (18 / 16),
4958
fontFeatures: const [FontFeature.enable('smcp')], // small caps
50-
color: backgroundColor is ChannelColorSwatch
51-
? designVariables.unreadCountBadgeTextForChannel
52-
: designVariables.labelCounterUnread,
59+
color: textColor,
5360
).merge(weightVariableTextStyle(context,
5461
wght: bold ? 600 : null)),
5562
count.toString())));

test/widgets/checks.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ extension PerAccountStoreWidgetChecks on Subject<PerAccountStoreWidget> {
9595
extension UnreadCountBadgeChecks on Subject<UnreadCountBadge> {
9696
Subject<int> get count => has((b) => b.count, 'count');
9797
Subject<bool> get bold => has((b) => b.bold, 'bold');
98-
Subject<Color?> get backgroundColor => has((b) => b.backgroundColor, 'backgroundColor');
98+
Subject<int?> get channelIdForBackground => has((b) => b.channelIdForBackground, 'channelIdForBackground');
9999
}
100100

101101
extension UnicodeEmojiWidgetChecks on Subject<UnicodeEmojiWidget> {

test/widgets/subscription_list_test.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:checks/checks.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter_checks/flutter_checks.dart';
44
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:legacy_checks/legacy_checks.dart';
56
import 'package:zulip/api/model/initial_snapshot.dart';
67
import 'package:zulip/api/model/model.dart';
78
import 'package:zulip/widgets/color.dart';
@@ -273,8 +274,12 @@ void main() {
273274
check(getItemCount()).equals(1);
274275
check(tester.widget<Icon>(find.byIcon(iconDataForStream(stream))).color)
275276
.isNotNull().isSameColorAs(swatch.iconOnPlainBackground);
276-
check(tester.widget<UnreadCountBadge>(find.byType(UnreadCountBadge)).backgroundColor)
277-
.isNotNull().isSameColorAs(swatch);
277+
278+
final unreadCountBadgeRenderBox = tester.renderObject<RenderBox>(find.byType(UnreadCountBadge));
279+
check(unreadCountBadgeRenderBox).legacyMatcher(
280+
// `paints` isn't a [Matcher] so we wrap it with `equals`;
281+
// awkward but it works
282+
equals(paints..rrect(color: swatch.unreadCountBadgeBackground)));
278283
});
279284

280285
testWidgets('muted streams are displayed as faded', (tester) async {

test/widgets/unread_count_badge_test.dart

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import 'package:flutter_checks/flutter_checks.dart';
33
import 'package:flutter/material.dart';
44

55
import 'package:flutter_test/flutter_test.dart';
6+
import 'package:zulip/api/model/model.dart';
67
import 'package:zulip/widgets/channel_colors.dart';
78
import 'package:zulip/widgets/unread_count_badge.dart';
89

10+
import '../example_data.dart' as eg;
911
import '../model/binding.dart';
12+
import '../model/test_store.dart';
1013
import 'test_app.dart';
1114

1215
void main() {
@@ -15,16 +18,24 @@ void main() {
1518
group('UnreadCountBadge', () {
1619
Future<void> prepare(WidgetTester tester, {
1720
required Widget child,
21+
Subscription? subscription,
1822
}) async {
1923
addTearDown(testBinding.reset);
24+
await testBinding.globalStore.add(eg.selfAccount, eg.initialSnapshot());
25+
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
26+
if (subscription != null) {
27+
await store.addStream(ZulipStream.fromSubscription(subscription));
28+
await store.addSubscription(subscription);
29+
}
2030
await tester.pumpWidget(TestZulipApp(
31+
accountId: eg.selfAccount.id,
2132
child: child));
2233
await tester.pump();
34+
await tester.pump();
2335
}
2436

2537
testWidgets('smoke test; no crash', (tester) async {
26-
await prepare(tester,
27-
child: UnreadCountBadge(count: 1, backgroundColor: null));
38+
await prepare(tester, child: const UnreadCountBadge(count: 1));
2839
tester.widget(find.text("1"));
2940
});
3041

@@ -36,16 +47,19 @@ void main() {
3647
}
3748

3849
testWidgets('default color', (tester) async {
39-
await prepare(tester,
40-
child: UnreadCountBadge(count: 1, backgroundColor: null));
50+
await prepare(tester, child: UnreadCountBadge(count: 1));
4151
check(findBackgroundColor(tester)).isNotNull().isSameColorAs(const Color(0x26666699));
4252
});
4353

4454
testWidgets('stream color', (tester) async {
45-
final swatch = ChannelColorSwatch.light(0xff76ce90);
55+
final subscription = eg.subscription(eg.stream(), color: 0xff76ce90);
4656
await prepare(tester,
47-
child: UnreadCountBadge(count: 1, backgroundColor: swatch));
48-
check(findBackgroundColor(tester)).isNotNull().isSameColorAs(swatch.unreadCountBadgeBackground);
57+
child: UnreadCountBadge(
58+
count: 1,
59+
channelIdForBackground: subscription.streamId),
60+
subscription: subscription);
61+
check(findBackgroundColor(tester)).isNotNull()
62+
.isSameColorAs(ChannelColorSwatch.light(0xff76ce90).unreadCountBadgeBackground);
4963
});
5064
});
5165
});

0 commit comments

Comments
 (0)