Skip to content

Commit 897788d

Browse files
committed
compose: Change topic hint text conditionally
This is implemented to match web's behavior. See CZO discussion for design details: https://chat.zulip.org/#narrow/channel/530-mobile-design/topic/general.20chat.20design.20.23F1297/near/2106736 Signed-off-by: Zixuan James Li <[email protected]>
1 parent a3a2e97 commit 897788d

12 files changed

+121
-16
lines changed

assets/l10n/app_en.arb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,13 @@
379379
"@composeBoxTopicHintText": {
380380
"description": "Hint text for topic input widget in compose box."
381381
},
382+
"composeBoxEnterTopicOrSkipHintText": "Enter a topic (skip for “{defaultTopicName}”)",
383+
"@composeBoxEnterTopicOrSkipHintText": {
384+
"description": "Hint text for topic input widget in compose box when topics are optional.",
385+
"placeholders": {
386+
"defaultTopicName": {"type": "String", "example": "general chat"}
387+
}
388+
},
382389
"composeBoxUploadingFilename": "Uploading {filename}…",
383390
"@composeBoxUploadingFilename": {
384391
"description": "Placeholder in compose box showing the specified file is currently uploading.",

lib/generated/l10n/zulip_localizations.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,12 @@ abstract class ZulipLocalizations {
609609
/// **'Topic'**
610610
String get composeBoxTopicHintText;
611611

612+
/// Hint text for topic input widget in compose box when topics are optional.
613+
///
614+
/// In en, this message translates to:
615+
/// **'Enter a topic (skip for “{defaultTopicName}”)'**
616+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName);
617+
612618
/// Placeholder in compose box showing the specified file is currently uploading.
613619
///
614620
/// In en, this message translates to:

lib/generated/l10n/zulip_localizations_ar.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Topic';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Uploading $filename…';

lib/generated/l10n/zulip_localizations_en.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Topic';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Uploading $filename…';

lib/generated/l10n/zulip_localizations_ja.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Topic';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Uploading $filename…';

lib/generated/l10n/zulip_localizations_nb.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Topic';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Uploading $filename…';

lib/generated/l10n/zulip_localizations_pl.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Wątek';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Przekazywanie $filename…';

lib/generated/l10n/zulip_localizations_ru.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Тема';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Загрузка $filename…';

lib/generated/l10n/zulip_localizations_sk.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
298298
@override
299299
String get composeBoxTopicHintText => 'Topic';
300300

301+
@override
302+
String composeBoxEnterTopicOrSkipHintText(String defaultTopicName) {
303+
return 'Enter a topic (skip for “$defaultTopicName”)';
304+
}
305+
301306
@override
302307
String composeBoxUploadingFilename(String filename) {
303308
return 'Uploading $filename…';

lib/widgets/compose_box.dart

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ class _TopicInputState extends State<_TopicInput> {
686686
void initState() {
687687
super.initState();
688688
widget.controller.topicFocusNode.addListener(_topicFocusChanged);
689+
widget.controller.hasChosenTopic.addListener(_hasChosenTopicChanged);
689690
}
690691

691692
@override
@@ -695,11 +696,16 @@ class _TopicInputState extends State<_TopicInput> {
695696
oldWidget.controller.topicFocusNode.removeListener(_topicFocusChanged);
696697
widget.controller.topicFocusNode.addListener(_topicFocusChanged);
697698
}
699+
if (widget.controller.hasChosenTopic != oldWidget.controller.hasChosenTopic) {
700+
oldWidget.controller.hasChosenTopic.removeListener(_hasChosenTopicChanged);
701+
widget.controller.hasChosenTopic.addListener(_hasChosenTopicChanged);
702+
}
698703
}
699704

700705
@override
701706
void dispose() {
702707
widget.controller.topicFocusNode.removeListener(_topicFocusChanged);
708+
widget.controller.hasChosenTopic.removeListener(_hasChosenTopicChanged);
703709
super.dispose();
704710
}
705711

@@ -712,16 +718,56 @@ class _TopicInputState extends State<_TopicInput> {
712718
}
713719
}
714720

721+
void _hasChosenTopicChanged() {
722+
setState(() {
723+
// The relevant state lives on widget.controller.hasChosenTopic itself.
724+
});
725+
}
726+
727+
/// Return the default topic display name to use, or `null` if topics are
728+
/// required.
729+
String? _defaultTopicDisplayName() {
730+
final store = PerAccountStoreWidget.of(context);
731+
if (store.realmMandatoryTopics) {
732+
return null;
733+
}
734+
735+
// TODO(server-10) simplify
736+
return store.zulipFeatureLevel >= 334
737+
? store.realmEmptyTopicDisplayName : kNoTopicTopic;
738+
}
739+
715740
@override
716741
Widget build(BuildContext context) {
717742
final zulipLocalizations = ZulipLocalizations.of(context);
718743
final designVariables = DesignVariables.of(context);
744+
final store = PerAccountStoreWidget.of(context);
719745
TextStyle topicTextStyle = TextStyle(
720746
fontSize: 20,
721747
height: 22 / 20,
722748
color: designVariables.textInput.withFadedAlpha(0.9),
723749
).merge(weightVariableTextStyle(context, wght: 600));
724750

751+
String hintText = zulipLocalizations.composeBoxTopicHintText;
752+
TextStyle hintStyle = topicTextStyle.copyWith(
753+
color: designVariables.textInput.withFadedAlpha(0.5));
754+
final defaultTopicDisplayName = _defaultTopicDisplayName();
755+
if (defaultTopicDisplayName != null) {
756+
if (widget.controller.topicFocusNode.hasFocus) {
757+
// The user is actively interacting with the input.
758+
// Show a long and engaging hint text.
759+
hintText = zulipLocalizations.composeBoxEnterTopicOrSkipHintText(
760+
defaultTopicDisplayName);
761+
} else if (widget.controller.hasChosenTopic.value) {
762+
// The topic has been chosen. Show the default topic display name in
763+
// the input as if the user has entered that when they left it empty.
764+
hintText = defaultTopicDisplayName;
765+
hintStyle = topicTextStyle.copyWith(
766+
// TODO(server-10) simplify
767+
fontStyle: store.zulipFeatureLevel >= 334 ? FontStyle.italic : null);
768+
}
769+
}
770+
725771
return TopicAutocomplete(
726772
streamId: widget.streamId,
727773
controller: widget.controller.topic,
@@ -738,9 +784,8 @@ class _TopicInputState extends State<_TopicInput> {
738784
textInputAction: TextInputAction.next,
739785
style: topicTextStyle,
740786
decoration: InputDecoration(
741-
hintText: zulipLocalizations.composeBoxTopicHintText,
742-
hintStyle: topicTextStyle.copyWith(
743-
color: designVariables.textInput.withFadedAlpha(0.5))))));
787+
hintText: hintText,
788+
hintStyle: hintStyle))));
744789
}
745790
}
746791

0 commit comments

Comments
 (0)