@@ -8,6 +8,7 @@ import 'package:share_plus/share_plus.dart';
88
99import '../api/exception.dart' ;
1010import '../api/model/model.dart' ;
11+ import '../api/model/narrow.dart' ;
1112import '../api/route/channels.dart' ;
1213import '../api/route/messages.dart' ;
1314import '../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