@@ -550,6 +550,15 @@ String? tryParseEmojiCodeToUnicode(String emojiCode) {
550550 }
551551}
552552
553+ /// The topic servers understand to mean "there is no topic".
554+ ///
555+ /// This should match
556+ /// https://github.com/zulip/zulip/blob/6.0/zerver/actions/message_edit.py#L940
557+ /// or similar logic at the latest `main` .
558+ // This is hardcoded in the server, and therefore untranslated; that's
559+ // zulip/zulip#3639.
560+ const String kNoTopicTopic = '(no topic)' ;
561+
553562/// The name of a Zulip topic.
554563// TODO(dart): Can we forbid calling Object members on this extension type?
555564// (The lack of "implements Object" ought to do that, but doesn't.)
@@ -604,6 +613,51 @@ extension type const TopicName(String _value) {
604613 /// using [canonicalize] .
605614 bool isSameAs (TopicName other) => canonicalize () == other.canonicalize ();
606615
616+ /// Process this topic to match how it would appear on a message object from
617+ /// the server.
618+ ///
619+ /// This assumes that the topic is constructed from a string without
620+ /// leading/trailing whitespace.
621+ ///
622+ /// For a client that does not support empty topics, when FL>=334, the server
623+ /// converts empty topics to `store.realmEmptyTopicDisplayName` ; when FL>=370,
624+ /// the server converts "(no topic)" to `store.realmEmptyTopicDisplayName`
625+ /// as well.
626+ ///
627+ /// See API docs:
628+ /// https://zulip.com/api/send-message#parameter-topic
629+ TopicName processLikeServer ({
630+ required int zulipFeatureLevel,
631+ required String ? realmEmptyTopicDisplayName,
632+ }) {
633+ assert (_value.trim () == _value);
634+ // TODO(server-10) simplify this away
635+ if (zulipFeatureLevel < 334 ) {
636+ // From the API docs:
637+ // > Before Zulip 10.0 (feature level 334), empty string was not a valid
638+ // > topic name for channel messages.
639+ assert (_value.isNotEmpty);
640+ return this ;
641+ }
642+
643+ // TODO(server-10) simplify this away
644+ if (zulipFeatureLevel < 370 && _value == kNoTopicTopic) {
645+ // From the API docs:
646+ // > Before Zulip 10.0 (feature level 370), "(no topic)" was not
647+ // > interpreted as an empty string.
648+ return TopicName (kNoTopicTopic);
649+ }
650+
651+ // TODO(#1250): This assumes that the 'empty_topic_name' client capability
652+ // is not declared. When we set 'empty_topic_name' to true,
653+ // make this return an empty topic if the value matches "(no topic)"
654+ // or realmEmptyTopicDisplayName.
655+ if (_value == kNoTopicTopic || _value.isEmpty) {
656+ return TopicName (realmEmptyTopicDisplayName! );
657+ }
658+ return TopicName (_value);
659+ }
660+
607661 TopicName .fromJson (this ._value);
608662
609663 String toJson () => apiName;
0 commit comments