Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions lib/widgets/channel_colors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,28 +91,40 @@ class ChannelColorSwatch extends ColorSwatch<ChannelColorVariant> {

/// The channel icon on a plain-colored surface, such as white.
///
/// For the icon on a [barBackground]-colored surface,
/// For the icon on a [barBackgroundSolid]-colored surface,
/// use [iconOnBarBackground] instead.
Color get iconOnPlainBackground => this[ChannelColorVariant.iconOnPlainBackground]!;

/// The channel icon on a [barBackground]-colored surface.
/// The channel icon on a [barBackgroundSolid]-colored surface.
///
/// For the icon on a plain surface, use [iconOnPlainBackground] instead.
/// This color is chosen to enhance contrast with [barBackground]:
/// This color is chosen to enhance contrast with [barBackgroundSolid]:
/// <https://github.com/zulip/zulip/pull/27485>
Color get iconOnBarBackground => this[ChannelColorVariant.iconOnBarBackground]!;

/// The background color of a bar representing a channel, like a recipient bar.
///
/// Use this in the message list, the "Inbox" view, and the "Channels" view.
Color get barBackground => this[ChannelColorVariant.barBackground]!;
Color get barBackgroundSolid => this[ChannelColorVariant.barBackgroundSolid]!;

/// The top color of a gradient-shaded bar representing a channel,
/// as in the inbox.
Color get barBackgroundGradientTop => this[ChannelColorVariant.barBackgroundGradientTop]!;

/// The bottom color of a gradient-shaded bar representing a channel,
/// as in the inbox.
Color get barBackgroundGradientBottom => this[ChannelColorVariant.barBackgroundGradientBottom]!;

static Map<ChannelColorVariant, Color> _computeLight(int base) {
final baseAsColor = Color(base);

final clamped20to75 = clampLchLightness(baseAsColor, 20, 75);
final clamped20to75AsHsl = HSLColor.fromColor(clamped20to75);

final barBackgroundSolid = LabColor.fromColor(const Color(0xfff9f9f9))
.interpolate(LabColor.fromColor(clamped20to75), 0.22)
.toColor();

return {
ChannelColorVariant.base: baseAsColor,

Expand Down Expand Up @@ -149,10 +161,12 @@ class ChannelColorSwatch extends ColorSwatch<ChannelColorVariant> {
// <https://pub.dev/documentation/flutter_color_models/latest/flutter_color_models/ColorModel/interpolate.html>
// which does ordinary RGB mixing. Investigate and send a PR?
// TODO fix bug where our results differ from the replit's (see unit tests)
ChannelColorVariant.barBackground:
LabColor.fromColor(const Color(0xfff9f9f9))
.interpolate(LabColor.fromColor(clamped20to75), 0.22)
.toColor(),
ChannelColorVariant.barBackgroundSolid: barBackgroundSolid,

ChannelColorVariant.barBackgroundGradientTop: barBackgroundSolid,

ChannelColorVariant.barBackgroundGradientBottom:
barBackgroundSolid.withValues(alpha: 0),
};
}

Expand All @@ -161,6 +175,10 @@ class ChannelColorSwatch extends ColorSwatch<ChannelColorVariant> {

final clamped20to75 = clampLchLightness(baseAsColor, 20, 75);

final barBackgroundSolid = LabColor.fromColor(const Color(0xff000000))
.interpolate(LabColor.fromColor(clamped20to75), 0.38)
.toColor();

return {
// See comments in [_computeLight] about what these computations are based
// on, and how the resulting values are a little off sometimes. The
Expand All @@ -187,10 +205,13 @@ class ChannelColorSwatch extends ColorSwatch<ChannelColorVariant> {
// TODO fix bug where our results are unexpected (see unit tests)
ChannelColorVariant.iconOnBarBackground: clamped20to75,

ChannelColorVariant.barBackground:
LabColor.fromColor(const Color(0xff000000))
.interpolate(LabColor.fromColor(clamped20to75), 0.38)
.toColor(),
ChannelColorVariant.barBackgroundSolid: barBackgroundSolid,

ChannelColorVariant.barBackgroundGradientTop:
barBackgroundSolid.withFadedAlpha(0.625),

ChannelColorVariant.barBackgroundGradientBottom:
barBackgroundSolid.withFadedAlpha(0.125),
};
}

Expand Down Expand Up @@ -219,5 +240,7 @@ enum ChannelColorVariant {
unreadCountBadgeBackground,
iconOnPlainBackground,
iconOnBarBackground,
barBackground,
barBackgroundSolid,
barBackgroundGradientTop,
barBackgroundGradientBottom,
}
12 changes: 5 additions & 7 deletions lib/widgets/inbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -432,17 +432,15 @@ class InboxChannelHeaderItem extends StatelessWidget {
}

BoxDecoration _solidBackground(ChannelColorSwatch swatch) =>
BoxDecoration(color: swatch.barBackground);
BoxDecoration(color: swatch.barBackgroundSolid);

BoxDecoration _gradientBackground(ChannelColorSwatch swatch) => BoxDecoration(
gradient: LinearGradient(
begin: .topCenter,
end: .bottomCenter,
colors: [
// TODO(design) is this the right color?
// https://chat.zulip.org/#narrow/channel/530-mobile-design/topic/channel.20folders.20in.20inbox.3A.20design/near/2422786
swatch.barBackground,
swatch.barBackground.withValues(alpha: 0),
swatch.barBackgroundGradientTop,
swatch.barBackgroundGradientBottom,
],
),
);
Expand All @@ -464,7 +462,7 @@ class InboxChannelHeaderItem extends StatelessWidget {
child: InkWell(
splashFactory: NoSplash.splashFactory,
// TODO(design) this is ad hoc
highlightColor: swatch.barBackground.withFadedAlpha(0.5),
highlightColor: swatch.barBackgroundSolid.withFadedAlpha(0.5),
// TODO use onRowTap to handle taps that are not on the collapse button.
// Probably we should give the collapse button a 44px or 48px square
// touch target:
Expand Down Expand Up @@ -584,7 +582,7 @@ class InboxTopicItem extends StatelessWidget {
child: InkWell(
splashFactory: NoSplash.splashFactory,
// TODO(design) this is ad hoc
highlightColor: swatch.barBackground.withFadedAlpha(0.25),
highlightColor: swatch.barBackgroundSolid.withFadedAlpha(0.25),
onTap: () {
final narrow = TopicNarrow(streamId, topic);
Navigator.push(context,
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ abstract class _MessageListAppBar {
case TopicNarrow(:final channelId):
final subscription = store.subscriptions[channelId];
appBarBackgroundColor =
colorSwatchFor(context, subscription).barBackground;
colorSwatchFor(context, subscription).barBackgroundSolid;
// All recipient headers will match this color; remove distracting line
// (but are recipient headers even needed for topic narrows?)
removeAppBarBottomBorder = true;
Expand Down Expand Up @@ -1859,7 +1859,7 @@ class StreamMessageRecipientHeader extends StatelessWidget {
final topic = message.conversation.topic;

final swatch = colorSwatchFor(context, store.subscriptions[streamId]);
final backgroundColor = swatch.barBackground;
final backgroundColor = swatch.barBackgroundSolid;
final iconColor = swatch.iconOnBarBackground;

final Widget streamWidget;
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/topic_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class TopicListPage extends StatelessWidget {
final store = PerAccountStoreWidget.of(context);
final zulipLocalizations = ZulipLocalizations.of(context);
final appBarBackgroundColor = colorSwatchFor(
context, store.subscriptions[channelId]).barBackground;
context, store.subscriptions[channelId]).barBackgroundSolid;

return PageRoot(child: Scaffold(
appBar: ZulipAppBar(
Expand Down
37 changes: 31 additions & 6 deletions test/widgets/channel_colors_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ void main() {
runCheck(0xffacc25d, const Color(0xff8ea43e));
});

test('barBackground', () {
test('barBackgroundSolid', () {
void runCheck(int base, Color expected) {
check(ChannelColorSwatch.light(base))
.barBackground.isSameColorAs(expected);
.barBackgroundSolid.isSameColorAs(expected);
}

// Check against everything in ZULIP_ASSIGNMENT_COLORS
Expand Down Expand Up @@ -263,6 +263,16 @@ void main() {
runCheck(0xffa47462, const Color(0xffe7dad6));
runCheck(0xffacc25d, const Color(0xffe9edd6));
});

test('barBackgroundGradientTop', () {
check(ChannelColorSwatch.light(0xff76ce90)).barBackgroundGradientTop
.isSameColorAs(const Color(0xffddefe1));
});

test('barBackgroundGradientBottom', () {
check(ChannelColorSwatch.light(0xff76ce90)).barBackgroundGradientBottom
.isSameColorAs(const Color(0x00ddefe1));
});
});

group('dark', () {
Expand Down Expand Up @@ -418,10 +428,10 @@ void main() {
runCheck(0xffacc25d, const Color(0xffacc25d));
});

test('barBackground', () {
test('barBackgroundSolid', () {
void runCheck(int base, Color expected) {
check(ChannelColorSwatch.dark(base))
.barBackground.isSameColorAs(expected);
.barBackgroundSolid.isSameColorAs(expected);
}

// Check against everything in ZULIP_ASSIGNMENT_COLORS
Expand Down Expand Up @@ -459,6 +469,17 @@ void main() {
runCheck(0xffa47462, const Color(0xff3d2d27));
runCheck(0xffacc25d, const Color(0xff404627));
});


test('barBackgroundGradientTop', () {
check(ChannelColorSwatch.dark(0xff76ce90)).barBackgroundGradientTop
.isSameColorAs(const Color(0x9f2e4935));
});

test('barBackgroundGradientBottom', () {
check(ChannelColorSwatch.dark(0xff76ce90)).barBackgroundGradientBottom
.isSameColorAs(const Color(0x202e4935));
});
});

test('lerp (different a, b)', () {
Expand All @@ -476,8 +497,12 @@ void main() {
Color.lerp(swatchA.iconOnPlainBackground, swatchB.iconOnPlainBackground, t)!),
ChannelColorVariant.iconOnBarBackground => (check(result).iconOnBarBackground,
Color.lerp(swatchA.iconOnBarBackground, swatchB.iconOnBarBackground, t)!),
ChannelColorVariant.barBackground => (check(result).barBackground,
Color.lerp(swatchA.barBackground, swatchB.barBackground, t)!),
ChannelColorVariant.barBackgroundSolid => (check(result).barBackgroundSolid,
Color.lerp(swatchA.barBackgroundSolid, swatchB.barBackgroundSolid, t)!),
ChannelColorVariant.barBackgroundGradientTop => (check(result).barBackgroundGradientTop,
Color.lerp(swatchA.barBackgroundGradientTop, swatchB.barBackgroundGradientTop, t)!),
ChannelColorVariant.barBackgroundGradientBottom => (check(result).barBackgroundGradientBottom,
Color.lerp(swatchA.barBackgroundGradientBottom, swatchB.barBackgroundGradientBottom, t)!),
};
subject.isSameColorAs(expected);
}
Expand Down
4 changes: 3 additions & 1 deletion test/widgets/checks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ extension ChannelColorSwatchChecks on Subject<ChannelColorSwatch> {
Subject<Color> get unreadCountBadgeBackground => has((s) => s.unreadCountBadgeBackground, 'unreadCountBadgeBackground');
Subject<Color> get iconOnPlainBackground => has((s) => s.iconOnPlainBackground, 'iconOnPlainBackground');
Subject<Color> get iconOnBarBackground => has((s) => s.iconOnBarBackground, 'iconOnBarBackground');
Subject<Color> get barBackground => has((s) => s.barBackground, 'barBackground');
Subject<Color> get barBackgroundSolid => has((s) => s.barBackgroundSolid, 'barBackgroundSolid');
Subject<Color> get barBackgroundGradientTop => has((s) => s.barBackgroundGradientTop, 'barBackgroundGradientTop');
Subject<Color> get barBackgroundGradientBottom => has((s) => s.barBackgroundGradientBottom, 'barBackgroundGradientBottom');
}

extension ComposeBoxStateChecks on Subject<ComposeBoxState> {
Expand Down
2 changes: 1 addition & 1 deletion test/widgets/message_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1834,7 +1834,7 @@ void main() {
find.descendant(
of: find.byType(StreamMessageRecipientHeader),
matching: find.byType(ColoredBox),
))).color.isNotNull().isSameColorAs(swatch.barBackground);
))).color.isNotNull().isSameColorAs(swatch.barBackgroundSolid);
});

testWidgets('color of stream icon', (tester) async {
Expand Down