@@ -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