Skip to content

Commit a9566bf

Browse files
committed
compose: Support sending to empty topic
This behavior is designed to replace how sending to an empty topic is effectively sending to "(no topic)". The key difference being that the `TopicName.apiValue` is actually empty, instead of being converted to "(no topic)" with `_computeTextNormalized. Signed-off-by: Zixuan James Li <[email protected]>
1 parent 9ad7427 commit a9566bf

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

lib/widgets/compose_box.dart

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,28 @@ class ComposeTopicController extends ComposeController<TopicValidationError> {
157157
@override
158158
String _computeTextNormalized() {
159159
String trimmed = text.trim();
160-
return trimmed.isEmpty ? kNoTopicTopic : trimmed;
160+
// TODO(server-10): simplify
161+
if (store.connection.zulipFeatureLevel! < 334) {
162+
return trimmed.isEmpty ? kNoTopicTopic : trimmed;
163+
}
164+
165+
return trimmed;
161166
}
162167

163168
bool get _isTopicConsideredEmpty {
164-
return textNormalized.isEmpty || textNormalized == kNoTopicTopic;
169+
bool result = textNormalized.isEmpty
170+
// We keep checking for '(no topic)' regardless of the feature level
171+
// because it remains equivalent to an empty topic even when FL >= 334.
172+
// This can change in the future:
173+
// https://chat.zulip.org/#narrow/channel/412-api-documentation/topic/.28realm_.29mandatory_topics.20behavior/near/2062391
174+
|| textNormalized == kNoTopicTopic;
175+
176+
// TODO(server-10): simplify
177+
if (store.connection.zulipFeatureLevel! >= 334) {
178+
result |= textNormalized == store.realmEmptyTopicDisplayName;
179+
}
180+
181+
return result;
165182
}
166183

167184
@override

test/widgets/compose_box_test.dart

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ void main() {
690690
Future<void> setupAndTapSend(WidgetTester tester, {
691691
required String topicInputText,
692692
required bool mandatoryTopics,
693+
int? zulipFeatureLevel,
693694
}) async {
694695
TypingNotifier.debugEnable = false;
695696
addTearDown(TypingNotifier.debugReset);
@@ -698,7 +699,8 @@ void main() {
698699
final narrow = ChannelNarrow(channel.streamId);
699700
await prepareComposeBox(tester,
700701
narrow: narrow, streams: [channel],
701-
mandatoryTopics: mandatoryTopics);
702+
mandatoryTopics: mandatoryTopics,
703+
zulipFeatureLevel: zulipFeatureLevel);
702704

703705
await enterTopic(tester, narrow: narrow, topic: topicInputText);
704706
await tester.enterText(contentInputFinder, 'test content');
@@ -713,10 +715,21 @@ void main() {
713715
expectedMessage: 'Topics are required in this organization.');
714716
}
715717

716-
testWidgets('empty topic -> "(no topic)"', (tester) async {
718+
testWidgets('empty topic -> empty topic', (tester) async {
717719
await setupAndTapSend(tester,
718720
topicInputText: '',
719721
mandatoryTopics: false);
722+
check(connection.lastRequest).isA<http.Request>()
723+
..method.equals('POST')
724+
..url.path.equals('/api/v1/messages')
725+
..bodyFields['topic'].equals('');
726+
}, skip: true); // null topic names soon to be enabled
727+
728+
testWidgets('legacy: empty topic -> "(no topic)"', (tester) async {
729+
await setupAndTapSend(tester,
730+
topicInputText: '',
731+
mandatoryTopics: false,
732+
zulipFeatureLevel: 333);
720733
check(connection.lastRequest).isA<http.Request>()
721734
..method.equals('POST')
722735
..url.path.equals('/api/v1/messages')
@@ -730,12 +743,27 @@ void main() {
730743
checkMessageNotSent(tester);
731744
});
732745

746+
testWidgets('if topics are mandatory, reject `realmEmptyTopicDisplayName`', (tester) async {
747+
await setupAndTapSend(tester,
748+
topicInputText: eg.defaultRealmEmptyTopicDisplayName,
749+
mandatoryTopics: true);
750+
checkMessageNotSent(tester);
751+
}, skip: true); // null topic names soon to be enabled
752+
733753
testWidgets('if topics are mandatory, reject "(no topic)"', (tester) async {
734754
await setupAndTapSend(tester,
735755
topicInputText: '(no topic)',
736756
mandatoryTopics: true);
737757
checkMessageNotSent(tester);
738758
});
759+
760+
testWidgets('legacy: if topics are mandatory, reject "(no topic)"', (tester) async {
761+
await setupAndTapSend(tester,
762+
topicInputText: '(no topic)',
763+
mandatoryTopics: true,
764+
zulipFeatureLevel: 333);
765+
checkMessageNotSent(tester);
766+
});
739767
});
740768

741769
group('uploads', () {

0 commit comments

Comments
 (0)