Skip to content

Commit e01cae1

Browse files
committed
action_sheet: Add "Mark topic as read" button
fixes: zulip#1225
1 parent 2fe8dfb commit e01cae1

11 files changed

+101
-0
lines changed

assets/l10n/app_en.arb

+4
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@
120120
"@actionSheetOptionUnstarMessage": {
121121
"description": "Label for unstar button on action sheet."
122122
},
123+
"actionSheetOptionMarkTopicAsRead": "Mark topic as read",
124+
"@actionSheetOptionMarkTopicAsRead": {
125+
"description": "Option to mark a specific topic as read in the action sheet."
126+
},
123127
"errorWebAuthOperationalErrorTitle": "Something went wrong",
124128
"@errorWebAuthOperationalErrorTitle": {
125129
"description": "Error title when third-party authentication has an operational error (not necessarily caused by invalid credentials)."

lib/generated/l10n/zulip_localizations.dart

+6
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ abstract class ZulipLocalizations {
285285
/// **'Unstar message'**
286286
String get actionSheetOptionUnstarMessage;
287287

288+
/// Option to mark a specific topic as read in the action sheet.
289+
///
290+
/// In en, this message translates to:
291+
/// **'Mark topic as read'**
292+
String get actionSheetOptionMarkTopicAsRead;
293+
288294
/// Error title when third-party authentication has an operational error (not necessarily caused by invalid credentials).
289295
///
290296
/// In en, this message translates to:

lib/generated/l10n/zulip_localizations_ar.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Unstar message';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
105108

lib/generated/l10n/zulip_localizations_en.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Unstar message';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
105108

lib/generated/l10n/zulip_localizations_ja.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Unstar message';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
105108

lib/generated/l10n/zulip_localizations_nb.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Unstar message';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
105108

lib/generated/l10n/zulip_localizations_pl.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Odbierz gwiazdkę';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Coś poszło nie tak';
105108

lib/generated/l10n/zulip_localizations_ru.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Снять отметку с сообщения';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Что-то пошло не так';
105108

lib/generated/l10n/zulip_localizations_sk.dart

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
100100
@override
101101
String get actionSheetOptionUnstarMessage => 'Odhviezdičkovať správu';
102102

103+
@override
104+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
105+
103106
@override
104107
String get errorWebAuthOperationalErrorTitle => 'Niečo sa pokazilo';
105108

lib/widgets/action_sheet.dart

+32
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,14 @@ void showTopicActionSheet(BuildContext context, {
240240
pageContext: context);
241241
}));
242242

243+
final unreadCount = store.unreads.countInTopicNarrow(channelId, topic);
244+
if (unreadCount > 0) {
245+
optionButtons.add(MarkTopicAsReadButton(
246+
channelId: channelId,
247+
topic: topic,
248+
pageContext: context));
249+
}
250+
243251
if (optionButtons.isEmpty) {
244252
// TODO(a11y): This case makes a no-op gesture handler; as a consequence,
245253
// we're presenting some UI (to people who use screen-reader software) as
@@ -372,6 +380,30 @@ class UserTopicUpdateButton extends ActionSheetMenuItemButton {
372380
}
373381
}
374382

383+
class MarkTopicAsReadButton extends ActionSheetMenuItemButton {
384+
const MarkTopicAsReadButton({
385+
super.key,
386+
required this.channelId,
387+
required this.topic,
388+
required super.pageContext,
389+
});
390+
391+
final int channelId;
392+
final TopicName topic;
393+
394+
@override IconData get icon => ZulipIcons.message_checked;
395+
396+
@override
397+
String label(ZulipLocalizations zulipLocalizations) {
398+
return zulipLocalizations.actionSheetOptionMarkTopicAsRead;
399+
}
400+
401+
@override void onPressed() async {
402+
if (!pageContext.mounted) return;
403+
await markNarrowAsRead(pageContext, TopicNarrow(channelId, topic));
404+
}
405+
}
406+
375407
/// Show a sheet of actions you can take on a message in the message list.
376408
///
377409
/// Must have a [MessageListPage] ancestor.

test/widgets/action_sheet_test.dart

+38
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,44 @@ void main() {
450450
}
451451
});
452452
});
453+
454+
group('MarkTopicAsReadButton', () {
455+
testWidgets('visible if topic has unread messages', (tester) async {
456+
await prepare();
457+
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
458+
await store.handleEvent(MessageEvent(id: 0, message: message));
459+
await showFromAppBar(tester, messages: [message]);
460+
check(find.text('Mark topic as read')).findsOne();
461+
});
462+
463+
testWidgets('not visible if topic has no unread messages', (tester) async {
464+
await prepare();
465+
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
466+
await showFromAppBar(tester, messages: [message]);
467+
check(find.text('Mark topic as read')).findsNothing();
468+
});
469+
470+
testWidgets('marks topic as read when pressed', (tester) async {
471+
await prepare();
472+
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
473+
await store.handleEvent(MessageEvent(id: 0, message: message));
474+
await showFromAppBar(tester, messages: [message]);
475+
476+
connection.prepare(json: UpdateMessageFlagsForNarrowResult(
477+
processedCount: 1, updatedCount: 1,
478+
firstProcessedId: message.id, lastProcessedId: message.id,
479+
foundOldest: true, foundNewest: true).toJson());
480+
await tester.tap(find.text('Mark topic as read'));
481+
await tester.pumpAndSettle();
482+
483+
check(connection.lastRequest).isA<http.Request>()
484+
..url.path.equals('/api/v1/messages/flags/narrow')
485+
..bodyFields['narrow'].equals(jsonEncode([
486+
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(),
487+
{'operator': 'is', 'operand': 'unread'}
488+
]));
489+
});
490+
});
453491
});
454492

455493
group('message action sheet', () {

0 commit comments

Comments
 (0)