Skip to content

Commit 8ab75bd

Browse files
committed
api: Make displayName nullable
Signed-off-by: Zixuan James Li <[email protected]>
1 parent 64004ee commit 8ab75bd

13 files changed

+19
-39
lines changed

lib/api/model/model.dart

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -563,11 +563,7 @@ extension type const TopicName(String _value) {
563563
/// The string this topic is displayed as to the user in our UI.
564564
///
565565
/// 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;
566+
String? get displayName => _value.isEmpty ? null : _value;
571567

572568
/// The key to use for "same topic as" comparisons.
573569
String canonicalize() => apiName.toLowerCase();

lib/model/autocomplete.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -942,13 +942,11 @@ class TopicAutocompleteQuery extends AutocompleteQuery {
942942
bool testTopic(TopicName topic, PerAccountStore store) {
943943
// TODO(#881): Sort by match relevance, like web does.
944944

945-
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
946945
if (topic.displayName == null) {
947946
return store.realmEmptyTopicDisplayName.toLowerCase()
948947
.contains(raw.toLowerCase());
949948
}
950949
return topic.displayName != raw
951-
// ignore: unnecessary_non_null_assertion // null topic names soon to be enabled
952950
&& topic.displayName!.toLowerCase().contains(raw.toLowerCase());
953951
}
954952

lib/widgets/action_sheet.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,7 @@ void showTopicActionSheet(BuildContext context, {
304304

305305
// TODO: check for other cases that may disallow this action (e.g.: time
306306
// limit for editing topics).
307-
if (someMessageIdInTopic != null
308-
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
309-
&& topic.displayName != null) {
307+
if (someMessageIdInTopic != null && topic.displayName != null) {
310308
optionButtons.add(ResolveUnresolveButton(pageContext: pageContext,
311309
topic: topic,
312310
someMessageIdInTopic: someMessageIdInTopic));

lib/widgets/autocomplete.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,11 @@ class TopicAutocomplete extends AutocompleteField<TopicAutocompleteQuery, TopicA
416416
@override
417417
Widget buildItem(BuildContext context, int index, TopicAutocompleteResult option) {
418418
final Widget child;
419-
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
420419
if (option.topic.displayName == null) {
421420
final store = PerAccountStoreWidget.of(context);
422421
child = Text(store.realmEmptyTopicDisplayName,
423422
style: const TextStyle(fontStyle: FontStyle.italic));
424423
} else {
425-
// ignore: unnecessary_non_null_assertion // null topic names soon to be enabled
426424
child = Text(option.topic.displayName!);
427425
}
428426

lib/widgets/compose_box.dart

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ class ComposeTopicController extends ComposeController<TopicValidationError> {
200200
}
201201

202202
void setTopic(TopicName newTopic) {
203-
// ignore: dead_null_aware_expression // null topic names soon to be enabled
204203
value = TextEditingValue(text: newTopic.displayName ?? '');
205204
}
206205
}
@@ -635,7 +634,7 @@ class _StreamContentInputState extends State<_StreamContentInput> {
635634
}
636635

637636
/// The topic name to show in the hint text, or null to show no topic.
638-
String? _hintTopicStr() {
637+
TopicName? _hintTopic() {
639638
if (widget.controller.topic.isTopicVacuous) {
640639
if (widget.controller.topic.mandatory) {
641640
// The chosen topic can't be sent to, so don't show it.
@@ -650,7 +649,7 @@ class _StreamContentInputState extends State<_StreamContentInput> {
650649
}
651650
}
652651

653-
return widget.controller.topic.textNormalized;
652+
return TopicName(widget.controller.topic.textNormalized);
654653
}
655654

656655
@override
@@ -660,15 +659,14 @@ class _StreamContentInputState extends State<_StreamContentInput> {
660659

661660
final streamName = store.streams[widget.narrow.streamId]?.name
662661
?? zulipLocalizations.unknownChannelName;
663-
final hintTopicStr = _hintTopicStr();
664-
final hintDestination = hintTopicStr == null
662+
final hintTopic = _hintTopic();
663+
final hintDestination = hintTopic == null
665664
// No i18n of this use of "#" and ">" string; those are part of how
666665
// Zulip expresses channels and topics, not any normal English punctuation,
667666
// so don't make sense to translate. See:
668667
// https://github.com/zulip/zulip-flutter/pull/1148#discussion_r1941990585
669668
? '#$streamName'
670-
: '#$streamName > '
671-
'${hintTopicStr.isEmpty ? store.realmEmptyTopicDisplayName : hintTopicStr}';
669+
: '#$streamName > ${hintTopic.displayName ?? store.realmEmptyTopicDisplayName}';
672670

673671
return _TypingNotifier(
674672
destination: TopicNarrow(widget.narrow.streamId,
@@ -831,7 +829,6 @@ class _FixedDestinationContentInput extends StatelessWidget {
831829
// Zulip expresses channels and topics, not any normal English punctuation,
832830
// so don't make sense to translate. See:
833831
// https://github.com/zulip/zulip-flutter/pull/1148#discussion_r1941990585
834-
// ignore: dead_null_aware_expression // null topic names soon to be enabled
835832
'#$streamName > ${topic.displayName ?? store.realmEmptyTopicDisplayName}');
836833

837834
case DmNarrow(otherRecipientIds: []): // The self-1:1 thread.

lib/widgets/inbox.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,14 +546,12 @@ class _TopicItem extends StatelessWidget {
546546
style: TextStyle(
547547
fontSize: 17,
548548
height: (20 / 17),
549-
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
550549
fontStyle: topic.displayName == null ? FontStyle.italic : null,
551550
// TODO(design) check if this is the right variable
552551
color: designVariables.labelMenuButton,
553552
),
554553
maxLines: 2,
555554
overflow: TextOverflow.ellipsis,
556-
// ignore: dead_null_aware_expression // null topic names soon to be enabled
557555
topic.displayName ?? store.realmEmptyTopicDisplayName))),
558556
const SizedBox(width: 12),
559557
if (hasMention) const _IconMarker(icon: ZulipIcons.at_sign),

lib/widgets/message_list.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,8 @@ class MessageListAppBarTitle extends StatelessWidget {
341341
return Row(
342342
mainAxisSize: MainAxisSize.min,
343343
children: [
344-
// ignore: dead_null_aware_expression // null topic names soon to be enabled
345344
Flexible(child: Text(topic.displayName ?? store.realmEmptyTopicDisplayName, style: TextStyle(
346345
fontSize: 13,
347-
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
348346
fontStyle: topic.displayName == null ? FontStyle.italic : null,
349347
).merge(weightVariableTextStyle(context)))),
350348
if (icon != null)
@@ -1122,13 +1120,11 @@ class StreamMessageRecipientHeader extends StatelessWidget {
11221120
child: Row(
11231121
children: [
11241122
Flexible(
1125-
// ignore: dead_null_aware_expression // null topic names soon to be enabled
11261123
child: Text(topic.displayName ?? store.realmEmptyTopicDisplayName,
11271124
// TODO: Give a way to see the whole topic (maybe a
11281125
// long-press interaction?)
11291126
overflow: TextOverflow.ellipsis,
11301127
style: recipientHeaderTextStyle(context,
1131-
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
11321128
fontStyle: topic.displayName == null ? FontStyle.italic : null,
11331129
))),
11341130
const SizedBox(width: 4),

test/api/model/model_checks.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ extension ZulipStreamChecks on Subject<ZulipStream> {
2626

2727
extension TopicNameChecks on Subject<TopicName> {
2828
Subject<String> get apiName => has((x) => x.apiName, 'apiName');
29-
Subject<String> get displayName => has((x) => x.displayName, 'displayName');
29+
Subject<String?> get displayName => has((x) => x.displayName, 'displayName');
3030
}
3131

3232
extension StreamConversationChecks on Subject<StreamConversation> {

test/widgets/action_sheet_test.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,6 @@ void main() {
372372
final topicRow = find.descendant(
373373
of: find.byType(ZulipAppBar),
374374
matching: find.text(
375-
// ignore: dead_null_aware_expression // null topic names soon to be enabled
376375
effectiveTopic.displayName ?? eg.defaultRealmEmptyTopicDisplayName));
377376
await tester.longPress(topicRow);
378377
// sheet appears onscreen; default duration of bottom-sheet enter animation
@@ -393,7 +392,7 @@ void main() {
393392

394393
await tester.longPress(find.descendant(
395394
of: find.byType(RecipientHeader),
396-
matching: find.text(effectiveMessage.topic.displayName)));
395+
matching: find.text(effectiveMessage.topic.displayName!)));
397396
// sheet appears onscreen; default duration of bottom-sheet enter animation
398397
await tester.pump(const Duration(milliseconds: 250));
399398
}
@@ -457,7 +456,7 @@ void main() {
457456
messages: [message]);
458457
check(findButtonForLabel('Mark as resolved')).findsNothing();
459458
check(findButtonForLabel('Mark as unresolved')).findsNothing();
460-
}, skip: true); // null topic names soon to be enabled
459+
});
461460

462461
testWidgets('show from recipient header', (tester) async {
463462
await prepare();

test/widgets/autocomplete_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ void main() {
418418
await tester.tap(find.text('Topic three'));
419419
await tester.pumpAndSettle();
420420
check(tester.widget<TextField>(topicInputFinder).controller!.text)
421-
.equals(topic3.name.displayName);
421+
.equals(topic3.name.displayName!);
422422
check(find.text('Topic one' )).findsNothing();
423423
check(find.text('Topic two' )).findsNothing();
424424
check(find.text('Topic three')).findsOne(); // shown in `_TopicInput` once
@@ -477,7 +477,7 @@ void main() {
477477
await tester.pumpAndSettle();
478478

479479
check(find.text('some display name')).findsOne();
480-
}, skip: true); // null topic names soon to be enabled
480+
});
481481

482482
testWidgets('match realmEmptyTopicDisplayName in autocomplete', (tester) async {
483483
final topic = eg.getStreamTopicsEntry(name: '');
@@ -491,7 +491,7 @@ void main() {
491491
await tester.pumpAndSettle();
492492

493493
check(find.text('general chat')).findsOne();
494-
}, skip: true); // null topic names soon to be enabled
494+
});
495495

496496
testWidgets('autocomplete to realmEmptyTopicDisplayName sets topic to empty string', (tester) async {
497497
final topic = eg.getStreamTopicsEntry(name: '');
@@ -508,6 +508,6 @@ void main() {
508508
await tester.tap(find.text('general chat'));
509509
await tester.pump(Duration.zero);
510510
check(controller.value).text.equals('');
511-
}, skip: true); // null topic names soon to be enabled
511+
});
512512
});
513513
}

test/widgets/compose_box_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ void main() {
557557
narrow: TopicNarrow(channel.streamId, TopicName('')));
558558
checkComposeBoxHintTexts(tester, contentHintText:
559559
'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}');
560-
}, skip: true); // null topic names soon to be enabled
560+
});
561561
});
562562

563563
testWidgets('to DmNarrow with self', (tester) async {

test/widgets/inbox_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ void main() {
318318
unreadMessages: [eg.streamMessage(stream: channel, topic: '')],
319319
zulipFeatureLevel: 334);
320320
check(find.text(eg.defaultRealmEmptyTopicDisplayName)).findsOne();
321-
}, skip: true); // null topic names soon to be enabled
321+
});
322322

323323
group('topic visibility', () {
324324
final channel = eg.stream();

test/widgets/message_list_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ void main() {
205205
zulipFeatureLevel: 334);
206206
checkAppBarChannelTopic(
207207
channel.name, eg.defaultRealmEmptyTopicDisplayName);
208-
}, skip: true); // null topic names soon to be enabled
208+
});
209209

210210
testWidgets('has channel-feed action for topic narrows', (tester) async {
211211
final pushedRoutes = <Route<void>>[];
@@ -957,7 +957,7 @@ void main() {
957957
await tester.pump();
958958
check(findInMessageList('stream name')).single;
959959
check(findInMessageList(eg.defaultRealmEmptyTopicDisplayName)).single;
960-
}, skip: true); // null topic names soon to be enabled
960+
});
961961

962962
testWidgets('show general chat for empty topics without channel name', (tester) async {
963963
await setupMessageListPage(tester,
@@ -967,7 +967,7 @@ void main() {
967967
await tester.pump();
968968
check(findInMessageList('stream name')).isEmpty();
969969
check(findInMessageList(eg.defaultRealmEmptyTopicDisplayName)).single;
970-
}, skip: true); // null topic names soon to be enabled
970+
});
971971

972972
testWidgets('show topic visibility icon when followed', (tester) async {
973973
await setupMessageListPage(tester,

0 commit comments

Comments
 (0)