From 0fe861fdf4043e9649baedd28e23159c42761a59 Mon Sep 17 00:00:00 2001 From: Zixuan James Li Date: Tue, 21 Jan 2025 11:28:24 -0500 Subject: [PATCH] wip; api: Make displayName nullable Signed-off-by: Zixuan James Li --- lib/api/model/model.dart | 2 +- lib/model/autocomplete.dart | 2 -- lib/widgets/autocomplete.dart | 2 -- lib/widgets/compose_box.dart | 4 ---- lib/widgets/inbox.dart | 2 -- lib/widgets/message_list.dart | 4 ---- test/api/model/model_checks.dart | 2 +- test/widgets/autocomplete_test.dart | 8 ++++---- test/widgets/compose_box_test.dart | 10 +++++----- test/widgets/inbox_test.dart | 2 +- test/widgets/message_list_test.dart | 4 ++-- 11 files changed, 14 insertions(+), 28 deletions(-) diff --git a/lib/api/model/model.dart b/lib/api/model/model.dart index 03af104baf2..63b2bd2e706 100644 --- a/lib/api/model/model.dart +++ b/lib/api/model/model.dart @@ -690,7 +690,7 @@ extension type const TopicName(String _value) { /// so that UI code can identify when it needs to represent the topic /// specially in the way prescribed for "general chat". // TODO(#1250) carry out that plan - String get displayName => _value; + String? get displayName => _value.isEmpty ? null : _value; /// The key to use for "same topic as" comparisons. String canonicalize() => apiName.toLowerCase(); diff --git a/lib/model/autocomplete.dart b/lib/model/autocomplete.dart index 45614360b28..dc7fcd44103 100644 --- a/lib/model/autocomplete.dart +++ b/lib/model/autocomplete.dart @@ -865,13 +865,11 @@ class TopicAutocompleteQuery extends AutocompleteQuery { bool testTopic(PerAccountStore store, TopicName topic) { // TODO(#881): Sort by match relevance, like web does. - // ignore: unnecessary_null_comparison // null topic names soon to be enabled if (topic.displayName == null) { return store.realmEmptyTopicDisplayName.toLowerCase() .contains(raw.toLowerCase()); } return topic.displayName != raw - // ignore: unnecessary_non_null_assertion // null topic names soon to be enabled && topic.displayName!.toLowerCase().contains(raw.toLowerCase()); } diff --git a/lib/widgets/autocomplete.dart b/lib/widgets/autocomplete.dart index 8e25712aac8..2c87d7f64a2 100644 --- a/lib/widgets/autocomplete.dart +++ b/lib/widgets/autocomplete.dart @@ -329,13 +329,11 @@ class TopicAutocomplete extends AutocompleteField { } void setTopic(TopicName newTopic) { - // ignore: dead_null_aware_expression // null topic names soon to be enabled value = TextEditingValue(text: newTopic.displayName ?? ''); } } @@ -440,7 +439,6 @@ class _ContentInputState extends State<_ContentInput> with WidgetsBindingObserve color: designVariables.textInput.withFadedAlpha(0.5)); if (widget.destination.destination - // ignore: constant_pattern_never_matches_value_type // null topic names soon to be enabled case StreamDestination(topic: TopicName(displayName: null))) { // TODO: This applies to the entire hint text; ideally we'd only want to // italize the "general chat" text, but [TextField] doesn't seem to have @@ -546,7 +544,6 @@ class _StreamContentInputState extends State<_StreamContentInput> { destination: TopicNarrow(widget.narrow.streamId, topic), controller: widget.controller, hintText: zulipLocalizations.composeBoxChannelContentHint( - // ignore: dead_null_aware_expression // null topic names soon to be enabled streamName, topic.displayName ?? store.realmEmptyTopicDisplayName)); } } @@ -612,7 +609,6 @@ class _FixedDestinationContentInput extends StatelessWidget { final streamName = store.streams[streamId]?.name ?? zulipLocalizations.composeBoxUnknownChannelName; return zulipLocalizations.composeBoxChannelContentHint( - // ignore: dead_null_aware_expression // null topic names soon to be enabled streamName, topic.displayName ?? store.realmEmptyTopicDisplayName); case DmNarrow(otherRecipientIds: []): // The self-1:1 thread. diff --git a/lib/widgets/inbox.dart b/lib/widgets/inbox.dart index cfb46cce519..108bb040950 100644 --- a/lib/widgets/inbox.dart +++ b/lib/widgets/inbox.dart @@ -526,7 +526,6 @@ class _TopicItem extends StatelessWidget { child: Text( style: TextStyle( fontSize: 17, - // ignore: unnecessary_null_comparison // null topic names soon to be enabled fontStyle: (topic.displayName == null) ? null : FontStyle.italic, height: (20 / 17), // TODO(design) check if this is the right variable @@ -534,7 +533,6 @@ class _TopicItem extends StatelessWidget { ), maxLines: 2, overflow: TextOverflow.ellipsis, - // ignore: dead_null_aware_expression // null topic names soon to be enabled topic.displayName ?? store.realmEmptyTopicDisplayName))), const SizedBox(width: 12), if (hasMention) const _IconMarker(icon: ZulipIcons.at_sign), diff --git a/lib/widgets/message_list.dart b/lib/widgets/message_list.dart index 4a0e8985313..70cb52c3c2d 100644 --- a/lib/widgets/message_list.dart +++ b/lib/widgets/message_list.dart @@ -362,10 +362,8 @@ class MessageListAppBarTitle extends StatelessWidget { return Row( mainAxisSize: MainAxisSize.min, children: [ - // ignore: dead_null_aware_expression // null topic names soon to be enabled Flexible(child: Text(topic.displayName ?? store.realmEmptyTopicDisplayName, style: TextStyle( fontSize: 13, - // ignore: unnecessary_null_comparison // null topic names soon to be enabled fontStyle: (topic.displayName == null) ? null : FontStyle.italic, ).merge(weightVariableTextStyle(context)))), if (icon != null) @@ -1098,13 +1096,11 @@ class StreamMessageRecipientHeader extends StatelessWidget { child: Row( children: [ Flexible( - // ignore: dead_null_aware_expression // null topic names soon to be enabled child: Text(topic.displayName ?? store.realmEmptyTopicDisplayName, // TODO: Give a way to see the whole topic (maybe a // long-press interaction?) overflow: TextOverflow.ellipsis, style: recipientHeaderTextStyle(context).copyWith( - // ignore: unnecessary_null_comparison // null topic names soon to be enabled fontStyle: (topic.displayName == null) ? null : FontStyle.italic, ))), const SizedBox(width: 4), diff --git a/test/api/model/model_checks.dart b/test/api/model/model_checks.dart index 8b39b1ad57d..747b2e1233c 100644 --- a/test/api/model/model_checks.dart +++ b/test/api/model/model_checks.dart @@ -48,7 +48,7 @@ extension MessageChecks on Subject { extension TopicNameChecks on Subject { Subject get apiName => has((x) => x.apiName, 'apiName'); - Subject get displayName => has((x) => x.displayName, 'displayName'); + Subject get displayName => has((x) => x.displayName, 'displayName'); } extension StreamMessageChecks on Subject { diff --git a/test/widgets/autocomplete_test.dart b/test/widgets/autocomplete_test.dart index a104edc0c4e..99681caf666 100644 --- a/test/widgets/autocomplete_test.dart +++ b/test/widgets/autocomplete_test.dart @@ -297,7 +297,7 @@ void main() { await tester.tap(find.text('Topic three')); await tester.pumpAndSettle(); check(tester.widget(topicInputFinder).controller!.text) - .equals(topic3.name.displayName); + .equals(topic3.name.displayName!); check(find.text('Topic one' )).findsNothing(); check(find.text('Topic two' )).findsNothing(); check(find.text('Topic three')).findsOne(); // shown in `_TopicInput` once @@ -354,7 +354,7 @@ void main() { await tester.pumpAndSettle(); check(find.text(eg.defaultRealmEmptyTopicDisplayName)).findsOne(); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('match general chat in autocomplete', (tester) async { final topic = eg.getStreamTopicsEntry(name: ''); @@ -366,7 +366,7 @@ void main() { await tester.pumpAndSettle(); check(find.text(eg.defaultRealmEmptyTopicDisplayName)).findsOne(); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('autocomplete to general chat sets topic to empty string', (tester) async { final topic = eg.getStreamTopicsEntry(name: ''); @@ -383,6 +383,6 @@ void main() { check(controller.value).text.equals(''); await tester.pump(Duration.zero); - }, skip: true); // null topic names soon to be enabled + }); }); } diff --git a/test/widgets/compose_box_test.dart b/test/widgets/compose_box_test.dart index 84ebe546ce5..fd068cc375b 100644 --- a/test/widgets/compose_box_test.dart +++ b/test/widgets/compose_box_test.dart @@ -350,7 +350,7 @@ void main() { checkComposeBoxHintTexts(tester, topicHintText: eg.defaultRealmEmptyTopicDisplayName, contentHintText: 'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}'); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('to ChannelNarrow without topic; mandatory topics', (tester) async { await prepare(tester, narrow: ChannelNarrow(channel.streamId), @@ -358,7 +358,7 @@ void main() { checkComposeBoxHintTexts(tester, topicHintText: 'Topic', contentHintText: 'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}'); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('legacy: to ChannelNarrow without topic', (tester) async { await prepare(tester, narrow: ChannelNarrow(channel.streamId), @@ -390,7 +390,7 @@ void main() { narrow: TopicNarrow(channel.streamId, TopicName(''))); checkComposeBoxHintTexts(tester, contentHintText: 'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}'); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('to DmNarrow with self', (tester) async { await prepare(tester, narrow: DmNarrow.withUser( @@ -710,7 +710,7 @@ void main() { 'content': 'test content', 'read_by_sender': 'true', }); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('legacy: empty topic -> (no topic)', (tester) async { await setupAndTapSend(tester, @@ -740,7 +740,7 @@ void main() { topicInputText: eg.defaultRealmEmptyTopicDisplayName, mandatoryTopics: true); checkMessageNotSent(tester); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('if topics are mandatory, reject (no topic)', (tester) async { await setupAndTapSend(tester, diff --git a/test/widgets/inbox_test.dart b/test/widgets/inbox_test.dart index 419c8123068..0cfb3fda0bc 100644 --- a/test/widgets/inbox_test.dart +++ b/test/widgets/inbox_test.dart @@ -316,7 +316,7 @@ void main() { unreadMessages: [eg.streamMessage(stream: channel, topic: '')]); check(find.text(eg.defaultRealmEmptyTopicDisplayName)).findsOne(); - }, skip: true); // null topic names soon to be enabled + }); }); group('topic visibility', () { diff --git a/test/widgets/message_list_test.dart b/test/widgets/message_list_test.dart index b48649d88ce..ea81ede25ff 100644 --- a/test/widgets/message_list_test.dart +++ b/test/widgets/message_list_test.dart @@ -813,7 +813,7 @@ void main() { await tester.pump(); check(findInMessageList('stream name')).length.equals(1); check(findInMessageList(eg.defaultRealmEmptyTopicDisplayName)).length.equals(1); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('show general chat for empty topics without channel name', (tester) async { await setupMessageListPage(tester, @@ -822,7 +822,7 @@ void main() { await tester.pump(); check(findInMessageList('stream name')).length.equals(0); check(findInMessageList(eg.defaultRealmEmptyTopicDisplayName)).length.equals(1); - }, skip: true); // null topic names soon to be enabled + }); testWidgets('show topic visibility icon when followed', (tester) async { await setupMessageListPage(tester,