Skip to content

Commit

Permalink
action_sheet: Add channel action sheet with mark as read option
Browse files Browse the repository at this point in the history
Fixes: #1226
  • Loading branch information
chimnayajith committed Feb 5, 2025
1 parent ef898b7 commit 8a4937e
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 0 deletions.
8 changes: 8 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
"@permissionsDeniedReadExternalStorage": {
"description": "Message for dialog asking the user to grant permissions for external storage read access."
},
"actionSheetOptionMarkChannelAsRead": "Mark channel as read",
"@actionSheetOptionMarkChannelAsRead": {
"description": "Label for marking a channel as read."
},
"actionSheetOptionMuteTopic": "Mute topic",
"@actionSheetOptionMuteTopic": {
"description": "Label for muting a topic on action sheet."
Expand Down Expand Up @@ -245,6 +249,10 @@
"url": {"type": "String", "example": "https://chat.example.com"}
}
},
"errorMarkChannelAsReadFailed": "Failed to mark channel as read",
"@errorMarkChannelAsReadFailed": {
"description": "Error message when marking a channel as read."
},
"errorMuteTopicFailed": "Failed to mute topic",
"@errorMuteTopicFailed": {
"description": "Error message when muting a topic failed."
Expand Down
12 changes: 12 additions & 0 deletions lib/generated/l10n/zulip_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ abstract class ZulipLocalizations {
/// **'To upload files, please grant Zulip additional permissions in Settings.'**
String get permissionsDeniedReadExternalStorage;

/// Label for marking a channel as read.
///
/// In en, this message translates to:
/// **'Mark channel as read'**
String get actionSheetOptionMarkChannelAsRead;

/// Label for muting a topic on action sheet.
///
/// In en, this message translates to:
Expand Down Expand Up @@ -423,6 +429,12 @@ abstract class ZulipLocalizations {
/// **'Link could not be opened: {url}'**
String errorCouldNotOpenLink(String url);

/// Error message when marking a channel as read.
///
/// In en, this message translates to:
/// **'Failed to mark channel as read'**
String get errorMarkChannelAsReadFailed;

/// Error message when muting a topic failed.
///
/// In en, this message translates to:
Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'To upload files, please grant Zulip additional permissions in Settings.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Mute topic';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Failed to mute topic';

Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'To upload files, please grant Zulip additional permissions in Settings.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Mute topic';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Failed to mute topic';

Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'To upload files, please grant Zulip additional permissions in Settings.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Mute topic';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Failed to mute topic';

Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_nb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'To upload files, please grant Zulip additional permissions in Settings.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Mute topic';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Failed to mute topic';

Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_pl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'Aby odebrać pliki Zulip musi uzyskać dodatkowe uprawnienia w Ustawieniach.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Wycisz wątek';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Wyciszenie bez powodzenia';

Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'Для загрузки файлов, пожалуйста, предоставьте Zulip дополнительные разрешения в настройках.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Отключить тему';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Не удалось отключить тему';

Expand Down
6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations_sk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
@override
String get permissionsDeniedReadExternalStorage => 'To upload files, please grant Zulip additional permissions in Settings.';

@override
String get actionSheetOptionMarkChannelAsRead => 'Mark channel as read';

@override
String get actionSheetOptionMuteTopic => 'Stlmiť tému';

Expand Down Expand Up @@ -199,6 +202,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
return 'Link could not be opened: $url';
}

@override
String get errorMarkChannelAsReadFailed => 'Failed to mark channel as read';

@override
String get errorMuteTopicFailed => 'Nepodarilo sa ztíšiť tému';

Expand Down
62 changes: 62 additions & 0 deletions lib/widgets/action_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,68 @@ class ActionSheetCancelButton extends StatelessWidget {
}
}

/// Show a sheet of actions you can take on a channel.
void showChannelActionSheet(BuildContext context, {
required int streamId,
}) {
final store = PerAccountStoreWidget.of(context);

final optionButtons = <ActionSheetMenuItemButton>[];
final unreadCount = store.unreads.countInChannelNarrow(streamId);
if (unreadCount > 0) {
optionButtons.add(
MarkChannelAsReadButton(
streamId: streamId,
pageContext: context,
),
);
}
if (optionButtons.isEmpty) {
// TODO(a11y): This case makes a no-op gesture handler; as a consequence,
// we're presenting some UI (to people who use screen-reader software) as
// though it offers a gesture interaction that it doesn't meaningfully
// offer, which is confusing. The solution here is probably to remove this
// is-empty case by having at least one button that's always present,
// such as "copy link to channel".
return;
}
_showActionSheet(context, optionButtons: optionButtons);
}

class MarkChannelAsReadButton extends ActionSheetMenuItemButton {
const MarkChannelAsReadButton({
super.key,
required this.streamId,
required super.pageContext
});

final int streamId;

@override
IconData get icon => ZulipIcons.message_checked;

@override
String label(ZulipLocalizations zulipLocalizations) {
return zulipLocalizations.actionSheetOptionMarkChannelAsRead;
}

@override
void onPressed() async {
try {
final narrow = ChannelNarrow(streamId);
await markNarrowAsRead(pageContext, narrow);
} catch (e) {
if (!pageContext.mounted) return;
final zulipLocalizations = ZulipLocalizations.of(pageContext);

showErrorDialog(
context: pageContext,
title: zulipLocalizations.errorMarkChannelAsReadFailed
);
}
}
}

/// Show a sheet of actions you can take on a topic.
void showTopicActionSheet(BuildContext context, {
required int channelId,
Expand Down
13 changes: 13 additions & 0 deletions lib/widgets/inbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ abstract class _HeaderItem extends StatelessWidget {
}

Future<void> onRowTap();
Future<void> onLongPress();

@override
Widget build(BuildContext context) {
Expand All @@ -272,6 +273,7 @@ abstract class _HeaderItem extends StatelessWidget {
// But that's in tension with the Figma, which gives these header rows
// 40px min height.
onTap: onCollapseButtonTap,
onLongPress: onLongPress,
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
Padding(padding: const EdgeInsets.all(10),
child: Icon(size: 20, color: designVariables.sectionCollapseIcon,
Expand Down Expand Up @@ -330,6 +332,12 @@ class _AllDmsHeaderItem extends _HeaderItem {
pageState.allDmsCollapsed = !collapsed;
}
@override Future<void> onRowTap() => onCollapseButtonTap(); // TODO open all-DMs narrow?

@override
Future<void> onLongPress() async {
// TODO(#1272) action sheet for DM conversation
return;
}
}

class _AllDmsSection extends StatelessWidget {
Expand Down Expand Up @@ -464,6 +472,11 @@ class _StreamHeaderItem extends _HeaderItem {
}
}
@override Future<void> onRowTap() => onCollapseButtonTap(); // TODO open channel narrow

@override
Future<void> onLongPress() async {
showChannelActionSheet(sectionContext, streamId: subscription.streamId);
}
}

class _StreamSection extends StatelessWidget {
Expand Down
2 changes: 2 additions & 0 deletions lib/widgets/subscription_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import '../api/model/model.dart';
import '../generated/l10n/zulip_localizations.dart';
import '../model/narrow.dart';
import '../model/unreads.dart';
import 'action_sheet.dart';
import 'icons.dart';
import 'message_list.dart';
import 'store.dart';
Expand Down Expand Up @@ -230,6 +231,7 @@ class SubscriptionItem extends StatelessWidget {
MessageListPage.buildRoute(context: context,
narrow: ChannelNarrow(subscription.streamId)));
},
onLongPress: () => showChannelActionSheet(context, streamId: subscription.streamId),
child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
const SizedBox(width: 16),
Padding(
Expand Down
Loading

0 comments on commit 8a4937e

Please sign in to comment.