Skip to content

Commit 10c647f

Browse files
committed
button: Implement "toggle" component from Figma, for "Invisible mode"
1 parent 2e6c293 commit 10c647f

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

lib/widgets/button.dart

Lines changed: 68 additions & 0 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

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

0 commit comments

Comments
 (0)