Skip to content

Commit 8f94b5b

Browse files
committed
compose: Show special hint text for inputs if empty topic
Signed-off-by: Zixuan James Li <[email protected]>
1 parent 86d18ac commit 8f94b5b

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

lib/widgets/compose_box.dart

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,14 @@ class _StreamContentInputState extends State<_StreamContentInput> {
589589
destination: TopicNarrow(widget.narrow.streamId, topic),
590590
controller: widget.controller,
591591
hint: Text(zulipLocalizations.composeBoxChannelContentHint(
592-
'#$streamName > ${topic.displayName}')));
592+
// ignore: dead_null_aware_expression // null topic names soon to be enabled
593+
'#$streamName > ${topic.displayName ?? store.realmEmptyTopicDisplayName}'),
594+
style: TextStyle(
595+
// TODO(#1285): This applies to the entire hint text; ideally we'd only
596+
// want to italize the "general chat" text, but this requires
597+
// special l10n support for the hint text string.
598+
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
599+
fontStyle: topic.displayName == null ? FontStyle.italic : null)));
593600
}
594601
}
595602

@@ -608,6 +615,9 @@ class _TopicInput extends StatelessWidget {
608615
height: 22 / 20,
609616
color: designVariables.textInput.withFadedAlpha(0.9),
610617
).merge(weightVariableTextStyle(context, wght: 600));
618+
final store = PerAccountStoreWidget.of(context);
619+
final allowsEmptyTopics =
620+
store.connection.zulipFeatureLevel! >= 334 && !store.realmMandatoryTopics;
611621

612622
return TopicAutocomplete(
613623
streamId: streamId,
@@ -625,8 +635,11 @@ class _TopicInput extends StatelessWidget {
625635
textInputAction: TextInputAction.next,
626636
style: topicTextStyle,
627637
decoration: InputDecoration(
628-
hintText: zulipLocalizations.composeBoxTopicHintText,
638+
hintText: allowsEmptyTopics
639+
? store.realmEmptyTopicDisplayName
640+
: zulipLocalizations.composeBoxTopicHintText,
629641
hintStyle: topicTextStyle.copyWith(
642+
fontStyle: allowsEmptyTopics ? FontStyle.italic : null,
630643
color: designVariables.textInput.withFadedAlpha(0.5))))));
631644
}
632645
}
@@ -648,7 +661,14 @@ class _FixedDestinationContentInput extends StatelessWidget {
648661
final streamName = store.streams[streamId]?.name
649662
?? zulipLocalizations.unknownChannelName;
650663
return Text(zulipLocalizations.composeBoxChannelContentHint(
651-
'#$streamName > ${topic.displayName}'));
664+
// ignore: dead_null_aware_expression // null topic names soon to be enabled
665+
'#$streamName > ${topic.displayName ?? store.realmEmptyTopicDisplayName}'),
666+
style: TextStyle(
667+
// TODO(#1285): This applies to the entire hint text; ideally we'd only
668+
// want to italize the "general chat" text, but this requires
669+
// special l10n support for the hint text string.
670+
// ignore: unnecessary_null_comparison // null topic names soon to be enabled
671+
fontStyle: topic.displayName == null ? FontStyle.italic : null));
652672

653673
case DmNarrow(otherRecipientIds: []): // The self-1:1 thread.
654674
return Text(zulipLocalizations.composeBoxSelfDmContentHint);

test/widgets/compose_box_test.dart

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,18 @@ void main() {
4747
List<User> otherUsers = const [],
4848
List<ZulipStream> streams = const [],
4949
bool? mandatoryTopics,
50+
int? zulipFeatureLevel,
5051
}) async {
5152
if (narrow case ChannelNarrow(:var streamId) || TopicNarrow(: var streamId)) {
5253
assert(streams.any((stream) => stream.streamId == streamId),
5354
'Add a channel with "streamId" the same as of $narrow.streamId to the store.');
5455
}
5556
addTearDown(testBinding.reset);
5657
selfUser ??= eg.selfUser;
57-
final selfAccount = eg.account(user: selfUser);
58+
zulipFeatureLevel ??= eg.futureZulipFeatureLevel;
59+
final selfAccount = eg.account(user: selfUser, zulipFeatureLevel: zulipFeatureLevel);
5860
await testBinding.globalStore.add(selfAccount, eg.initialSnapshot(
61+
zulipFeatureLevel: zulipFeatureLevel,
5962
realmMandatoryTopics: mandatoryTopics,
6063
));
6164

@@ -326,11 +329,15 @@ void main() {
326329

327330
Future<void> prepare(WidgetTester tester, {
328331
required Narrow narrow,
332+
bool? mandatoryTopics,
333+
int? zulipFeatureLevel,
329334
}) async {
330335
await prepareComposeBox(tester,
331336
narrow: narrow,
332337
otherUsers: [eg.otherUser, eg.thirdUser],
333-
streams: [channel]);
338+
streams: [channel],
339+
mandatoryTopics: mandatoryTopics,
340+
zulipFeatureLevel: zulipFeatureLevel);
334341
}
335342

336343
void checkComposeBoxHintTexts(WidgetTester tester, {
@@ -347,48 +354,79 @@ void main() {
347354
of: contentInputFinder, matching: find.text(contentHintText))).findsOne();
348355
}
349356

350-
testWidgets('to ChannelNarrow without topic', (tester) async {
351-
await prepare(tester, narrow: ChannelNarrow(channel.streamId));
357+
testWidgets('to ChannelNarrow with empty topic', (tester) async {
358+
await prepare(tester, narrow: ChannelNarrow(channel.streamId),
359+
mandatoryTopics: false);
360+
checkComposeBoxHintTexts(tester,
361+
topicHintText: eg.defaultRealmEmptyTopicDisplayName,
362+
contentHintText: 'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}');
363+
}, skip: true); // null topic names soon to be enabled
364+
365+
testWidgets('to ChannelNarrow with empty topic (mandatory topics)', (tester) async {
366+
await prepare(tester, narrow: ChannelNarrow(channel.streamId),
367+
mandatoryTopics: true);
368+
checkComposeBoxHintTexts(tester,
369+
topicHintText: 'Topic',
370+
contentHintText: 'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}');
371+
}, skip: true); // null topic names soon to be enabled
372+
373+
testWidgets('legacy: to ChannelNarrow with empty topic', (tester) async {
374+
await prepare(tester, narrow: ChannelNarrow(channel.streamId),
375+
mandatoryTopics: false,
376+
zulipFeatureLevel: 333);
352377
checkComposeBoxHintTexts(tester,
353378
topicHintText: 'Topic',
354379
contentHintText: 'Message #${channel.name} > (no topic)');
355380
});
356381

357-
testWidgets('to ChannelNarrow with topic', (tester) async {
382+
testWidgets('to ChannelNarrow with non-empty topic', (tester) async {
358383
final narrow = ChannelNarrow(channel.streamId);
359-
await prepare(tester, narrow: narrow);
384+
await prepare(tester, narrow: narrow,
385+
mandatoryTopics: false);
360386
await enterTopic(tester, narrow: narrow, topic: 'new topic');
361387
await tester.pump();
362388
checkComposeBoxHintTexts(tester,
363-
topicHintText: 'Topic',
389+
topicHintText: eg.defaultRealmEmptyTopicDisplayName,
364390
contentHintText: 'Message #${channel.name} > new topic');
365391
});
366392

367-
testWidgets('to TopicNarrow', (tester) async {
393+
testWidgets('to TopicNarrow with non-empty topic', (tester) async {
368394
await prepare(tester,
369-
narrow: TopicNarrow(channel.streamId, TopicName('topic')));
395+
narrow: TopicNarrow(channel.streamId, TopicName('topic')),
396+
mandatoryTopics: false);
370397
checkComposeBoxHintTexts(tester,
371398
contentHintText: 'Message #${channel.name} > topic');
372399
});
373400

401+
testWidgets('to TopicNarrow with empty topic', (tester) async {
402+
await prepare(tester,
403+
narrow: TopicNarrow(channel.streamId, TopicName('')),
404+
mandatoryTopics: false);
405+
checkComposeBoxHintTexts(tester, contentHintText:
406+
'Message #${channel.name} > ${eg.defaultRealmEmptyTopicDisplayName}');
407+
}, skip: true); // null topic names soon to be enabled
408+
374409
testWidgets('to DmNarrow with self', (tester) async {
375410
await prepare(tester, narrow: DmNarrow.withUser(
376-
eg.selfUser.userId, selfUserId: eg.selfUser.userId));
411+
eg.selfUser.userId, selfUserId: eg.selfUser.userId),
412+
mandatoryTopics: false);
377413
checkComposeBoxHintTexts(tester,
378414
contentHintText: 'Jot down something');
379415
});
380416

381417
testWidgets('to 1:1 DmNarrow', (tester) async {
382418
await prepare(tester, narrow: DmNarrow.withUser(
383-
eg.otherUser.userId, selfUserId: eg.selfUser.userId));
419+
eg.otherUser.userId, selfUserId: eg.selfUser.userId),
420+
mandatoryTopics: false);
384421
checkComposeBoxHintTexts(tester,
385422
contentHintText: 'Message @${eg.otherUser.fullName}');
386423
});
387424

388425
testWidgets('to group DmNarrow', (tester) async {
389426
await prepare(tester, narrow: DmNarrow.withOtherUsers(
390427
[eg.otherUser.userId, eg.thirdUser.userId],
391-
selfUserId: eg.selfUser.userId));
428+
selfUserId: eg.selfUser.userId),
429+
mandatoryTopics: false);
392430
checkComposeBoxHintTexts(tester,
393431
contentHintText: 'Message group');
394432
});

0 commit comments

Comments
 (0)