Skip to content

Commit ee04c30

Browse files
committed
action_sheet: Add "Mark topic as read" button
Fixes: zulip#1225
1 parent 181dc8c commit ee04c30

11 files changed

+101
-0
lines changed

assets/l10n/app_en.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@
136136
"@actionSheetOptionUnstarMessage": {
137137
"description": "Label for unstar button on action sheet."
138138
},
139+
"actionSheetOptionMarkTopicAsRead": "Mark topic as read",
140+
"@actionSheetOptionMarkTopicAsRead": {
141+
"description": "Option to mark a specific topic as read in the action sheet."
142+
},
139143
"errorWebAuthOperationalErrorTitle": "Something went wrong",
140144
"@errorWebAuthOperationalErrorTitle": {
141145
"description": "Error title when third-party authentication has an operational error (not necessarily caused by invalid credentials)."

lib/generated/l10n/zulip_localizations.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ abstract class ZulipLocalizations {
309309
/// **'Unstar message'**
310310
String get actionSheetOptionUnstarMessage;
311311

312+
/// Option to mark a specific topic as read in the action sheet.
313+
///
314+
/// In en, this message translates to:
315+
/// **'Mark topic as read'**
316+
String get actionSheetOptionMarkTopicAsRead;
317+
312318
/// Error title when third-party authentication has an operational error (not necessarily caused by invalid credentials).
313319
///
314320
/// In en, this message translates to:

lib/generated/l10n/zulip_localizations_ar.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Unstar message';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
117120

lib/generated/l10n/zulip_localizations_en.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Unstar message';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
117120

lib/generated/l10n/zulip_localizations_ja.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Unstar message';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
117120

lib/generated/l10n/zulip_localizations_nb.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Unstar message';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Something went wrong';
117120

lib/generated/l10n/zulip_localizations_pl.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Odbierz gwiazdkę';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Coś poszło nie tak';
117120

lib/generated/l10n/zulip_localizations_ru.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Снять отметку с сообщения';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Что-то пошло не так';
117120

lib/generated/l10n/zulip_localizations_sk.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
112112
@override
113113
String get actionSheetOptionUnstarMessage => 'Odhviezdičkovať správu';
114114

115+
@override
116+
String get actionSheetOptionMarkTopicAsRead => 'Mark topic as read';
117+
115118
@override
116119
String get errorWebAuthOperationalErrorTitle => 'Niečo sa pokazilo';
117120

lib/widgets/action_sheet.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,14 @@ void showTopicActionSheet(BuildContext context, {
255255
someMessageIdInTopic: someMessageIdInTopic));
256256
}
257257

258+
final unreadCount = store.unreads.countInTopicNarrow(channelId, topic);
259+
if (unreadCount > 0) {
260+
optionButtons.add(MarkTopicAsReadButton(
261+
channelId: channelId,
262+
topic: topic,
263+
pageContext: context));
264+
}
265+
258266
if (optionButtons.isEmpty) {
259267
// TODO(a11y): This case makes a no-op gesture handler; as a consequence,
260268
// we're presenting some UI (to people who use screen-reader software) as
@@ -461,6 +469,30 @@ class ResolveUnresolveButton extends ActionSheetMenuItemButton {
461469
}
462470
}
463471

472+
class MarkTopicAsReadButton extends ActionSheetMenuItemButton {
473+
const MarkTopicAsReadButton({
474+
super.key,
475+
required this.channelId,
476+
required this.topic,
477+
required super.pageContext,
478+
});
479+
480+
final int channelId;
481+
final TopicName topic;
482+
483+
@override IconData get icon => ZulipIcons.message_checked;
484+
485+
@override
486+
String label(ZulipLocalizations zulipLocalizations) {
487+
return zulipLocalizations.actionSheetOptionMarkTopicAsRead;
488+
}
489+
490+
@override void onPressed() async {
491+
if (!pageContext.mounted) return;
492+
await ZulipAction.markNarrowAsRead(pageContext, TopicNarrow(channelId, topic));
493+
}
494+
}
495+
464496
/// Show a sheet of actions you can take on a message in the message list.
465497
///
466498
/// Must have a [MessageListPage] ancestor.

test/widgets/action_sheet_test.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,44 @@ void main() {
562562
expectedTitle: 'Failed to mark topic as unresolved');
563563
});
564564
});
565+
566+
group('MarkTopicAsReadButton', () {
567+
testWidgets('visible if topic has unread messages', (tester) async {
568+
await prepare();
569+
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
570+
await store.handleEvent(MessageEvent(id: 0, message: message));
571+
await showFromAppBar(tester, messages: [message]);
572+
check(find.text('Mark topic as read')).findsOne();
573+
});
574+
575+
testWidgets('not visible if topic has no unread messages', (tester) async {
576+
await prepare();
577+
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
578+
await showFromAppBar(tester, messages: [message]);
579+
check(find.text('Mark topic as read')).findsNothing();
580+
});
581+
582+
testWidgets('marks topic as read when pressed', (tester) async {
583+
await prepare();
584+
final message = eg.streamMessage(stream: someChannel, topic: someTopic);
585+
await store.handleEvent(MessageEvent(id: 0, message: message));
586+
await showFromAppBar(tester, messages: [message]);
587+
588+
connection.prepare(json: UpdateMessageFlagsForNarrowResult(
589+
processedCount: 1, updatedCount: 1,
590+
firstProcessedId: message.id, lastProcessedId: message.id,
591+
foundOldest: true, foundNewest: true).toJson());
592+
await tester.tap(find.text('Mark topic as read'));
593+
await tester.pumpAndSettle();
594+
595+
check(connection.lastRequest).isA<http.Request>()
596+
..url.path.equals('/api/v1/messages/flags/narrow')
597+
..bodyFields['narrow'].equals(jsonEncode([
598+
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(),
599+
{'operator': 'is', 'operand': 'unread'},
600+
]));
601+
});
602+
});
565603
});
566604

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

0 commit comments

Comments
 (0)