Skip to content

Commit 058312d

Browse files
committed
compose_box: Implement topic input redesign
The bottom underline implementation draws similarity to that of `Spoiler`'s. We could have used `UnderlineInputBorder` on `InputDecoration`, but that also comes with other input state styles that we do not need (e.g.: focused, disabled, etc.). This also adds a new helper on `ColorExtension` following a similar naming and documentation style as other method like `withValues`. The motivation for this is to support a faded effect applies to colors that are possibly already transparent (i.e. have a non-one alpha channel value). Note that we use `withFadedAlpha` on `designVariables.textInput` because the color is already transparent in dark mode, and the helper allows us to multiply, instead of to override, the alpha channel of the color with a factor. See also: - https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3954-13395 - https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3862-14350 - zulip#928 (comment) Signed-off-by: Zixuan James Li <[email protected]>
1 parent fd8025a commit 058312d

File tree

4 files changed

+56
-8
lines changed

4 files changed

+56
-8
lines changed

lib/widgets/color.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,13 @@ extension ColorExtension on Color {
3838
((g * 255.0).round() & 0xff) << 8 |
3939
((b * 255.0).round() & 0xff) << 0;
4040
}
41+
42+
/// Makes a copy of this color with the alpha channel multiplied by `factor`.
43+
///
44+
/// `factor` must not be less than 0 or greater than 1.
45+
Color withFadedAlpha(double factor) {
46+
assert(factor >= 0);
47+
assert(factor <= 1);
48+
return withValues(alpha: a * factor);
49+
}
4150
}

lib/widgets/compose_box.dart

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import '../model/compose.dart';
1414
import '../model/narrow.dart';
1515
import '../model/store.dart';
1616
import 'autocomplete.dart';
17+
import 'color.dart';
1718
import 'dialog.dart';
1819
import 'icons.dart';
1920
import 'store.dart';
21+
import 'text.dart';
2022
import 'theme.dart';
2123

2224
const double _composeButtonWidth = 44;
@@ -472,20 +474,39 @@ class _TopicInput extends StatelessWidget {
472474
@override
473475
Widget build(BuildContext context) {
474476
final zulipLocalizations = ZulipLocalizations.of(context);
475-
ColorScheme colorScheme = Theme.of(context).colorScheme;
477+
final designVariables = DesignVariables.of(context);
478+
TextStyle topicTextStyle = TextStyle(
479+
fontSize: 20,
480+
height: 22 / 20,
481+
color: designVariables.textInput.withFadedAlpha(0.9),
482+
).merge(weightVariableTextStyle(context, wght: 600));
476483

477484
return TopicAutocomplete(
478485
streamId: streamId,
479486
controller: controller,
480487
focusNode: focusNode,
481488
contentFocusNode: contentFocusNode,
482-
fieldViewBuilder: (context) => TextField(
483-
controller: controller,
484-
focusNode: focusNode,
485-
textInputAction: TextInputAction.next,
486-
style: TextStyle(color: colorScheme.onSurface),
487-
decoration: InputDecoration(hintText: zulipLocalizations.composeBoxTopicHintText),
488-
));
489+
fieldViewBuilder: (context) => Column(
490+
mainAxisSize: MainAxisSize.min,
491+
children: [
492+
Padding(
493+
padding: const EdgeInsets.symmetric(vertical: 10),
494+
child: TextField(
495+
controller: controller,
496+
focusNode: focusNode,
497+
textInputAction: TextInputAction.next,
498+
style: topicTextStyle,
499+
decoration: InputDecoration(
500+
hintText: zulipLocalizations.composeBoxTopicHintText,
501+
hintStyle: topicTextStyle.copyWith(
502+
color: designVariables.textInput.withFadedAlpha(0.5))))),
503+
SizedBox(height: 0, width: double.infinity,
504+
child: DecoratedBox(decoration: BoxDecoration(
505+
border: Border(
506+
bottom: BorderSide(
507+
width: 1,
508+
color: designVariables.foreground.withFadedAlpha(0.2)))))),
509+
]));
489510
}
490511
}
491512

lib/widgets/theme.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
129129
labelEdited: const HSLColor.fromAHSL(0.35, 0, 0, 0).toColor(),
130130
labelMenuButton: const Color(0xff222222),
131131
mainBackground: const Color(0xfff0f0f0),
132+
textInput: const Color(0xff000000),
132133
title: const Color(0xff1a1a1a),
133134
channelColorSwatches: ChannelColorSwatches.light,
134135
atMentionMarker: const HSLColor.fromAHSL(0.5, 0, 0, 0.2).toColor(),
@@ -168,6 +169,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
168169
labelEdited: const HSLColor.fromAHSL(0.35, 0, 0, 1).toColor(),
169170
labelMenuButton: const Color(0xffffffff).withValues(alpha: 0.85),
170171
mainBackground: const Color(0xff1d1d1d),
172+
textInput: const Color(0xffffffff).withValues(alpha: 0.9),
171173
title: const Color(0xffffffff),
172174
channelColorSwatches: ChannelColorSwatches.dark,
173175
contextMenuCancelBg: const Color(0xff797986), // the same as the light mode in Figma
@@ -214,6 +216,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
214216
required this.labelEdited,
215217
required this.labelMenuButton,
216218
required this.mainBackground,
219+
required this.textInput,
217220
required this.title,
218221
required this.channelColorSwatches,
219222
required this.atMentionMarker,
@@ -261,6 +264,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
261264
final Color labelEdited;
262265
final Color labelMenuButton;
263266
final Color mainBackground;
267+
final Color textInput;
264268
final Color title;
265269

266270
// Not exactly from the Figma design, but from Vlad anyway.
@@ -303,6 +307,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
303307
Color? labelEdited,
304308
Color? labelMenuButton,
305309
Color? mainBackground,
310+
Color? textInput,
306311
Color? title,
307312
ChannelColorSwatches? channelColorSwatches,
308313
Color? atMentionMarker,
@@ -340,6 +345,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
340345
labelEdited: labelEdited ?? this.labelEdited,
341346
labelMenuButton: labelMenuButton ?? this.labelMenuButton,
342347
mainBackground: mainBackground ?? this.mainBackground,
348+
textInput: textInput ?? this.textInput,
343349
title: title ?? this.title,
344350
channelColorSwatches: channelColorSwatches ?? this.channelColorSwatches,
345351
atMentionMarker: atMentionMarker ?? this.atMentionMarker,
@@ -384,6 +390,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
384390
labelEdited: Color.lerp(labelEdited, other.labelEdited, t)!,
385391
labelMenuButton: Color.lerp(labelMenuButton, other.labelMenuButton, t)!,
386392
mainBackground: Color.lerp(mainBackground, other.mainBackground, t)!,
393+
textInput: Color.lerp(textInput, other.textInput, t)!,
387394
title: Color.lerp(title, other.title, t)!,
388395
channelColorSwatches: ChannelColorSwatches.lerp(channelColorSwatches, other.channelColorSwatches, t),
389396
atMentionMarker: Color.lerp(atMentionMarker, other.atMentionMarker, t)!,

test/widgets/color_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:ui';
22

33
import 'package:checks/checks.dart';
4+
import 'package:flutter_checks/flutter_checks.dart';
45
import 'package:test/scaffolding.dart';
56
import 'package:zulip/widgets/color.dart';
67

@@ -14,5 +15,15 @@ void main() {
1415
check(Color(testCase).argbInt).equals(testCase);
1516
}
1617
});
18+
19+
test('withFadedAlpha smoke', () {
20+
const color = Color.fromRGBO(100, 200, 100, 0.5);
21+
22+
check(color.withFadedAlpha(0.5))
23+
.isSameColorAs(color.withValues(alpha: 0.25));
24+
25+
check(() => color.withFadedAlpha(1.1)).throws<AssertionError>();
26+
check(() => color.withFadedAlpha(-0.1)).throws<AssertionError>();
27+
});
1728
});
1829
}

0 commit comments

Comments
 (0)