Skip to content

Commit 43403b1

Browse files
committed
model: Add more colors to StreamColorSwatch
We'll use these soon, in the Inbox view.
1 parent 1352007 commit 43403b1

File tree

3 files changed

+180
-0
lines changed

3 files changed

+180
-0
lines changed

lib/api/model/model.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/foundation.dart';
22
import 'package:flutter/painting.dart';
3+
import 'package:flutter_color_models/flutter_color_models.dart';
34
import 'package:json_annotation/json_annotation.dart';
45

56
import '../../widgets/color.dart';
@@ -396,9 +397,30 @@ class StreamColorSwatch extends ColorSwatch<_StreamColorVariant> {
396397

397398
Color get unreadCountBadgeBackground => this[_StreamColorVariant.unreadCountBadgeBackground]!;
398399

400+
/// The stream icon on a plain-colored surface, such as white.
401+
///
402+
/// For the icon on a [barBackground]-colored surface,
403+
/// use [iconOnBarBackground] instead.
404+
Color get iconOnPlainBackground => this[_StreamColorVariant.iconOnPlainBackground]!;
405+
406+
/// The stream icon on a [barBackground]-colored surface.
407+
///
408+
/// For the icon on a plain surface, use [iconOnPlainBackground] instead.
409+
/// This color is chosen to enhance contrast with [barBackground]:
410+
/// <https://github.com/zulip/zulip/pull/27485>
411+
Color get iconOnBarBackground => this[_StreamColorVariant.iconOnBarBackground]!;
412+
413+
/// The background color of a bar representing a stream, like a recipient bar.
414+
///
415+
/// Use this in the message list, the "Inbox" view, and the "Streams" view.
416+
Color get barBackground => this[_StreamColorVariant.barBackground]!;
417+
399418
static Map<_StreamColorVariant, Color> _compute(int base) {
400419
final baseAsColor = Color(base);
401420

421+
final clamped20to75 = clampLchLightness(baseAsColor, 20, 75);
422+
final clamped20to75AsHsl = HSLColor.fromColor(clamped20to75);
423+
402424
return {
403425
_StreamColorVariant.base: baseAsColor,
404426

@@ -410,13 +432,45 @@ class StreamColorSwatch extends ColorSwatch<_StreamColorVariant> {
410432
_StreamColorVariant.unreadCountBadgeBackground:
411433
clampLchLightness(baseAsColor, 30, 70)
412434
.withOpacity(0.3),
435+
436+
// Follows `.sidebar-row__icon` in Vlad's replit:
437+
// <https://replit.com/@VladKorobov/zulip-topic-feed-colors#script.js>
438+
//
439+
// TODO fix bug where our results differ from the replit's (see unit tests)
440+
_StreamColorVariant.iconOnPlainBackground: clamped20to75,
441+
442+
// Follows `.recepeient__icon` in Vlad's replit:
443+
// <https://replit.com/@VladKorobov/zulip-topic-feed-colors#script.js>
444+
// <https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/design.3A.20.23F117.20.22Inbox.22.20screen/near/1624484>
445+
//
446+
// TODO fix bug where our results differ from the replit's (see unit tests)
447+
_StreamColorVariant.iconOnBarBackground:
448+
clamped20to75AsHsl
449+
.withLightness(clamped20to75AsHsl.lightness - 0.12)
450+
.toColor(),
451+
452+
// Follows `.recepient` in Vlad's replit:
453+
// <https://replit.com/@VladKorobov/zulip-topic-feed-colors#script.js>
454+
//
455+
// TODO I think [LabColor.interpolate] doesn't actually do LAB mixing;
456+
// it just calls up to the superclass method [ColorModel.interpolate]:
457+
// <https://pub.dev/documentation/flutter_color_models/latest/flutter_color_models/ColorModel/interpolate.html>
458+
// which does ordinary RGB mixing. Investigate and send a PR?
459+
// TODO fix bug where our results differ from the replit's (see unit tests)
460+
_StreamColorVariant.barBackground:
461+
LabColor.fromColor(const Color(0xfff9f9f9))
462+
.interpolate(LabColor.fromColor(clamped20to75), 0.22)
463+
.toColor(),
413464
};
414465
}
415466
}
416467

417468
enum _StreamColorVariant {
418469
base,
419470
unreadCountBadgeBackground,
471+
iconOnPlainBackground,
472+
iconOnBarBackground,
473+
barBackground,
420474
}
421475

422476
/// As in the get-messages response.

test/api/model/model_checks.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ extension ZulipStreamChecks on Subject<ZulipStream> {
1010
extension StreamColorSwatchChecks on Subject<StreamColorSwatch> {
1111
Subject<Color> get base => has((s) => s.base, 'base');
1212
Subject<Color> get unreadCountBadgeBackground => has((s) => s.unreadCountBadgeBackground, 'unreadCountBadgeBackground');
13+
Subject<Color> get iconOnPlainBackground => has((s) => s.iconOnPlainBackground, 'iconOnPlainBackground');
14+
Subject<Color> get iconOnBarBackground => has((s) => s.iconOnBarBackground, 'iconOnBarBackground');
15+
Subject<Color> get barBackground => has((s) => s.barBackground, 'barBackground');
1316
}
1417

1518
extension MessageChecks on Subject<Message> {

test/api/model/model_test.dart

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,129 @@ void main() {
193193
runCheck(0xFFFFFFE0, const Color(0x4dadad90)); // 0x4dacad90
194194
runCheck(0xFFFF69B4, const Color(0x4dff69b4));
195195
});
196+
197+
test('iconOnPlainBackground', () {
198+
void runCheck(int base, Color expected) {
199+
check(StreamColorSwatch(base)).iconOnPlainBackground.equals(expected);
200+
}
201+
202+
// Check against everything in ZULIP_ASSIGNMENT_COLORS
203+
// in <https://replit.com/@VladKorobov/zulip-topic-feed-colors#script.js>.
204+
// (Skipping `streamColors` because there are 100+ of them.)
205+
// On how to extract expected results from the replit, see:
206+
// TODO
207+
208+
// TODO Fix bug causing our implementation's results to differ from the
209+
// replit's. Where they differ, see comment with what the replit gives.
210+
211+
runCheck(0xff76ce90, const Color(0xff73cb8d));
212+
runCheck(0xfffae589, const Color(0xffccb95f)); // 0xffcbb85e
213+
runCheck(0xffa6c7e5, const Color(0xff9cbcda)); // 0xff9cbddb
214+
runCheck(0xffe79ab5, const Color(0xffe79ab5));
215+
runCheck(0xffbfd56f, const Color(0xffacc25d));
216+
runCheck(0xfff4ae55, const Color(0xfff0ab52)); // 0xffefa951
217+
runCheck(0xffb0a5fd, const Color(0xffb0a5fd));
218+
runCheck(0xffaddfe5, const Color(0xff90c1c7)); // 0xff90c2c8
219+
runCheck(0xfff5ce6e, const Color(0xffd9b456)); // 0xffd8b355
220+
runCheck(0xffc2726a, const Color(0xffc2726a));
221+
runCheck(0xff94c849, const Color(0xff94c849));
222+
runCheck(0xffbd86e5, const Color(0xffbd86e5));
223+
runCheck(0xffee7e4a, const Color(0xffee7e4a));
224+
runCheck(0xffa6dcbf, const Color(0xff8fc4a8));
225+
runCheck(0xff95a5fd, const Color(0xff95a5fd));
226+
runCheck(0xff53a063, const Color(0xff53a063));
227+
runCheck(0xff9987e1, const Color(0xff9987e1));
228+
runCheck(0xffe4523d, const Color(0xffe4523d));
229+
runCheck(0xffc2c2c2, const Color(0xffb9b9b9));
230+
runCheck(0xff4f8de4, const Color(0xff4f8de4));
231+
runCheck(0xffc6a8ad, const Color(0xffc6a8ad));
232+
runCheck(0xffe7cc4d, const Color(0xffd1b839)); // 0xffd0b737
233+
runCheck(0xffc8bebf, const Color(0xffc0b6b7));
234+
runCheck(0xffa47462, const Color(0xffa47462));
235+
runCheck(0xffacc25d, const Color(0xffacc25d));
236+
});
237+
238+
test('iconOnBarBackground', () {
239+
void runCheck(int base, Color expected) {
240+
check(StreamColorSwatch(base)).iconOnBarBackground.equals(expected);
241+
}
242+
243+
// Check against everything in ZULIP_ASSIGNMENT_COLORS
244+
// in <https://replit.com/@VladKorobov/zulip-topic-feed-colors#script.js>.
245+
// (Skipping `streamColors` because there are 100+ of them.)
246+
// On how to extract expected results from the replit, see:
247+
// TODO
248+
249+
// TODO Fix bug causing our implementation's results to differ from the
250+
// replit's. Where they differ, see comment with what the replit gives.
251+
252+
runCheck(0xff76ce90, const Color(0xff46ba69));
253+
runCheck(0xfffae589, const Color(0xffb49f39)); // 0xffb29d3a
254+
runCheck(0xffa6c7e5, const Color(0xff6f9ec9)); // 0xff6f9fcb
255+
runCheck(0xffe79ab5, const Color(0xffdb6991));
256+
runCheck(0xffbfd56f, const Color(0xff8ea43e));
257+
runCheck(0xfff4ae55, const Color(0xffeb901a)); // 0xffea8d19
258+
runCheck(0xffb0a5fd, const Color(0xff7b69fc));
259+
runCheck(0xffaddfe5, const Color(0xff67aab2)); // 0xff67acb4
260+
runCheck(0xfff5ce6e, const Color(0xffc59a2c)); // 0xffc3992d
261+
runCheck(0xffc2726a, const Color(0xffa94e45));
262+
runCheck(0xff94c849, const Color(0xff74a331));
263+
runCheck(0xffbd86e5, const Color(0xffa254da));
264+
runCheck(0xffee7e4a, const Color(0xffe55716));
265+
runCheck(0xffa6dcbf, const Color(0xff67af89));
266+
runCheck(0xff95a5fd, const Color(0xff5972fc));
267+
runCheck(0xff53a063, const Color(0xff3e784a));
268+
runCheck(0xff9987e1, const Color(0xff6f56d5));
269+
runCheck(0xffe4523d, const Color(0xffc8311c));
270+
runCheck(0xffc2c2c2, const Color(0xff9a9a9a));
271+
runCheck(0xff4f8de4, const Color(0xff216cd5));
272+
runCheck(0xffc6a8ad, const Color(0xffae838a));
273+
runCheck(0xffe7cc4d, const Color(0xffa69127)); // 0xffa38f26
274+
runCheck(0xffc8bebf, const Color(0xffa49597));
275+
runCheck(0xffa47462, const Color(0xff7f584a));
276+
runCheck(0xffacc25d, const Color(0xff8ea43e));
277+
});
278+
279+
test('barBackground', () {
280+
void runCheck(int base, Color expected) {
281+
check(StreamColorSwatch(base)).barBackground.equals(expected);
282+
}
283+
284+
// Check against everything in ZULIP_ASSIGNMENT_COLORS
285+
// in <https://replit.com/@VladKorobov/zulip-topic-feed-colors#script.js>.
286+
// (Skipping `streamColors` because there are 100+ of them.)
287+
// On how to extract expected results from the replit, see:
288+
// TODO
289+
290+
// TODO Fix bug causing our implementation's results to differ from the
291+
// replit's. Where they differ, see comment with what the replit gives.
292+
293+
runCheck(0xff76ce90, const Color(0xffddefe1));
294+
runCheck(0xfffae589, const Color(0xfff1ead7)); // 0xfff0ead6
295+
runCheck(0xffa6c7e5, const Color(0xffe5ebf2)); // 0xffe5ecf2
296+
runCheck(0xffe79ab5, const Color(0xfff6e4ea));
297+
runCheck(0xffbfd56f, const Color(0xffe9edd6));
298+
runCheck(0xfff4ae55, const Color(0xfffbe7d4)); // 0xfffae7d4
299+
runCheck(0xffb0a5fd, const Color(0xffeae6fa));
300+
runCheck(0xffaddfe5, const Color(0xffe2edee));
301+
runCheck(0xfff5ce6e, const Color(0xfff5e9d5)); // 0xfff4e9d5
302+
runCheck(0xffc2726a, const Color(0xfff0dbd8)); // 0xffefdbd8
303+
runCheck(0xff94c849, const Color(0xffe5eed3)); // 0xffe4eed3
304+
runCheck(0xffbd86e5, const Color(0xffeddff5));
305+
runCheck(0xffee7e4a, const Color(0xfffdded1)); // 0xfffcded1
306+
runCheck(0xffa6dcbf, const Color(0xffe2ede7));
307+
runCheck(0xff95a5fd, const Color(0xffe5e6fa)); // 0xffe4e6fa
308+
runCheck(0xff53a063, const Color(0xffd5e5d6));
309+
runCheck(0xff9987e1, const Color(0xffe5dff4));
310+
runCheck(0xffe4523d, const Color(0xfffcd6cd)); // 0xfffbd6cd
311+
runCheck(0xffc2c2c2, const Color(0xffebebeb));
312+
runCheck(0xff4f8de4, const Color(0xffd9e0f5)); // 0xffd8e0f5
313+
runCheck(0xffc6a8ad, const Color(0xffeee7e8));
314+
runCheck(0xffe7cc4d, const Color(0xfff4ead0)); // 0xfff3eacf
315+
runCheck(0xffc8bebf, const Color(0xffeceaea));
316+
runCheck(0xffa47462, const Color(0xffe7dad6));
317+
runCheck(0xffacc25d, const Color(0xffe9edd6));
318+
});
196319
});
197320
});
198321

0 commit comments

Comments
 (0)