Skip to content

Commit 428e97e

Browse files
committed
button: Implement "toggle" component from Figma, for "Invisible mode"
1 parent f5598f5 commit 428e97e

File tree

1 file changed

+67
-2
lines changed

1 file changed

+67
-2
lines changed

lib/widgets/button.dart

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:flutter/material.dart';
22

33
import 'color.dart';
4+
import 'icons.dart';
45
import 'text.dart';
56
import 'theme.dart';
67

@@ -297,8 +298,7 @@ class MenuButton extends StatelessWidget {
297298

298299
/// An element to go before [icon], or in its place if it's null.
299300
///
300-
/// E.g. a switch:
301-
/// https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=6070-60682&m=dev
301+
/// E.g. a [Toggle].
302302
final Widget? beforeIcon;
303303

304304
static double itemSpacing = 16;
@@ -357,3 +357,68 @@ class MenuButton extends StatelessWidget {
357357
));
358358
}
359359
}
360+
361+
/// The "toggle" component in Figma.
362+
///
363+
/// See Figma:
364+
/// https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=6070-60682&m=dev
365+
class Toggle extends StatelessWidget {
366+
const Toggle({
367+
super.key,
368+
required this.value,
369+
required this.onChanged,
370+
});
371+
372+
final bool value;
373+
final ValueChanged<bool> onChanged;
374+
375+
@override
376+
Widget build(BuildContext context) {
377+
// Figma has this (blue/500) in both light and dark mode.
378+
final activeColor = Color(0xff4370f0);
379+
380+
// Figma has this (grey/400) in both light and dark mode.
381+
final inactiveColor = Color(0xff9194a3);
382+
383+
// TODO(#1636):
384+
// All of these just need _SwitchConfig to be exposed,
385+
// and there's an upstream issue for that:
386+
// https://github.com/flutter/flutter/issues/131478
387+
//
388+
// - active thumb radius should be 10px, not 12px
389+
// (_SwitchConfig.thumbRadiusWithIcon)
390+
// - inactive thumb radius should be 7px, not 8px
391+
// (_SwitchConfig.inactiveThumbRadius)
392+
// - track dimensions before trackOutlineWidth should be 24px by 44px,
393+
// not 32px by 52px (_SwitchConfig.trackHeight and trackWidth).
394+
395+
return Switch(
396+
value: value,
397+
onChanged: onChanged,
398+
padding: EdgeInsets.zero,
399+
splashRadius: 0,
400+
thumbIcon: WidgetStateProperty<Icon?>.fromMap({
401+
WidgetState.selected: Icon(ZulipIcons.check, size: 16, color: activeColor),
402+
~WidgetState.selected: null,
403+
}),
404+
405+
// Figma has white for "on" and "off" in both light and dark mode.
406+
thumbColor: WidgetStatePropertyAll(Colors.white),
407+
408+
activeTrackColor: activeColor,
409+
inactiveTrackColor: inactiveColor,
410+
trackOutlineColor: WidgetStateColor.fromMap({
411+
WidgetState.selected: activeColor,
412+
~WidgetState.selected: inactiveColor,
413+
}),
414+
trackOutlineWidth: WidgetStateProperty<double>.fromMap({
415+
// The outline is effectively painted with strokeAlignCenter:
416+
// https://api.flutter.dev/flutter/painting/BorderSide/strokeAlignCenter-constant.html
417+
WidgetState.selected: 2 * 2,
418+
~WidgetState.selected: 1 * 2,
419+
}),
420+
overlayColor: WidgetStatePropertyAll(Colors.transparent),
421+
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
422+
);
423+
}
424+
}

0 commit comments

Comments
 (0)