11import 'dart:async' ;
22
3+ import 'package:flutter/foundation.dart' ;
34import 'package:flutter/material.dart' ;
45import 'package:flutter/services.dart' ;
56import 'package:flutter_gen/gen_l10n/zulip_localizations.dart' ;
@@ -14,10 +15,12 @@ import 'actions.dart';
1415import 'clipboard.dart' ;
1516import 'compose_box.dart' ;
1617import 'dialog.dart' ;
17- import 'draggable_scrollable_modal_bottom_sheet.dart' ;
1818import 'icons.dart' ;
19+ import 'inset_shadow.dart' ;
1920import 'message_list.dart' ;
2021import 'store.dart' ;
22+ import 'text.dart' ;
23+ import 'theme.dart' ;
2124
2225/// Show a sheet of actions you can take on a message in the message list.
2326///
@@ -43,21 +46,48 @@ void showMessageActionSheet({required BuildContext context, required Message mes
4346 && reactionWithVotes.userIds.contains (store.selfUserId))
4447 ?? false ;
4548
46- showDraggableScrollableModalBottomSheet <void >(
49+ final optionButtons = [
50+ if (! hasThumbsUpReactionVote)
51+ AddThumbsUpButton (message: message, messageListContext: context),
52+ StarButton (message: message, messageListContext: context),
53+ if (isComposeBoxOffered)
54+ QuoteAndReplyButton (message: message, messageListContext: context),
55+ if (showMarkAsUnreadButton)
56+ MarkAsUnreadButton (message: message, messageListContext: context, narrow: narrow),
57+ CopyMessageTextButton (message: message, messageListContext: context),
58+ CopyMessageLinkButton (message: message, messageListContext: context),
59+ ShareButton (message: message, messageListContext: context),
60+ ];
61+
62+ showModalBottomSheet <void >(
4763 context: context,
64+ // Clip.hardEdge looks bad; Clip.antiAliasWithSaveLayer looks pixel-perfect
65+ // on my iPhone 13 Pro but is marked as "much slower":
66+ // https://api.flutter.dev/flutter/dart-ui/Clip.html
67+ clipBehavior: Clip .antiAlias,
68+ useSafeArea: true ,
69+ isScrollControlled: true ,
4870 builder: (BuildContext _) {
49- return Column (children: [
50- if (! hasThumbsUpReactionVote)
51- AddThumbsUpButton (message: message, messageListContext: context),
52- StarButton (message: message, messageListContext: context),
53- if (isComposeBoxOffered)
54- QuoteAndReplyButton (message: message, messageListContext: context),
55- if (showMarkAsUnreadButton)
56- MarkAsUnreadButton (message: message, messageListContext: context, narrow: narrow),
57- CopyMessageTextButton (message: message, messageListContext: context),
58- CopyMessageLinkButton (message: message, messageListContext: context),
59- ShareButton (message: message, messageListContext: context),
60- ]);
71+ return SafeArea (
72+ minimum: const EdgeInsets .only (bottom: 16 ),
73+ child: Padding (
74+ padding: const EdgeInsets .fromLTRB (16 , 0 , 16 , 0 ),
75+ child: Column (
76+ crossAxisAlignment: CrossAxisAlignment .stretch,
77+ mainAxisSize: MainAxisSize .min,
78+ children: [
79+ // TODO(#217): show message text
80+ Flexible (child: InsetShadowBox (
81+ top: 8 , bottom: 8 ,
82+ color: DesignVariables .of (context).bgContextMenu,
83+ child: SingleChildScrollView (
84+ padding: const EdgeInsets .only (top: 16 , bottom: 8 ),
85+ child: ClipRRect (
86+ borderRadius: BorderRadius .circular (7 ),
87+ child: Column (spacing: 1 ,
88+ children: optionButtons))))),
89+ const MessageActionSheetCancelButton (),
90+ ])));
6191 });
6292}
6393
@@ -77,11 +107,47 @@ abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
77107
78108 @override
79109 Widget build (BuildContext context) {
110+ final designVariables = DesignVariables .of (context);
80111 final zulipLocalizations = ZulipLocalizations .of (context);
81112 return MenuItemButton (
82- leadingIcon: Icon (icon),
113+ trailingIcon: Icon (icon, color: designVariables.contextMenuItemText),
114+ style: MenuItemButton .styleFrom (
115+ padding: const EdgeInsets .symmetric (vertical: 12 , horizontal: 16 ),
116+ foregroundColor: designVariables.contextMenuItemText,
117+ splashFactory: NoSplash .splashFactory,
118+ ).copyWith (backgroundColor: WidgetStateColor .resolveWith ((states) =>
119+ designVariables.contextMenuItemBg.withValues (
120+ alpha: states.contains (WidgetState .pressed) ? 0.20 : 0.12 ))),
83121 onPressed: () => onPressed (context),
84- child: Text (label (zulipLocalizations)));
122+ child: Text (label (zulipLocalizations),
123+ style: const TextStyle (fontSize: 20 , height: 24 / 20 )
124+ .merge (weightVariableTextStyle (context, wght: 600 )),
125+ ));
126+ }
127+ }
128+
129+ class MessageActionSheetCancelButton extends StatelessWidget {
130+ const MessageActionSheetCancelButton ({super .key});
131+
132+ @override
133+ Widget build (BuildContext context) {
134+ final designVariables = DesignVariables .of (context);
135+ return TextButton (
136+ style: TextButton .styleFrom (
137+ padding: const EdgeInsets .all (10 ),
138+ foregroundColor: designVariables.contextMenuCancelText,
139+ shape: RoundedRectangleBorder (borderRadius: BorderRadius .circular (7 )),
140+ splashFactory: NoSplash .splashFactory,
141+ ).copyWith (backgroundColor: WidgetStateColor .resolveWith ((states) =>
142+ designVariables.contextMenuCancelBg.withValues (
143+ alpha: states.contains (WidgetState .pressed) ? 0.20 : 0.15 ))),
144+ onPressed: () {
145+ Navigator .pop (context);
146+ },
147+ child: Text (ZulipLocalizations .of (context).dialogCancel,
148+ style: const TextStyle (fontSize: 20 , height: 24 / 20 )
149+ .merge (weightVariableTextStyle (context, wght: 600 ))),
150+ );
85151 }
86152}
87153
@@ -94,7 +160,7 @@ class AddThumbsUpButton extends MessageActionSheetMenuItemButton {
94160 required super .messageListContext,
95161 });
96162
97- @override IconData get icon => Icons .add_reaction_outlined ;
163+ @override IconData get icon => ZulipIcons .smile ;
98164
99165 @override
100166 String label (ZulipLocalizations zulipLocalizations) {
@@ -135,11 +201,13 @@ class StarButton extends MessageActionSheetMenuItemButton {
135201 required super .messageListContext,
136202 });
137203
138- @override IconData get icon => ZulipIcons .star_filled;
204+ @override IconData get icon => _isStarred ? ZulipIcons .star_filled : ZulipIcons .star;
205+
206+ bool get _isStarred => message.flags.contains (MessageFlag .starred);
139207
140208 @override
141209 String label (ZulipLocalizations zulipLocalizations) {
142- return message.flags. contains ( MessageFlag .starred)
210+ return _isStarred
143211 ? zulipLocalizations.actionSheetOptionUnstarMessage
144212 : zulipLocalizations.actionSheetOptionStarMessage;
145213 }
@@ -231,7 +299,7 @@ class QuoteAndReplyButton extends MessageActionSheetMenuItemButton {
231299 required super .messageListContext,
232300 });
233301
234- @override IconData get icon => Icons .format_quote_outlined ;
302+ @override IconData get icon => ZulipIcons .format_quote ;
235303
236304 @override
237305 String label (ZulipLocalizations zulipLocalizations) {
@@ -316,7 +384,7 @@ class CopyMessageTextButton extends MessageActionSheetMenuItemButton {
316384 required super .messageListContext,
317385 });
318386
319- @override IconData get icon => Icons .copy;
387+ @override IconData get icon => ZulipIcons .copy;
320388
321389 @override
322390 String label (ZulipLocalizations zulipLocalizations) {
@@ -384,7 +452,10 @@ class ShareButton extends MessageActionSheetMenuItemButton {
384452 required super .messageListContext,
385453 });
386454
387- @override IconData get icon => Icons .adaptive.share;
455+ @override
456+ IconData get icon => defaultTargetPlatform == TargetPlatform .iOS
457+ ? ZulipIcons .share_ios
458+ : ZulipIcons .share;
388459
389460 @override
390461 String label (ZulipLocalizations zulipLocalizations) {
0 commit comments