Skip to content

Series of prep commits for topic action sheet related changes #1125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 60 additions & 49 deletions lib/widgets/action_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,10 @@ import 'store.dart';
import 'text.dart';
import 'theme.dart';

/// Show a sheet of actions you can take on a message in the message list.
///
/// Must have a [MessageListPage] ancestor.
void showMessageActionSheet({required BuildContext context, required Message message}) {
final store = PerAccountStoreWidget.of(context);

// The UI that's conditioned on this won't live-update during this appearance
// of the action sheet (we avoid calling composeBoxControllerOf in a build
// method; see its doc).
// So we rely on the fact that isComposeBoxOffered for any given message list
// will be constant through the page's life.
final messageListPage = MessageListPage.ancestorOf(context);
final isComposeBoxOffered = messageListPage.composeBoxController != null;

final isMessageRead = message.flags.contains(MessageFlag.read);
final markAsUnreadSupported = store.connection.zulipFeatureLevel! >= 155; // TODO(server-6)
final showMarkAsUnreadButton = markAsUnreadSupported && isMessageRead;

final hasThumbsUpReactionVote = message.reactions
?.aggregated.any((reactionWithVotes) =>
reactionWithVotes.reactionType == ReactionType.unicodeEmoji
&& reactionWithVotes.emojiCode == '1f44d'
&& reactionWithVotes.userIds.contains(store.selfUserId))
?? false;

final optionButtons = [
if (!hasThumbsUpReactionVote)
AddThumbsUpButton(message: message, pageContext: context),
StarButton(message: message, pageContext: context),
if (isComposeBoxOffered)
QuoteAndReplyButton(message: message, pageContext: context),
if (showMarkAsUnreadButton)
MarkAsUnreadButton(message: message, pageContext: context),
CopyMessageTextButton(message: message, pageContext: context),
CopyMessageLinkButton(message: message, pageContext: context),
ShareButton(message: message, pageContext: context),
];

void _showActionSheet(
BuildContext context, {
required List<ActionSheetMenuItemButton> optionButtons,
}) {
showModalBottomSheet<void>(
context: context,
// Clip.hardEdge looks bad; Clip.antiAliasWithSaveLayer looks pixel-perfect
Expand Down Expand Up @@ -88,17 +54,13 @@ void showMessageActionSheet({required BuildContext context, required Message mes
borderRadius: BorderRadius.circular(7),
child: Column(spacing: 1,
children: optionButtons))))),
const MessageActionSheetCancelButton(),
const ActionSheetCancelButton(),
])));
});
}

abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
MessageActionSheetMenuItemButton({
super.key,
required this.message,
required this.pageContext,
}) : assert(pageContext.findAncestorWidgetOfExactType<MessageListPage>() != null);
abstract class ActionSheetMenuItemButton extends StatelessWidget {
const ActionSheetMenuItemButton({super.key, required this.pageContext});

IconData get icon;
String label(ZulipLocalizations zulipLocalizations);
Expand All @@ -111,8 +73,6 @@ abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
/// For operations that need a [BuildContext], see [pageContext].
void onPressed();

final Message message;

/// A context within the [MessageListPage] this action sheet was
/// triggered from.
final BuildContext pageContext;
Expand Down Expand Up @@ -157,8 +117,8 @@ abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
}
}

class MessageActionSheetCancelButton extends StatelessWidget {
const MessageActionSheetCancelButton({super.key});
class ActionSheetCancelButton extends StatelessWidget {
const ActionSheetCancelButton({super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -183,6 +143,57 @@ class MessageActionSheetCancelButton extends StatelessWidget {
}
}

/// Show a sheet of actions you can take on a message in the message list.
///
/// Must have a [MessageListPage] ancestor.
void showMessageActionSheet({required BuildContext context, required Message message}) {
final store = PerAccountStoreWidget.of(context);

// The UI that's conditioned on this won't live-update during this appearance
// of the action sheet (we avoid calling composeBoxControllerOf in a build
// method; see its doc).
// So we rely on the fact that isComposeBoxOffered for any given message list
// will be constant through the page's life.
final messageListPage = MessageListPage.ancestorOf(context);
final isComposeBoxOffered = messageListPage.composeBoxController != null;

final isMessageRead = message.flags.contains(MessageFlag.read);
final markAsUnreadSupported = store.connection.zulipFeatureLevel! >= 155; // TODO(server-6)
final showMarkAsUnreadButton = markAsUnreadSupported && isMessageRead;

final hasThumbsUpReactionVote = message.reactions
?.aggregated.any((reactionWithVotes) =>
reactionWithVotes.reactionType == ReactionType.unicodeEmoji
&& reactionWithVotes.emojiCode == '1f44d'
&& reactionWithVotes.userIds.contains(store.selfUserId))
?? false;

final optionButtons = [
if (!hasThumbsUpReactionVote)
AddThumbsUpButton(message: message, pageContext: context),
StarButton(message: message, pageContext: context),
if (isComposeBoxOffered)
QuoteAndReplyButton(message: message, pageContext: context),
if (showMarkAsUnreadButton)
MarkAsUnreadButton(message: message, pageContext: context),
CopyMessageTextButton(message: message, pageContext: context),
CopyMessageLinkButton(message: message, pageContext: context),
ShareButton(message: message, pageContext: context),
];

_showActionSheet(context, optionButtons: optionButtons);
}

abstract class MessageActionSheetMenuItemButton extends ActionSheetMenuItemButton {
MessageActionSheetMenuItemButton({
super.key,
required this.message,
required super.pageContext,
}) : assert(pageContext.findAncestorWidgetOfExactType<MessageListPage>() != null);

final Message message;
}

// This button is very temporary, to complete #125 before we have a way to
// choose an arbitrary reaction (#388). So, skipping i18n.
class AddThumbsUpButton extends MessageActionSheetMenuItemButton {
Expand Down