Skip to content

Commit 2563a47

Browse files
committed
action_sheet: Redesign bottom sheet
Fixes: #90
1 parent 7538967 commit 2563a47

File tree

3 files changed

+206
-35
lines changed

3 files changed

+206
-35
lines changed

lib/widgets/action_sheet.dart

Lines changed: 121 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flutter/foundation.dart';
12
import 'package:flutter/material.dart';
23
import 'package:flutter/services.dart';
34
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
@@ -12,16 +13,18 @@ import 'actions.dart';
1213
import 'clipboard.dart';
1314
import 'compose_box.dart';
1415
import 'dialog.dart';
15-
import 'draggable_scrollable_modal_bottom_sheet.dart';
1616
import 'icons.dart';
1717
import 'message_list.dart';
1818
import 'store.dart';
19+
import 'text.dart';
20+
import 'theme.dart';
1921

2022
/// Show a sheet of actions you can take on a message in the message list.
2123
///
2224
/// Must have a [MessageListPage] ancestor.
2325
void showMessageActionSheet({required BuildContext context, required Message message}) {
2426
final store = PerAccountStoreWidget.of(context);
27+
final designVariables = DesignVariables.of(context);
2528

2629
// The UI that's conditioned on this won't live-update during this appearance
2730
// of the action sheet (we avoid calling composeBoxControllerOf in a build
@@ -41,21 +44,76 @@ void showMessageActionSheet({required BuildContext context, required Message mes
4144
&& reactionWithVotes.userIds.contains(store.selfUserId))
4245
?? false;
4346

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>(
4561
context: context,
62+
useSafeArea: true,
63+
isScrollControlled: true,
4664
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-
]);
65+
return SafeArea(
66+
minimum: const EdgeInsets.only(bottom: 16),
67+
child: Padding(
68+
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
69+
child: Column(
70+
crossAxisAlignment: CrossAxisAlignment.stretch,
71+
mainAxisSize: MainAxisSize.min,
72+
children: [
73+
// TODO(#217): show message text
74+
Flexible(
75+
child: Stack(
76+
children: [
77+
SingleChildScrollView(
78+
padding: const EdgeInsets.only(top: 16, bottom: 8),
79+
child: ClipRRect(
80+
borderRadius: BorderRadius.circular(7),
81+
child: Column(spacing: 1, children: optionButtons),
82+
)),
83+
// top shadow
84+
Positioned(
85+
top: 0, right: 0, left: 0,
86+
child: Container(
87+
height: 8,
88+
decoration: BoxDecoration(
89+
gradient: LinearGradient(
90+
begin: Alignment.topCenter,
91+
end: Alignment.bottomCenter,
92+
colors: [
93+
designVariables.bgContextMenu,
94+
designVariables.bgContextMenu.withValues(alpha: 0),
95+
])))),
96+
// bottom shadow
97+
Positioned(
98+
bottom: 0, right: 0, left: 0,
99+
child: Container(
100+
height: 8,
101+
decoration: BoxDecoration(
102+
gradient: LinearGradient(
103+
begin: Alignment.topCenter,
104+
end: Alignment.bottomCenter,
105+
colors: [
106+
designVariables.bgContextMenu.withValues(alpha: 0),
107+
designVariables.bgContextMenu,
108+
])))),
109+
],
110+
),
111+
),
112+
const MessageActionSheetCancelButton(),
113+
],
114+
),
115+
),
116+
);
59117
});
60118
}
61119

@@ -75,11 +133,22 @@ abstract class MessageActionSheetMenuItemButton extends StatelessWidget {
75133

76134
@override
77135
Widget build(BuildContext context) {
136+
final designVariables = DesignVariables.of(context);
78137
final zulipLocalizations = ZulipLocalizations.of(context);
79138
return MenuItemButton(
80-
leadingIcon: Icon(icon),
139+
trailingIcon: Icon(icon, color: designVariables.contextMenuItemText),
140+
style: MenuItemButton.styleFrom(
141+
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
142+
foregroundColor: designVariables.contextMenuItemText,
143+
splashFactory: NoSplash.splashFactory,
144+
).copyWith(backgroundColor: WidgetStateColor.resolveWith((states) =>
145+
designVariables.contextMenuItemBg.withValues(
146+
alpha: states.contains(WidgetState.pressed) ? 0.20 : 0.12))),
81147
onPressed: () => onPressed(context),
82-
child: Text(label(zulipLocalizations)));
148+
child: Text(label(zulipLocalizations),
149+
style: const TextStyle(fontSize: 20, height: 24 / 20)
150+
.merge(weightVariableTextStyle(context, wght: 600)),
151+
));
83152
}
84153
}
85154

@@ -92,7 +161,7 @@ class AddThumbsUpButton extends MessageActionSheetMenuItemButton {
92161
required super.messageListContext,
93162
});
94163

95-
@override IconData get icon => Icons.add_reaction_outlined;
164+
@override IconData get icon => ZulipIcons.smile;
96165

97166
@override
98167
String label(ZulipLocalizations zulipLocalizations) {
@@ -133,11 +202,13 @@ class StarButton extends MessageActionSheetMenuItemButton {
133202
required super.messageListContext,
134203
});
135204

136-
@override IconData get icon => ZulipIcons.star_filled;
205+
@override IconData get icon => _isStarred ? ZulipIcons.star_filled : ZulipIcons.star;
206+
207+
bool get _isStarred => message.flags.contains(MessageFlag.starred);
137208

138209
@override
139210
String label(ZulipLocalizations zulipLocalizations) {
140-
return message.flags.contains(MessageFlag.starred)
211+
return _isStarred
141212
? zulipLocalizations.actionSheetOptionUnstarMessage
142213
: zulipLocalizations.actionSheetOptionStarMessage;
143214
}
@@ -229,7 +300,7 @@ class QuoteAndReplyButton extends MessageActionSheetMenuItemButton {
229300
required super.messageListContext,
230301
});
231302

232-
@override IconData get icon => Icons.format_quote_outlined;
303+
@override IconData get icon => ZulipIcons.format_quote;
233304

234305
@override
235306
String label(ZulipLocalizations zulipLocalizations) {
@@ -314,7 +385,7 @@ class CopyMessageTextButton extends MessageActionSheetMenuItemButton {
314385
required super.messageListContext,
315386
});
316387

317-
@override IconData get icon => Icons.copy;
388+
@override IconData get icon => ZulipIcons.copy;
318389

319390
@override
320391
String label(ZulipLocalizations zulipLocalizations) {
@@ -382,7 +453,10 @@ class ShareButton extends MessageActionSheetMenuItemButton {
382453
required super.messageListContext,
383454
});
384455

385-
@override IconData get icon => Icons.adaptive.share;
456+
@override
457+
IconData get icon => defaultTargetPlatform == TargetPlatform.iOS
458+
? ZulipIcons.share_ios
459+
: ZulipIcons.share;
386460

387461
@override
388462
String label(ZulipLocalizations zulipLocalizations) {
@@ -431,3 +505,28 @@ class ShareButton extends MessageActionSheetMenuItemButton {
431505
}
432506
}
433507
}
508+
509+
class MessageActionSheetCancelButton extends StatelessWidget {
510+
const MessageActionSheetCancelButton({super.key});
511+
512+
@override
513+
Widget build(BuildContext context) {
514+
final designVariables = DesignVariables.of(context);
515+
return TextButton(
516+
style: TextButton.styleFrom(
517+
padding: const EdgeInsets.all(10),
518+
foregroundColor: designVariables.contextMenuCancelText,
519+
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(7)),
520+
splashFactory: NoSplash.splashFactory,
521+
).copyWith(backgroundColor: WidgetStateColor.resolveWith((states) =>
522+
designVariables.contextMenuCancelBg.withValues(
523+
alpha: states.contains(WidgetState.pressed) ? 0.20 : 0.15))),
524+
onPressed: () {
525+
Navigator.pop(context);
526+
},
527+
child: Text(ZulipLocalizations.of(context).dialogCancel,
528+
style: const TextStyle(fontSize: 20, height: 24 / 20)
529+
.merge(weightVariableTextStyle(context, wght: 600))),
530+
);
531+
}
532+
}

0 commit comments

Comments
 (0)