Skip to content

Commit af14f10

Browse files
committed
action_sheet: Add "Mark Topic As Read" button
Adds button to mark all messages in a topic as read. The button: - Appears only when the topic has unread messages - Uses mark_topic_as_read API for server feature level < 155 - Uses messages/flags/narrow API for server feature level >= 155 - Shows error dialog if the request fails fixes: #1225
1 parent abec662 commit af14f10

12 files changed

+284
-1
lines changed

assets/l10n/app_en.arb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,5 +680,13 @@
680680
"emojiPickerSearchEmoji": "Search emoji",
681681
"@emojiPickerSearchEmoji": {
682682
"description": "Hint text for the emoji picker search text field."
683+
},
684+
"actionSheetOptionMarkTopicAsRead": "Mark Topic As Read",
685+
"@actionSheetOptionMarkTopicAsRead": {
686+
"description": "Option to mark a specific topic as read in the action sheet."
687+
},
688+
"errorMarkTopicAsReadFailed": "Failed to mark the topic as read. Please try again.",
689+
"@errorMarkTopicAsReadFailed": {
690+
"description": "Error message displayed when marking a topic as read fails."
683691
}
684692
}

lib/generated/l10n/zulip_localizations.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,18 @@ abstract class ZulipLocalizations {
10161016
/// In en, this message translates to:
10171017
/// **'Search emoji'**
10181018
String get emojiPickerSearchEmoji;
1019+
1020+
/// Option to mark a specific topic as read in the action sheet.
1021+
///
1022+
/// In en, this message translates to:
1023+
/// **'Mark Topic As Read'**
1024+
String get actionSheetOptionMarkTopicAsRead;
1025+
1026+
/// Error message displayed when marking a topic as read fails.
1027+
///
1028+
/// In en, this message translates to:
1029+
/// **'Failed to mark the topic as read. Please try again.'**
1030+
String get errorMarkTopicAsReadFailed;
10191031
}
10201032

10211033
class _ZulipLocalizationsDelegate extends LocalizationsDelegate<ZulipLocalizations> {

lib/generated/l10n/zulip_localizations_ar.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Search emoji';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/generated/l10n/zulip_localizations_en.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Search emoji';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/generated/l10n/zulip_localizations_ja.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Search emoji';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/generated/l10n/zulip_localizations_nb.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Search emoji';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/generated/l10n/zulip_localizations_pl.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Szukaj emoji';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/generated/l10n/zulip_localizations_ru.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Поиск эмодзи';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/generated/l10n/zulip_localizations_sk.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,10 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
537537

538538
@override
539539
String get emojiPickerSearchEmoji => 'Hľadať emotikon';
540+
541+
@override
542+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
543+
544+
@override
545+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
540546
}

lib/widgets/action_sheet.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:share_plus/share_plus.dart';
88

99
import '../api/exception.dart';
1010
import '../api/model/model.dart';
11+
import '../api/model/narrow.dart';
1112
import '../api/route/channels.dart';
1213
import '../api/route/messages.dart';
1314
import '../generated/l10n/zulip_localizations.dart';
@@ -240,6 +241,14 @@ void showTopicActionSheet(BuildContext context, {
240241
pageContext: context);
241242
}));
242243

244+
final unreadCount = store.unreads.countInTopicNarrow(channelId, topic);
245+
if (unreadCount > 0) {
246+
optionButtons.add(MarkTopicAsReadButton(
247+
channelId: channelId,
248+
topic: topic,
249+
pageContext: context));
250+
}
251+
243252
if (optionButtons.isEmpty) {
244253
// TODO(a11y): This case makes a no-op gesture handler; as a consequence,
245254
// we're presenting some UI (to people who use screen-reader software) as
@@ -372,6 +381,61 @@ class UserTopicUpdateButton extends ActionSheetMenuItemButton {
372381
}
373382
}
374383

384+
class MarkTopicAsReadButton extends ActionSheetMenuItemButton {
385+
const MarkTopicAsReadButton({
386+
super.key,
387+
required this.channelId,
388+
required this.topic,
389+
required super.pageContext,
390+
});
391+
392+
final int channelId;
393+
final TopicName topic;
394+
395+
@override IconData get icon => Icons.mark_chat_read_outlined;
396+
397+
@override
398+
String label(ZulipLocalizations zulipLocalizations) {
399+
return zulipLocalizations.actionSheetOptionMarkTopicAsRead;
400+
}
401+
402+
@override void onPressed() async {
403+
final store = PerAccountStoreWidget.of(pageContext);
404+
final connection = store.connection;
405+
final zulipLocalizations = ZulipLocalizations.of(pageContext);
406+
407+
try {
408+
if (connection.zulipFeatureLevel! >= 155) {
409+
await updateMessageFlagsForNarrow(connection,
410+
anchor: AnchorCode.oldest,
411+
numBefore: 0,
412+
numAfter: 1000,
413+
narrow: TopicNarrow(channelId, topic).apiEncode()
414+
..add(ApiNarrowIs(IsOperand.unread)),
415+
op: UpdateMessageFlagsOp.add,
416+
flag: MessageFlag.read);
417+
} else {
418+
await markTopicAsRead(connection,
419+
streamId: channelId,
420+
topicName: topic);
421+
}
422+
} catch (e) {
423+
if (!pageContext.mounted) return;
424+
425+
String? errorMessage;
426+
switch (e) {
427+
case ZulipApiException():
428+
errorMessage = e.message;
429+
default:
430+
}
431+
432+
showErrorDialog(context: pageContext,
433+
title: zulipLocalizations.errorMarkTopicAsReadFailed,
434+
message: errorMessage);
435+
}
436+
}
437+
}
438+
375439
/// Show a sheet of actions you can take on a message in the message list.
376440
///
377441
/// Must have a [MessageListPage] ancestor.

0 commit comments

Comments
 (0)