1
1
import 'dart:async' ;
2
2
3
+ import 'package:flutter/foundation.dart' ;
3
4
import 'package:flutter/material.dart' ;
4
5
import 'package:flutter/services.dart' ;
5
6
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart' ;
@@ -14,10 +15,12 @@ import 'actions.dart';
14
15
import 'clipboard.dart' ;
15
16
import 'compose_box.dart' ;
16
17
import 'dialog.dart' ;
17
- import 'draggable_scrollable_modal_bottom_sheet.dart' ;
18
18
import 'icons.dart' ;
19
+ import 'inset_shadow.dart' ;
19
20
import 'message_list.dart' ;
20
21
import 'store.dart' ;
22
+ import 'text.dart' ;
23
+ import 'theme.dart' ;
21
24
22
25
/// Show a sheet of actions you can take on a message in the message list.
23
26
///
@@ -43,21 +46,48 @@ void showMessageActionSheet({required BuildContext context, required Message mes
43
46
&& reactionWithVotes.userIds.contains (store.selfUserId))
44
47
?? false ;
45
48
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 >(
47
63
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 ,
48
70
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
+ ])));
61
91
});
62
92
}
63
93
@@ -77,11 +107,47 @@ abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
77
107
78
108
@override
79
109
Widget build (BuildContext context) {
110
+ final designVariables = DesignVariables .of (context);
80
111
final zulipLocalizations = ZulipLocalizations .of (context);
81
112
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 ))),
83
121
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
+ );
85
151
}
86
152
}
87
153
@@ -94,7 +160,7 @@ class AddThumbsUpButton extends MessageActionSheetMenuItemButton {
94
160
required super .messageListContext,
95
161
});
96
162
97
- @override IconData get icon => Icons .add_reaction_outlined ;
163
+ @override IconData get icon => ZulipIcons .smile ;
98
164
99
165
@override
100
166
String label (ZulipLocalizations zulipLocalizations) {
@@ -135,11 +201,13 @@ class StarButton extends MessageActionSheetMenuItemButton {
135
201
required super .messageListContext,
136
202
});
137
203
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);
139
207
140
208
@override
141
209
String label (ZulipLocalizations zulipLocalizations) {
142
- return message.flags. contains ( MessageFlag .starred)
210
+ return _isStarred
143
211
? zulipLocalizations.actionSheetOptionUnstarMessage
144
212
: zulipLocalizations.actionSheetOptionStarMessage;
145
213
}
@@ -231,7 +299,7 @@ class QuoteAndReplyButton extends MessageActionSheetMenuItemButton {
231
299
required super .messageListContext,
232
300
});
233
301
234
- @override IconData get icon => Icons .format_quote_outlined ;
302
+ @override IconData get icon => ZulipIcons .format_quote ;
235
303
236
304
@override
237
305
String label (ZulipLocalizations zulipLocalizations) {
@@ -316,7 +384,7 @@ class CopyMessageTextButton extends MessageActionSheetMenuItemButton {
316
384
required super .messageListContext,
317
385
});
318
386
319
- @override IconData get icon => Icons .copy;
387
+ @override IconData get icon => ZulipIcons .copy;
320
388
321
389
@override
322
390
String label (ZulipLocalizations zulipLocalizations) {
@@ -384,7 +452,10 @@ class ShareButton extends MessageActionSheetMenuItemButton {
384
452
required super .messageListContext,
385
453
});
386
454
387
- @override IconData get icon => Icons .adaptive.share;
455
+ @override
456
+ IconData get icon => defaultTargetPlatform == TargetPlatform .iOS
457
+ ? ZulipIcons .share_ios
458
+ : ZulipIcons .share;
388
459
389
460
@override
390
461
String label (ZulipLocalizations zulipLocalizations) {
0 commit comments