Skip to content

Commit e45f627

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 51d71a9 commit e45f627

11 files changed

+283
-0
lines changed

assets/l10n/app_en.arb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,5 +716,13 @@
716716
"emojiPickerSearchEmoji": "Search emoji",
717717
"@emojiPickerSearchEmoji": {
718718
"description": "Hint text for the emoji picker search text field."
719+
},
720+
"actionSheetOptionMarkTopicAsRead": "Mark Topic As Read",
721+
"@actionSheetOptionMarkTopicAsRead": {
722+
"description": "Option to mark a specific topic as read in the action sheet."
723+
},
724+
"errorMarkTopicAsReadFailed": "Failed to mark the topic as read. Please try again.",
725+
"@errorMarkTopicAsReadFailed": {
726+
"description": "Error message displayed when marking a topic as read fails."
719727
}
720728
}

lib/generated/l10n/zulip_localizations.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,18 @@ abstract class ZulipLocalizations {
10701070
/// In en, this message translates to:
10711071
/// **'Search emoji'**
10721072
String get emojiPickerSearchEmoji;
1073+
1074+
/// Option to mark a specific topic as read in the action sheet.
1075+
///
1076+
/// In en, this message translates to:
1077+
/// **'Mark Topic As Read'**
1078+
String get actionSheetOptionMarkTopicAsRead;
1079+
1080+
/// Error message displayed when marking a topic as read fails.
1081+
///
1082+
/// In en, this message translates to:
1083+
/// **'Failed to mark the topic as read. Please try again.'**
1084+
String get errorMarkTopicAsReadFailed;
10731085
}
10741086

10751087
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
@@ -564,4 +564,10 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
564564

565565
@override
566566
String get emojiPickerSearchEmoji => 'Search emoji';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

lib/generated/l10n/zulip_localizations_en.dart

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

565565
@override
566566
String get emojiPickerSearchEmoji => 'Search emoji';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

lib/generated/l10n/zulip_localizations_ja.dart

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

565565
@override
566566
String get emojiPickerSearchEmoji => 'Search emoji';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

lib/generated/l10n/zulip_localizations_nb.dart

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

565565
@override
566566
String get emojiPickerSearchEmoji => 'Search emoji';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

lib/generated/l10n/zulip_localizations_pl.dart

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

565565
@override
566566
String get emojiPickerSearchEmoji => 'Szukaj emoji';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

lib/generated/l10n/zulip_localizations_ru.dart

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

565565
@override
566566
String get emojiPickerSearchEmoji => 'Поиск эмодзи';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

lib/generated/l10n/zulip_localizations_sk.dart

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

565565
@override
566566
String get emojiPickerSearchEmoji => 'Hľadať emotikon';
567+
568+
@override
569+
String get actionSheetOptionMarkTopicAsRead => 'Mark Topic As Read';
570+
571+
@override
572+
String get errorMarkTopicAsReadFailed => 'Failed to mark the topic as read. Please try again.';
567573
}

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 => ZulipIcons.message_checked;
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)