Skip to content

Commit cf3ef49

Browse files
committed
emoji_reaction: Add EmojiReactionTheme, including dark variant
Related: #95
1 parent fa3f012 commit cf3ef49

File tree

2 files changed

+111
-24
lines changed

2 files changed

+111
-24
lines changed

lib/widgets/emoji_reaction.dart

Lines changed: 105 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,104 @@ import 'content.dart';
88
import 'store.dart';
99
import 'text.dart';
1010

11+
/// Emoji-reaction styles that differ between light and dark themes.
12+
class EmojiReactionTheme extends ThemeExtension<EmojiReactionTheme> {
13+
factory EmojiReactionTheme.light() {
14+
return EmojiReactionTheme._(
15+
bgSelected: Colors.white,
16+
17+
// TODO shadow effect, following web, which uses `box-shadow: inset`:
18+
// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow#inset
19+
// Needs Flutter support for something like that:
20+
// https://github.com/flutter/flutter/issues/18636
21+
// https://github.com/flutter/flutter/issues/52999
22+
// Until then use a solid color; a much-lightened version of the shadow color.
23+
// Also adapt by making [borderUnselected] more transparent, so we'll
24+
// want to check that against web when implementing the shadow.
25+
bgUnselected: const HSLColor.fromAHSL(0.08, 210, 0.50, 0.875).toColor(),
26+
27+
borderSelected: Colors.black.withOpacity(0.45),
28+
29+
// TODO see TODO on [bgUnselected] about shadow effect
30+
borderUnselected: Colors.black.withOpacity(0.05),
31+
32+
textSelected: const HSLColor.fromAHSL(1, 210, 0.20, 0.20).toColor(),
33+
textUnselected: const HSLColor.fromAHSL(1, 210, 0.20, 0.25).toColor(),
34+
);
35+
}
36+
37+
factory EmojiReactionTheme.dark() {
38+
return EmojiReactionTheme._(
39+
bgSelected: Colors.black.withOpacity(0.8),
40+
bgUnselected: Colors.black.withOpacity(0.3),
41+
borderSelected: Colors.white.withOpacity(0.75),
42+
borderUnselected: Colors.white.withOpacity(0.15),
43+
textSelected: Colors.white.withOpacity(0.85),
44+
textUnselected: Colors.white.withOpacity(0.75),
45+
);
46+
}
47+
48+
EmojiReactionTheme._({
49+
required this.bgSelected,
50+
required this.bgUnselected,
51+
required this.borderSelected,
52+
required this.borderUnselected,
53+
required this.textSelected,
54+
required this.textUnselected,
55+
});
56+
57+
/// The [EmojiReactionTheme] from the context's active theme.
58+
///
59+
/// The [ThemeData] must include [EmojiReactionTheme] in [ThemeData.extensions].
60+
static EmojiReactionTheme of(BuildContext context) {
61+
final theme = Theme.of(context);
62+
final extension = theme.extension<EmojiReactionTheme>();
63+
assert(extension != null);
64+
return extension!;
65+
}
66+
67+
final Color bgSelected;
68+
final Color bgUnselected;
69+
final Color borderSelected;
70+
final Color borderUnselected;
71+
final Color textSelected;
72+
final Color textUnselected;
73+
74+
@override
75+
EmojiReactionTheme copyWith({
76+
Color? bgSelected,
77+
Color? bgUnselected,
78+
Color? borderSelected,
79+
Color? borderUnselected,
80+
Color? textSelected,
81+
Color? textUnselected,
82+
}) {
83+
return EmojiReactionTheme._(
84+
bgSelected: bgSelected ?? this.bgSelected,
85+
bgUnselected: bgUnselected ?? this.bgUnselected,
86+
borderSelected: borderSelected ?? this.borderSelected,
87+
borderUnselected: borderUnselected ?? this.borderUnselected,
88+
textSelected: textSelected ?? this.textSelected,
89+
textUnselected: textUnselected ?? this.textUnselected,
90+
);
91+
}
92+
93+
@override
94+
EmojiReactionTheme lerp(EmojiReactionTheme other, double t) {
95+
if (identical(this, other)) {
96+
return this;
97+
}
98+
return EmojiReactionTheme._(
99+
bgSelected: Color.lerp(bgSelected, other.bgSelected, t)!,
100+
bgUnselected: Color.lerp(bgUnselected, other.bgUnselected, t)!,
101+
borderSelected: Color.lerp(borderSelected, other.borderSelected, t)!,
102+
borderUnselected: Color.lerp(borderUnselected, other.borderUnselected, t)!,
103+
textSelected: Color.lerp(textSelected, other.textSelected, t)!,
104+
textUnselected: Color.lerp(textUnselected, other.textUnselected, t)!,
105+
);
106+
}
107+
}
108+
11109
class ReactionChipsList extends StatelessWidget {
12110
const ReactionChipsList({
13111
super.key,
@@ -32,24 +130,6 @@ class ReactionChipsList extends StatelessWidget {
32130
}
33131
}
34132

35-
final _textColorSelected = const HSLColor.fromAHSL(1, 210, 0.20, 0.20).toColor();
36-
final _textColorUnselected = const HSLColor.fromAHSL(1, 210, 0.20, 0.25).toColor();
37-
38-
const _backgroundColorSelected = Colors.white;
39-
// TODO shadow effect, following web, which uses `box-shadow: inset`:
40-
// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow#inset
41-
// Needs Flutter support for something like that:
42-
// https://github.com/flutter/flutter/issues/18636
43-
// https://github.com/flutter/flutter/issues/52999
44-
// Until then use a solid color; a much-lightened version of the shadow color.
45-
// Also adapt by making [_borderColorUnselected] more transparent, so we'll
46-
// want to check that against web when implementing the shadow.
47-
final _backgroundColorUnselected = const HSLColor.fromAHSL(0.08, 210, 0.50, 0.875).toColor();
48-
49-
final _borderColorSelected = Colors.black.withOpacity(0.45);
50-
// TODO see TODO on [_backgroundColorUnselected] about shadow effect
51-
final _borderColorUnselected = Colors.black.withOpacity(0.05);
52-
53133
class ReactionChip extends StatelessWidget {
54134
final bool showName;
55135
final int messageId;
@@ -85,10 +165,11 @@ class ReactionChip extends StatelessWidget {
85165
}).join(', ')
86166
: userIds.length.toString();
87167

88-
final borderColor = selfVoted ? _borderColorSelected : _borderColorUnselected;
89-
final labelColor = selfVoted ? _textColorSelected : _textColorUnselected;
90-
final backgroundColor = selfVoted ? _backgroundColorSelected : _backgroundColorUnselected;
91-
final splashColor = selfVoted ? _backgroundColorUnselected : _backgroundColorSelected;
168+
final reactionTheme = EmojiReactionTheme.of(context);
169+
final borderColor = selfVoted ? reactionTheme.borderSelected : reactionTheme.borderUnselected;
170+
final labelColor = selfVoted ? reactionTheme.textSelected : reactionTheme.textUnselected;
171+
final backgroundColor = selfVoted ? reactionTheme.bgSelected : reactionTheme.bgUnselected;
172+
final splashColor = selfVoted ? reactionTheme.bgUnselected : reactionTheme.bgSelected;
92173
final highlightColor = splashColor.withOpacity(0.5);
93174

94175
final borderSide = BorderSide(
@@ -349,14 +430,15 @@ class _TextEmoji extends StatelessWidget {
349430

350431
@override
351432
Widget build(BuildContext context) {
433+
final reactionTheme = EmojiReactionTheme.of(context);
352434
return Text(
353435
textAlign: TextAlign.end,
354436
textScaler: _textEmojiScalerClamped(context),
355437
textWidthBasis: TextWidthBasis.longestLine,
356438
style: TextStyle(
357439
fontSize: 14 * 0.8,
358440
height: 1, // to be denser when we have to wrap
359-
color: selected ? _textColorSelected : _textColorUnselected,
441+
color: selected ? reactionTheme.textSelected : reactionTheme.textUnselected,
360442
).merge(weightVariableTextStyle(context,
361443
wght: selected ? 600 : null)),
362444
// Encourage line breaks before "_" (common in these), but try not

lib/widgets/theme.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ import 'package:flutter/material.dart';
22

33
import '../api/model/model.dart';
44
import 'content.dart';
5+
import 'emoji_reaction.dart';
56
import 'stream_colors.dart';
67
import 'text.dart';
78

89
ThemeData zulipThemeData(BuildContext context) {
910
final designVariables = DesignVariables();
1011
return ThemeData(
1112
typography: zulipTypography(context),
12-
extensions: [ContentTheme.light(context), designVariables],
13+
extensions: [
14+
ContentTheme.light(context),
15+
designVariables,
16+
EmojiReactionTheme.light(),
17+
],
1318
appBarTheme: AppBarTheme(
1419
// Set these two fields to prevent a color change in [AppBar]s when
1520
// there is something scrolled under it. If an app bar hasn't been

0 commit comments

Comments
 (0)