1
+ import 'package:flutter/foundation.dart' ;
1
2
import 'package:flutter/material.dart' ;
2
3
import 'package:flutter/services.dart' ;
3
4
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart' ;
@@ -12,10 +13,12 @@ import 'actions.dart';
12
13
import 'clipboard.dart' ;
13
14
import 'compose_box.dart' ;
14
15
import 'dialog.dart' ;
15
- import 'draggable_scrollable_modal_bottom_sheet.dart' ;
16
16
import 'icons.dart' ;
17
+ import 'inset_shadow.dart' ;
17
18
import 'message_list.dart' ;
18
19
import 'store.dart' ;
20
+ import 'text.dart' ;
21
+ import 'theme.dart' ;
19
22
20
23
/// Show a sheet of actions you can take on a message in the message list.
21
24
///
@@ -41,21 +44,48 @@ void showMessageActionSheet({required BuildContext context, required Message mes
41
44
&& reactionWithVotes.userIds.contains (store.selfUserId))
42
45
?? false ;
43
46
44
- showDraggableScrollableModalBottomSheet <void >(
47
+ final optionButtons = [
48
+ if (! hasThumbsUpReactionVote)
49
+ AddThumbsUpButton (message: message, messageListContext: context),
50
+ StarButton (message: message, messageListContext: context),
51
+ if (isComposeBoxOffered)
52
+ QuoteAndReplyButton (message: message, messageListContext: context),
53
+ if (showMarkAsUnreadButton)
54
+ MarkAsUnreadButton (message: message, messageListContext: context, narrow: narrow),
55
+ CopyMessageTextButton (message: message, messageListContext: context),
56
+ CopyMessageLinkButton (message: message, messageListContext: context),
57
+ ShareButton (message: message, messageListContext: context),
58
+ ];
59
+
60
+ showModalBottomSheet <void >(
45
61
context: context,
62
+ // Clip.hardEdge looks bad; Clip.antiAliasWithSaveLayer looks pixel-perfect
63
+ // on my iPhone 13 Pro but is marked as "much slower":
64
+ // https://api.flutter.dev/flutter/dart-ui/Clip.html
65
+ clipBehavior: Clip .antiAlias,
66
+ useSafeArea: true ,
67
+ isScrollControlled: true ,
46
68
builder: (BuildContext _) {
47
- return Column (children: [
48
- if (! hasThumbsUpReactionVote)
49
- AddThumbsUpButton (message: message, messageListContext: context),
50
- StarButton (message: message, messageListContext: context),
51
- if (isComposeBoxOffered)
52
- QuoteAndReplyButton (message: message, messageListContext: context),
53
- if (showMarkAsUnreadButton)
54
- MarkAsUnreadButton (message: message, messageListContext: context, narrow: narrow),
55
- CopyMessageTextButton (message: message, messageListContext: context),
56
- CopyMessageLinkButton (message: message, messageListContext: context),
57
- ShareButton (message: message, messageListContext: context),
58
- ]);
69
+ return SafeArea (
70
+ minimum: const EdgeInsets .only (bottom: 16 ),
71
+ child: Padding (
72
+ padding: const EdgeInsets .fromLTRB (16 , 0 , 16 , 0 ),
73
+ child: Column (
74
+ crossAxisAlignment: CrossAxisAlignment .stretch,
75
+ mainAxisSize: MainAxisSize .min,
76
+ children: [
77
+ // TODO(#217): show message text
78
+ Flexible (child: InsetShadowBox (
79
+ top: 8 , bottom: 8 ,
80
+ color: DesignVariables .of (context).bgContextMenu,
81
+ child: SingleChildScrollView (
82
+ padding: const EdgeInsets .only (top: 16 , bottom: 8 ),
83
+ child: ClipRRect (
84
+ borderRadius: BorderRadius .circular (7 ),
85
+ child: Column (spacing: 1 , children: optionButtons),
86
+ )))),
87
+ const MessageActionSheetCancelButton (),
88
+ ])));
59
89
});
60
90
}
61
91
@@ -75,11 +105,47 @@ abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
75
105
76
106
@override
77
107
Widget build (BuildContext context) {
108
+ final designVariables = DesignVariables .of (context);
78
109
final zulipLocalizations = ZulipLocalizations .of (context);
79
110
return MenuItemButton (
80
- leadingIcon: Icon (icon),
111
+ trailingIcon: Icon (icon, color: designVariables.contextMenuItemText),
112
+ style: MenuItemButton .styleFrom (
113
+ padding: const EdgeInsets .symmetric (vertical: 12 , horizontal: 16 ),
114
+ foregroundColor: designVariables.contextMenuItemText,
115
+ splashFactory: NoSplash .splashFactory,
116
+ ).copyWith (backgroundColor: WidgetStateColor .resolveWith ((states) =>
117
+ designVariables.contextMenuItemBg.withValues (
118
+ alpha: states.contains (WidgetState .pressed) ? 0.20 : 0.12 ))),
81
119
onPressed: () => onPressed (context),
82
- child: Text (label (zulipLocalizations)));
120
+ child: Text (label (zulipLocalizations),
121
+ style: const TextStyle (fontSize: 20 , height: 24 / 20 )
122
+ .merge (weightVariableTextStyle (context, wght: 600 )),
123
+ ));
124
+ }
125
+ }
126
+
127
+ class MessageActionSheetCancelButton extends StatelessWidget {
128
+ const MessageActionSheetCancelButton ({super .key});
129
+
130
+ @override
131
+ Widget build (BuildContext context) {
132
+ final designVariables = DesignVariables .of (context);
133
+ return TextButton (
134
+ style: TextButton .styleFrom (
135
+ padding: const EdgeInsets .all (10 ),
136
+ foregroundColor: designVariables.contextMenuCancelText,
137
+ shape: RoundedRectangleBorder (borderRadius: BorderRadius .circular (7 )),
138
+ splashFactory: NoSplash .splashFactory,
139
+ ).copyWith (backgroundColor: WidgetStateColor .resolveWith ((states) =>
140
+ designVariables.contextMenuCancelBg.withValues (
141
+ alpha: states.contains (WidgetState .pressed) ? 0.20 : 0.15 ))),
142
+ onPressed: () {
143
+ Navigator .pop (context);
144
+ },
145
+ child: Text (ZulipLocalizations .of (context).dialogCancel,
146
+ style: const TextStyle (fontSize: 20 , height: 24 / 20 )
147
+ .merge (weightVariableTextStyle (context, wght: 600 ))),
148
+ );
83
149
}
84
150
}
85
151
@@ -92,7 +158,7 @@ class AddThumbsUpButton extends MessageActionSheetMenuItemButton {
92
158
required super .messageListContext,
93
159
});
94
160
95
- @override IconData get icon => Icons .add_reaction_outlined ;
161
+ @override IconData get icon => ZulipIcons .smile ;
96
162
97
163
@override
98
164
String label (ZulipLocalizations zulipLocalizations) {
@@ -133,11 +199,13 @@ class StarButton extends MessageActionSheetMenuItemButton {
133
199
required super .messageListContext,
134
200
});
135
201
136
- @override IconData get icon => ZulipIcons .star_filled;
202
+ @override IconData get icon => _isStarred ? ZulipIcons .star_filled : ZulipIcons .star;
203
+
204
+ bool get _isStarred => message.flags.contains (MessageFlag .starred);
137
205
138
206
@override
139
207
String label (ZulipLocalizations zulipLocalizations) {
140
- return message.flags. contains ( MessageFlag .starred)
208
+ return _isStarred
141
209
? zulipLocalizations.actionSheetOptionUnstarMessage
142
210
: zulipLocalizations.actionSheetOptionStarMessage;
143
211
}
@@ -229,7 +297,7 @@ class QuoteAndReplyButton extends MessageActionSheetMenuItemButton {
229
297
required super .messageListContext,
230
298
});
231
299
232
- @override IconData get icon => Icons .format_quote_outlined ;
300
+ @override IconData get icon => ZulipIcons .format_quote ;
233
301
234
302
@override
235
303
String label (ZulipLocalizations zulipLocalizations) {
@@ -314,7 +382,7 @@ class CopyMessageTextButton extends MessageActionSheetMenuItemButton {
314
382
required super .messageListContext,
315
383
});
316
384
317
- @override IconData get icon => Icons .copy;
385
+ @override IconData get icon => ZulipIcons .copy;
318
386
319
387
@override
320
388
String label (ZulipLocalizations zulipLocalizations) {
@@ -382,7 +450,10 @@ class ShareButton extends MessageActionSheetMenuItemButton {
382
450
required super .messageListContext,
383
451
});
384
452
385
- @override IconData get icon => Icons .adaptive.share;
453
+ @override
454
+ IconData get icon => defaultTargetPlatform == TargetPlatform .iOS
455
+ ? ZulipIcons .share_ios
456
+ : ZulipIcons .share;
386
457
387
458
@override
388
459
String label (ZulipLocalizations zulipLocalizations) {
0 commit comments