@@ -532,6 +532,65 @@ String? tryParseEmojiCodeToUnicode(String emojiCode) {
532
532
}
533
533
}
534
534
535
+ /// The name of a Zulip topic.
536
+ // TODO(dart): Can we forbid calling Object members on this extension type?
537
+ // (The lack of "implements Object" ought to do that, but doesn't.)
538
+ // In particular an interpolation "foo > $topic" is a bug we'd like to catch.
539
+ // TODO(dart): Can we forbid using this extension type as a key in a Map?
540
+ // (The lack of "implements Object" arguably should do that, but doesn't.)
541
+ // Using as a Map key is almost certainly a bug because it won't case-fold;
542
+ // see for example #739, #980, #1205.
543
+ extension type const TopicName (String _value) {
544
+ /// The canonical form of the resolved-topic prefix.
545
+ // This is RESOLVED_TOPIC_PREFIX in web:
546
+ // https://github.com/zulip/zulip/blob/1fac99733/web/shared/src/resolved_topic.ts
547
+ static const resolvedTopicPrefix = '✔ ' ;
548
+
549
+ /// Pattern for an arbitrary resolved-topic prefix.
550
+ ///
551
+ /// These always begin with [resolvedTopicPrefix]
552
+ /// but can be weird and go on longer, like "✔ ✔✔ ".
553
+ // This is RESOLVED_TOPIC_PREFIX_RE in web:
554
+ // https://github.com/zulip/zulip/blob/1fac99733/web/shared/src/resolved_topic.ts#L4-L12
555
+ static final resolvedTopicPrefixRegexp = RegExp (r'^✔ [ ✔]*' );
556
+
557
+ /// The string this topic is identified by in the Zulip API.
558
+ ///
559
+ /// This should be used in constructing HTTP requests to the server,
560
+ /// but rarely for other purposes. See [displayName] and [canonicalize] .
561
+ String get apiName => _value;
562
+
563
+ /// The string this topic is displayed as to the user in our UI.
564
+ ///
565
+ /// At the moment this always equals [apiName] .
566
+ /// In the future this will become null for the "general chat" topic (#1250),
567
+ /// so that UI code can identify when it needs to represent the topic
568
+ /// specially in the way prescribed for "general chat".
569
+ // TODO(#1250) carry out that plan
570
+ String get displayName => _value;
571
+
572
+ /// The key to use for "same topic as" comparisons.
573
+ String canonicalize () => apiName.toLowerCase ();
574
+
575
+ /// Whether the topic starts with [resolvedTopicPrefix] .
576
+ bool get isResolved => _value.startsWith (resolvedTopicPrefix);
577
+
578
+ /// This [TopicName] plus the [resolvedTopicPrefix] prefix.
579
+ TopicName resolve () => TopicName (resolvedTopicPrefix + _value);
580
+
581
+ /// A [TopicName] with [resolvedTopicPrefixRegexp] stripped if present.
582
+ TopicName unresolve () =>
583
+ TopicName (_value.replaceFirst (resolvedTopicPrefixRegexp, '' ));
584
+
585
+ /// Whether [this] and [other] have the same canonical form,
586
+ /// using [canonicalize] .
587
+ bool isSameAs (TopicName other) => canonicalize () == other.canonicalize ();
588
+
589
+ TopicName .fromJson (this ._value);
590
+
591
+ String toJson () => apiName;
592
+ }
593
+
535
594
/// As in [StreamMessage.conversation] and [DmMessage.conversation] .
536
595
///
537
596
/// Different from [MessageDestination] , this information comes from
@@ -702,65 +761,6 @@ enum MessageFlag {
702
761
String toJson () => _$MessageFlagEnumMap [this ]! ;
703
762
}
704
763
705
- /// The name of a Zulip topic.
706
- // TODO(dart): Can we forbid calling Object members on this extension type?
707
- // (The lack of "implements Object" ought to do that, but doesn't.)
708
- // In particular an interpolation "foo > $topic" is a bug we'd like to catch.
709
- // TODO(dart): Can we forbid using this extension type as a key in a Map?
710
- // (The lack of "implements Object" arguably should do that, but doesn't.)
711
- // Using as a Map key is almost certainly a bug because it won't case-fold;
712
- // see for example #739, #980, #1205.
713
- extension type const TopicName (String _value) {
714
- /// The canonical form of the resolved-topic prefix.
715
- // This is RESOLVED_TOPIC_PREFIX in web:
716
- // https://github.com/zulip/zulip/blob/1fac99733/web/shared/src/resolved_topic.ts
717
- static const resolvedTopicPrefix = '✔ ' ;
718
-
719
- /// Pattern for an arbitrary resolved-topic prefix.
720
- ///
721
- /// These always begin with [resolvedTopicPrefix]
722
- /// but can be weird and go on longer, like "✔ ✔✔ ".
723
- // This is RESOLVED_TOPIC_PREFIX_RE in web:
724
- // https://github.com/zulip/zulip/blob/1fac99733/web/shared/src/resolved_topic.ts#L4-L12
725
- static final resolvedTopicPrefixRegexp = RegExp (r'^✔ [ ✔]*' );
726
-
727
- /// The string this topic is identified by in the Zulip API.
728
- ///
729
- /// This should be used in constructing HTTP requests to the server,
730
- /// but rarely for other purposes. See [displayName] and [canonicalize] .
731
- String get apiName => _value;
732
-
733
- /// The string this topic is displayed as to the user in our UI.
734
- ///
735
- /// At the moment this always equals [apiName] .
736
- /// In the future this will become null for the "general chat" topic (#1250),
737
- /// so that UI code can identify when it needs to represent the topic
738
- /// specially in the way prescribed for "general chat".
739
- // TODO(#1250) carry out that plan
740
- String get displayName => _value;
741
-
742
- /// The key to use for "same topic as" comparisons.
743
- String canonicalize () => apiName.toLowerCase ();
744
-
745
- /// Whether the topic starts with [resolvedTopicPrefix] .
746
- bool get isResolved => _value.startsWith (resolvedTopicPrefix);
747
-
748
- /// This [TopicName] plus the [resolvedTopicPrefix] prefix.
749
- TopicName resolve () => TopicName (resolvedTopicPrefix + _value);
750
-
751
- /// A [TopicName] with [resolvedTopicPrefixRegexp] stripped if present.
752
- TopicName unresolve () =>
753
- TopicName (_value.replaceFirst (resolvedTopicPrefixRegexp, '' ));
754
-
755
- /// Whether [this] and [other] have the same canonical form,
756
- /// using [canonicalize] .
757
- bool isSameAs (TopicName other) => canonicalize () == other.canonicalize ();
758
-
759
- TopicName .fromJson (this ._value);
760
-
761
- String toJson () => apiName;
762
- }
763
-
764
764
@JsonSerializable (fieldRename: FieldRename .snake)
765
765
class StreamMessage extends Message {
766
766
@override
0 commit comments