Skip to content

Commit b8ccd55

Browse files
committed
button [nfc]: Extract MenuButton{,sShape} out to here, from action sheet
1 parent 8108762 commit b8ccd55

File tree

2 files changed

+78
-18
lines changed

2 files changed

+78
-18
lines changed

lib/widgets/action_sheet.dart

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import '../model/emoji.dart';
1818
import '../model/internal_link.dart';
1919
import '../model/narrow.dart';
2020
import 'actions.dart';
21+
import 'button.dart';
2122
import 'color.dart';
2223
import 'compose_box.dart';
2324
import 'content.dart';
@@ -90,10 +91,7 @@ void _showActionSheet(
9091
color: designVariables.bgContextMenu,
9192
child: SingleChildScrollView(
9293
padding: const EdgeInsets.symmetric(vertical: 8),
93-
child: ClipRRect(
94-
borderRadius: BorderRadius.circular(7),
95-
child: Column(spacing: 1,
96-
children: optionButtons))))),
94+
child: MenuButtonsShape(buttons: optionButtons)))),
9795
const ActionSheetCancelButton(),
9896
]))),
9997
]))));
@@ -153,22 +151,12 @@ abstract class ActionSheetMenuItemButton extends StatelessWidget {
153151

154152
@override
155153
Widget build(BuildContext context) {
156-
final designVariables = DesignVariables.of(context);
157154
final zulipLocalizations = ZulipLocalizations.of(context);
158-
return MenuItemButton(
159-
trailingIcon: Icon(icon, color: designVariables.contextMenuItemText),
160-
style: MenuItemButton.styleFrom(
161-
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
162-
foregroundColor: designVariables.contextMenuItemText,
163-
splashFactory: NoSplash.splashFactory,
164-
).copyWith(backgroundColor: WidgetStateColor.resolveWith((states) =>
165-
designVariables.contextMenuItemBg.withFadedAlpha(
166-
states.contains(WidgetState.pressed) ? 0.20 : 0.12))),
155+
return MenuButton(
156+
icon: icon,
157+
label: label(zulipLocalizations),
167158
onPressed: () => _handlePressed(context),
168-
child: Text(label(zulipLocalizations),
169-
style: const TextStyle(fontSize: 20, height: 24 / 20)
170-
.merge(weightVariableTextStyle(context, wght: 600)),
171-
));
159+
);
172160
}
173161
}
174162

lib/widgets/button.dart

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,75 @@ class _AnimatedScaleOnTapState extends State<AnimatedScaleOnTap> {
257257
child: widget.child));
258258
}
259259
}
260+
261+
/// The rounded-rectangle shape and 1-pixel spacing for a run of [MenuButton]s.
262+
class MenuButtonsShape extends StatelessWidget {
263+
const MenuButtonsShape({
264+
super.key,
265+
required this.buttons,
266+
});
267+
268+
final List<Widget> buttons;
269+
270+
@override
271+
Widget build(BuildContext context) {
272+
return ClipRRect(
273+
borderRadius: BorderRadius.circular(7),
274+
child: Column(spacing: 1,
275+
children: buttons));
276+
}
277+
}
278+
279+
/// The "menu button" component in Figma.
280+
///
281+
/// Must have a [MenuButtonsShape] ancestor.
282+
///
283+
/// See Figma:
284+
/// https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=6070-60681&m=dev
285+
class MenuButton extends StatelessWidget {
286+
const MenuButton({
287+
super.key,
288+
required this.label,
289+
required this.onPressed,
290+
this.icon,
291+
});
292+
293+
final String label;
294+
final VoidCallback onPressed;
295+
final IconData? icon;
296+
297+
static bool _debugCheckShapeAncestor(BuildContext context) {
298+
final ancestor = context.findAncestorWidgetOfExactType<MenuButtonsShape>();
299+
assert(() {
300+
if (ancestor != null) return true;
301+
throw FlutterError.fromParts([
302+
ErrorSummary('No MenuButtonsShape ancestor found.'),
303+
ErrorDescription('MenuButton widgets require a MenuButtonsShape ancestor.'),
304+
]);
305+
}());
306+
return true;
307+
}
308+
309+
@override
310+
Widget build(BuildContext context) {
311+
_debugCheckShapeAncestor(context);
312+
313+
final designVariables = DesignVariables.of(context);
314+
315+
return MenuItemButton(
316+
trailingIcon: icon != null
317+
? Icon(icon, color: designVariables.contextMenuItemText)
318+
: null,
319+
style: MenuItemButton.styleFrom(
320+
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
321+
foregroundColor: designVariables.contextMenuItemText,
322+
splashFactory: NoSplash.splashFactory,
323+
).copyWith(backgroundColor: WidgetStateColor.resolveWith((states) =>
324+
designVariables.contextMenuItemBg.withFadedAlpha(
325+
states.contains(WidgetState.pressed) ? 0.20 : 0.12))),
326+
onPressed: onPressed,
327+
child: Text(label,
328+
style: const TextStyle(fontSize: 20, height: 24 / 20)
329+
.merge(weightVariableTextStyle(context, wght: 600))));
330+
}
331+
}

0 commit comments

Comments
 (0)