From 461fce17420066bda5781d69a310955ae5ecafef Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Wed, 11 Jan 2023 12:52:38 -0800 Subject: [PATCH 1/8] Add focus detector to CupertinoSwitch --- .../flutter/lib/src/cupertino/switch.dart | 74 +++++++++++++++---- .../flutter/test/cupertino/switch_test.dart | 33 +++++++++ 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 26d86ce8b8424..7c25fc8579fe1 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -178,8 +178,14 @@ class _CupertinoSwitchState extends State with TickerProviderSt late AnimationController _reactionController; late Animation _reaction; + late bool isFocused; + bool get isInteractive => widget.onChanged != null; + late final Map> _actionMap = >{ + ActivateIntent: CallbackAction(onInvoke: _handleTap), + }; + // A non-null boolean value that changes to true at the end of a drag if the // switch must be animated to the position indicated by the widget's value. bool needsPositionAnimation = false; @@ -188,6 +194,8 @@ class _CupertinoSwitchState extends State with TickerProviderSt void initState() { super.initState(); + isFocused = false; + _tap = TapGestureRecognizer() ..onTapDown = _handleTapDown ..onTapUp = _handleTapUp @@ -253,7 +261,7 @@ class _CupertinoSwitchState extends State with TickerProviderSt _reactionController.forward(); } - void _handleTap() { + void _handleTap([Intent? _]) { if (isInteractive) { widget.onChanged!(!widget.value); _emitVibration(); @@ -322,6 +330,10 @@ class _CupertinoSwitchState extends State with TickerProviderSt } } + void _onShowFocusHighlight(bool showHighlight) { + setState(() { isFocused = showHighlight; }); + } + @override Widget build(BuildContext context) { final CupertinoThemeData theme = CupertinoTheme.of(context); @@ -332,19 +344,25 @@ class _CupertinoSwitchState extends State with TickerProviderSt cursor: isInteractive && kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, child: Opacity( opacity: widget.onChanged == null ? _kCupertinoSwitchDisabledOpacity : 1.0, - child: _CupertinoSwitchRenderObjectWidget( - value: widget.value, - activeColor: CupertinoDynamicColor.resolve( - widget.activeColor - ?? ((widget.applyTheme ?? theme.applyThemeToAll) ? theme.primaryColor : null) - ?? CupertinoColors.systemGreen, - context, + child: FocusableActionDetector( + onShowFocusHighlight: _onShowFocusHighlight, + actions: _actionMap, + enabled: isInteractive, + child: _CupertinoSwitchRenderObjectWidget( + value: widget.value, + activeColor: CupertinoDynamicColor.resolve( + widget.activeColor + ?? ((widget.applyTheme ?? theme.applyThemeToAll) ? theme.primaryColor : null) + ?? CupertinoColors.systemGreen, + context, + ), + trackColor: CupertinoDynamicColor.resolve(widget.trackColor ?? CupertinoColors.secondarySystemFill, context), + thumbColor: CupertinoDynamicColor.resolve(widget.thumbColor ?? CupertinoColors.white, context), + onChanged: widget.onChanged, + textDirection: Directionality.of(context), + isFocused: isFocused, + state: this, ), - trackColor: CupertinoDynamicColor.resolve(widget.trackColor ?? CupertinoColors.secondarySystemFill, context), - thumbColor: CupertinoDynamicColor.resolve(widget.thumbColor ?? CupertinoColors.white, context), - onChanged: widget.onChanged, - textDirection: Directionality.of(context), - state: this, ), ), ); @@ -369,6 +387,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { required this.thumbColor, required this.onChanged, required this.textDirection, + required this.isFocused, required this.state, }); @@ -379,6 +398,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { final ValueChanged? onChanged; final _CupertinoSwitchState state; final TextDirection textDirection; + final bool isFocused; @override _RenderCupertinoSwitch createRenderObject(BuildContext context) { @@ -389,6 +409,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { thumbColor: thumbColor, onChanged: onChanged, textDirection: textDirection, + isFocused: isFocused, state: state, ); } @@ -402,7 +423,8 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { ..trackColor = trackColor ..thumbColor = thumbColor ..onChanged = onChanged - ..textDirection = textDirection; + ..textDirection = textDirection + ..isFocused = isFocused; } } @@ -428,6 +450,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { required Color thumbColor, ValueChanged? onChanged, required TextDirection textDirection, + required bool isFocused, required _CupertinoSwitchState state, }) : assert(value != null), assert(activeColor != null), @@ -438,6 +461,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { _thumbPainter = CupertinoThumbPainter.switchThumb(color: thumbColor), _onChanged = onChanged, _textDirection = textDirection, + _isFocused = isFocused, _state = state, super(additionalConstraints: const BoxConstraints.tightFor(width: _kSwitchWidth, height: _kSwitchHeight)) { state.position.addListener(markNeedsPaint); @@ -515,6 +539,17 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { markNeedsPaint(); } + bool get isFocused => _isFocused; + bool _isFocused; + set isFocused(bool value) { + assert(value != null); + if(value == _isFocused) { + return; + } + _isFocused = value; + markNeedsPaint(); + } + bool get isInteractive => onChanged != null; @override @@ -570,6 +605,17 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { final RRect trackRRect = RRect.fromRectAndRadius(trackRect, const Radius.circular(_kTrackRadius)); canvas.drawRRect(trackRRect, paint); + if(_isFocused) { + final RRect borderTrackRRect = trackRRect.inflate(2.5); + + final Paint borderPaint = Paint() + ..color = activeColor + ..style = PaintingStyle.stroke + ..strokeWidth = 4.0; + + canvas.drawRRect(borderTrackRRect, borderPaint); + } + final double currentThumbExtension = CupertinoThumbPainter.extension * currentReactionValue; final double thumbLeft = lerpDouble( trackRect.left + _kTrackInnerStart - CupertinoThumbPainter.radius, diff --git a/packages/flutter/test/cupertino/switch_test.dart b/packages/flutter/test/cupertino/switch_test.dart index 2644de9932680..c32dc69c99528 100644 --- a/packages/flutter/test/cupertino/switch_test.dart +++ b/packages/flutter/test/cupertino/switch_test.dart @@ -48,6 +48,39 @@ void main() { expect(value, isTrue); }); + testWidgets('CupertinoSwitch can be toggled by keyboard shortcuts', (WidgetTester tester) async { + bool value = true; + Widget buildApp({bool enabled = true}) { + return CupertinoApp( + home: CupertinoPageScaffold( + child: Center( + child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { + return CupertinoSwitch( + value: value, + onChanged: enabled ? (bool newValue) { + setState(() { + value = newValue; + }); + } : null, + ); + }), + ), + ), + ); + } + await tester.pumpWidget(buildApp()); + await tester.pumpAndSettle(); + expect(value, isTrue); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pumpAndSettle(); + await tester.sendKeyEvent(LogicalKeyboardKey.space); + await tester.pumpAndSettle(); + expect(value, isFalse); + await tester.sendKeyEvent(LogicalKeyboardKey.space); + await tester.pumpAndSettle(); + expect(value, isTrue); + }); + testWidgets('Switch emits light haptic vibration on tap', (WidgetTester tester) async { final Key switchKey = UniqueKey(); bool value = false; From 3e41bc20e6e30033dd1ddbf884a349f1ca80349f Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Wed, 11 Jan 2023 13:07:26 -0800 Subject: [PATCH 2/8] Add comment --- packages/flutter/lib/src/cupertino/switch.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 7c25fc8579fe1..dbc936549d4e9 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -606,6 +606,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { canvas.drawRRect(trackRRect, paint); if(_isFocused) { + // Paints a border with a slight gap around the switch in the active color. final RRect borderTrackRRect = trackRRect.inflate(2.5); final Paint borderPaint = Paint() From 2c66ee371c16e295a7de06e47d26ec626c818c25 Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Wed, 11 Jan 2023 13:51:47 -0800 Subject: [PATCH 3/8] Remove whitespace --- packages/flutter/lib/src/cupertino/switch.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index dbc936549d4e9..c42fef0a2193c 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -614,7 +614,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { ..style = PaintingStyle.stroke ..strokeWidth = 4.0; - canvas.drawRRect(borderTrackRRect, borderPaint); + canvas.drawRRect(borderTrackRRect, borderPaint); } final double currentThumbExtension = CupertinoThumbPainter.extension * currentReactionValue; From 6435af30f35f39be1dfd96655bade0138d816e88 Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Thu, 12 Jan 2023 11:37:57 -0800 Subject: [PATCH 4/8] Add focusColor constructor to CupertinoSwitch --- .../flutter/lib/src/cupertino/switch.dart | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index c42fef0a2193c..503ac0b7c0d80 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -74,6 +74,7 @@ class CupertinoSwitch extends StatefulWidget { this.trackColor, this.thumbColor, this.applyTheme, + this.focusColor, this.dragStartBehavior = DragStartBehavior.start, }) : assert(value != null), assert(dragStartBehavior != null); @@ -125,6 +126,11 @@ class CupertinoSwitch extends StatefulWidget { /// Defaults to [CupertinoColors.white] when null. final Color? thumbColor; + /// The color to use for the focus highlight for keyboard interactions. + /// + /// Defaults to a a slightly transparent [activeColor]. + final Color? focusColor; + /// {@template flutter.cupertino.CupertinoSwitch.applyTheme} /// Whether to apply the ambient [CupertinoThemeData]. /// @@ -337,6 +343,12 @@ class _CupertinoSwitchState extends State with TickerProviderSt @override Widget build(BuildContext context) { final CupertinoThemeData theme = CupertinoTheme.of(context); + final activeColor = CupertinoDynamicColor.resolve( + widget.activeColor + ?? ((widget.applyTheme ?? theme.applyThemeToAll) ? theme.primaryColor : null) + ?? CupertinoColors.systemGreen, + context, + ); if (needsPositionAnimation) { _resumePositionAnimation(); } @@ -350,14 +362,11 @@ class _CupertinoSwitchState extends State with TickerProviderSt enabled: isInteractive, child: _CupertinoSwitchRenderObjectWidget( value: widget.value, - activeColor: CupertinoDynamicColor.resolve( - widget.activeColor - ?? ((widget.applyTheme ?? theme.applyThemeToAll) ? theme.primaryColor : null) - ?? CupertinoColors.systemGreen, - context, - ), + activeColor: activeColor, trackColor: CupertinoDynamicColor.resolve(widget.trackColor ?? CupertinoColors.secondarySystemFill, context), thumbColor: CupertinoDynamicColor.resolve(widget.thumbColor ?? CupertinoColors.white, context), + // Opacity value was eyeballed by looking at a switch in the macOS settings. + focusColor: CupertinoDynamicColor.resolve(widget.focusColor ?? activeColor.withOpacity(0.7), context), onChanged: widget.onChanged, textDirection: Directionality.of(context), isFocused: isFocused, @@ -385,6 +394,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { required this.activeColor, required this.trackColor, required this.thumbColor, + required this.focusColor, required this.onChanged, required this.textDirection, required this.isFocused, @@ -395,6 +405,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { final Color activeColor; final Color trackColor; final Color thumbColor; + final Color focusColor; final ValueChanged? onChanged; final _CupertinoSwitchState state; final TextDirection textDirection; @@ -407,6 +418,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { activeColor: activeColor, trackColor: trackColor, thumbColor: thumbColor, + focusColor: focusColor, onChanged: onChanged, textDirection: textDirection, isFocused: isFocused, @@ -422,6 +434,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { ..activeColor = activeColor ..trackColor = trackColor ..thumbColor = thumbColor + ..focusColor = focusColor ..onChanged = onChanged ..textDirection = textDirection ..isFocused = isFocused; @@ -448,6 +461,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { required Color activeColor, required Color trackColor, required Color thumbColor, + required Color focusColor, ValueChanged? onChanged, required TextDirection textDirection, required bool isFocused, @@ -458,6 +472,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { _value = value, _activeColor = activeColor, _trackColor = trackColor, + _focusColor = focusColor, _thumbPainter = CupertinoThumbPainter.switchThumb(color: thumbColor), _onChanged = onChanged, _textDirection = textDirection, @@ -514,6 +529,17 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { markNeedsPaint(); } + Color get focusColor => _focusColor; + Color _focusColor; + set focusColor(Color value) { + assert(value != null); + if (value == _focusColor) { + return; + } + _focusColor = value; + markNeedsPaint(); + } + ValueChanged? get onChanged => _onChanged; ValueChanged? _onChanged; set onChanged(ValueChanged? value) { @@ -610,7 +636,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { final RRect borderTrackRRect = trackRRect.inflate(2.5); final Paint borderPaint = Paint() - ..color = activeColor + ..color = focusColor ..style = PaintingStyle.stroke ..strokeWidth = 4.0; From f4e8e4953bbc2d9c4564125025ccf851bf59aef7 Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Tue, 17 Jan 2023 09:18:05 -0800 Subject: [PATCH 5/8] Remove whitespace --- packages/flutter/lib/src/cupertino/switch.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 503ac0b7c0d80..c7b22a0211628 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -127,7 +127,7 @@ class CupertinoSwitch extends StatefulWidget { final Color? thumbColor; /// The color to use for the focus highlight for keyboard interactions. - /// + /// /// Defaults to a a slightly transparent [activeColor]. final Color? focusColor; From 84ae5d3cca1bdaf299da4990c0efdf40fbd1154c Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Tue, 17 Jan 2023 09:27:46 -0800 Subject: [PATCH 6/8] Add color type --- packages/flutter/lib/src/cupertino/switch.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index c7b22a0211628..b3dda10546b47 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -343,7 +343,7 @@ class _CupertinoSwitchState extends State with TickerProviderSt @override Widget build(BuildContext context) { final CupertinoThemeData theme = CupertinoTheme.of(context); - final activeColor = CupertinoDynamicColor.resolve( + final Color activeColor = CupertinoDynamicColor.resolve( widget.activeColor ?? ((widget.applyTheme ?? theme.applyThemeToAll) ? theme.primaryColor : null) ?? CupertinoColors.systemGreen, From 11e30d5e96e43f2992f2efb57e75a99cdb2b37bc Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Tue, 17 Jan 2023 14:37:50 -0800 Subject: [PATCH 7/8] Remove gap in border --- .../windows/flutter/generated_plugins.cmake | 23 +++++++++++++++++++ .../windows/flutter/generated_plugins.cmake | 23 +++++++++++++++++++ .../windows/flutter/generated_plugins.cmake | 23 +++++++++++++++++++ .../flutter/lib/src/cupertino/switch.dart | 4 ++-- 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 dev/benchmarks/complex_layout/windows/flutter/generated_plugins.cmake create mode 100644 examples/flutter_view/windows/flutter/generated_plugins.cmake create mode 100644 examples/platform_view/windows/flutter/generated_plugins.cmake diff --git a/dev/benchmarks/complex_layout/windows/flutter/generated_plugins.cmake b/dev/benchmarks/complex_layout/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000000..b93c4c30c1670 --- /dev/null +++ b/dev/benchmarks/complex_layout/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/examples/flutter_view/windows/flutter/generated_plugins.cmake b/examples/flutter_view/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000000..b93c4c30c1670 --- /dev/null +++ b/examples/flutter_view/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/examples/platform_view/windows/flutter/generated_plugins.cmake b/examples/platform_view/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000000..b93c4c30c1670 --- /dev/null +++ b/examples/platform_view/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index b3dda10546b47..86d5fc5d32177 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -632,8 +632,8 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { canvas.drawRRect(trackRRect, paint); if(_isFocused) { - // Paints a border with a slight gap around the switch in the active color. - final RRect borderTrackRRect = trackRRect.inflate(2.5); + // Paints a border around the switch in the focus color. + final RRect borderTrackRRect = trackRRect.inflate(2.0); final Paint borderPaint = Paint() ..color = focusColor From 250ce4e86bd59005bb71c694cd3bb86155867953 Mon Sep 17 00:00:00 2001 From: Mitchell Goodwin Date: Wed, 18 Jan 2023 13:16:31 -0800 Subject: [PATCH 8/8] Adjust color and line thickness --- packages/flutter/lib/src/cupertino/switch.dart | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 86d5fc5d32177..095a3285aba73 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -365,8 +365,15 @@ class _CupertinoSwitchState extends State with TickerProviderSt activeColor: activeColor, trackColor: CupertinoDynamicColor.resolve(widget.trackColor ?? CupertinoColors.secondarySystemFill, context), thumbColor: CupertinoDynamicColor.resolve(widget.thumbColor ?? CupertinoColors.white, context), - // Opacity value was eyeballed by looking at a switch in the macOS settings. - focusColor: CupertinoDynamicColor.resolve(widget.focusColor ?? activeColor.withOpacity(0.7), context), + // Opacity, lightness, and saturation values were aproximated with + // color pickers on the switches in the macOS settings. + focusColor: CupertinoDynamicColor.resolve( + widget.focusColor ?? + HSLColor + .fromColor(activeColor.withOpacity(0.80)) + .withLightness(0.69).withSaturation(0.835) + .toColor(), + context), onChanged: widget.onChanged, textDirection: Directionality.of(context), isFocused: isFocused, @@ -633,12 +640,12 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { if(_isFocused) { // Paints a border around the switch in the focus color. - final RRect borderTrackRRect = trackRRect.inflate(2.0); + final RRect borderTrackRRect = trackRRect.inflate(1.75); final Paint borderPaint = Paint() ..color = focusColor ..style = PaintingStyle.stroke - ..strokeWidth = 4.0; + ..strokeWidth = 3.5; canvas.drawRRect(borderTrackRRect, borderPaint); }