|
1 | 1 | import 'package:flutter/material.dart'; |
2 | 2 |
|
| 3 | +import 'package:mix/mix.dart'; |
| 4 | +import 'package:moon_core/moon_core.dart'; |
| 5 | + |
3 | 6 | import 'package:moon_design/src/theme/effects/effects_theme.dart'; |
| 7 | +import 'package:moon_design/src/theme/effects/focus_effect.dart'; |
4 | 8 | import 'package:moon_design/src/theme/theme.dart'; |
5 | 9 | import 'package:moon_design/src/theme/tokens/opacities.dart'; |
6 | 10 | import 'package:moon_design/src/theme/tokens/tokens.dart'; |
7 | | -import 'package:moon_design/src/utils/touch_target_padding.dart'; |
8 | | -import 'package:moon_design/src/widgets/common/effects/focus_effect.dart'; |
9 | | -import 'package:moon_design/src/widgets/radio/radio_painter.dart'; |
| 11 | + |
10 | 12 | import 'package:moon_tokens/moon_tokens.dart'; |
11 | 13 |
|
12 | 14 | class MoonRadio<T> extends StatefulWidget { |
@@ -86,128 +88,105 @@ class MoonRadio<T> extends StatefulWidget { |
86 | 88 | required this.onChanged, |
87 | 89 | }); |
88 | 90 |
|
89 | | - bool get _selected => value == groupValue; |
90 | | - |
91 | 91 | @override |
92 | 92 | State<MoonRadio<T>> createState() => _RadioState<T>(); |
93 | 93 | } |
94 | 94 |
|
95 | | -class _RadioState<T> extends State<MoonRadio<T>> |
96 | | - with TickerProviderStateMixin, ToggleableStateMixin { |
97 | | - final MoonRadioPainter _painter = MoonRadioPainter(); |
98 | | - |
99 | | - void _handleChanged(bool? selected) { |
100 | | - if (selected == null) { |
101 | | - widget.onChanged!(null); |
102 | | - |
103 | | - return; |
104 | | - } |
105 | | - if (selected) { |
106 | | - widget.onChanged!(widget.value); |
107 | | - } |
108 | | - } |
| 95 | +class _RadioState<T> extends State<MoonRadio<T>> { |
| 96 | + bool get _selected => widget.value == widget.groupValue; |
| 97 | + |
| 98 | + ShapeDecorationWithPremultipliedAlpha _getFocusDecoration( |
| 99 | + double width, |
| 100 | + Color color, |
| 101 | + ) => |
| 102 | + ShapeDecorationWithPremultipliedAlpha( |
| 103 | + shape: CircleBorder( |
| 104 | + side: BorderSide( |
| 105 | + width: width, |
| 106 | + color: color, |
| 107 | + strokeAlign: BorderSide.strokeAlignOutside, |
| 108 | + ), |
| 109 | + ), |
| 110 | + ); |
109 | 111 |
|
110 | 112 | @override |
111 | | - void didUpdateWidget(MoonRadio<T> oldWidget) { |
112 | | - super.didUpdateWidget(oldWidget); |
| 113 | + Widget build(BuildContext context) { |
| 114 | + const double sizeValue = 16; |
| 115 | + const double dotSizeValue = (sizeValue - 1) / 2; |
113 | 116 |
|
114 | | - if (widget._selected != oldWidget._selected) animateToValue(); |
115 | | - } |
| 117 | + final MoonFocusEffect focusEffect = |
| 118 | + MoonEffectsTheme(tokens: MoonTokens.light).controlFocusEffect; |
116 | 119 |
|
117 | | - @override |
118 | | - void dispose() { |
119 | | - _painter.dispose(); |
| 120 | + final Color effectiveActiveColor = |
| 121 | + widget.activeColor ?? MoonColors.light.piccolo; |
120 | 122 |
|
121 | | - super.dispose(); |
122 | | - } |
| 123 | + final Color effectiveInactiveColor = |
| 124 | + widget.inactiveColor ?? MoonColors.light.trunks; |
123 | 125 |
|
124 | | - @override |
125 | | - ValueChanged<bool?>? get onChanged => |
126 | | - widget.onChanged != null ? _handleChanged : null; |
| 126 | + final Color effectiveFocusEffectColor = focusEffect.effectColor; |
127 | 127 |
|
128 | | - @override |
129 | | - bool get tristate => widget.toggleable; |
| 128 | + final double effectiveFocusEffectExtent = focusEffect.effectExtent; |
130 | 129 |
|
131 | | - @override |
132 | | - bool? get value => widget._selected; |
| 130 | + final Duration effectiveFocusEffectDuration = focusEffect.effectDuration; |
133 | 131 |
|
134 | | - @override |
135 | | - Widget build(BuildContext context) { |
136 | | - const Size size = Size(16, 16); |
137 | | - |
138 | | - final Color effectiveActiveColor = widget.activeColor ?? |
139 | | - context.moonTheme?.radioTheme.colors.activeColor ?? |
140 | | - MoonColors.light.piccolo; |
141 | | - |
142 | | - final Color effectiveInactiveColor = widget.inactiveColor ?? |
143 | | - context.moonTheme?.radioTheme.colors.inactiveColor ?? |
144 | | - MoonColors.light.trunks; |
145 | | - |
146 | | - final Color effectiveFocusEffectColor = |
147 | | - context.moonEffects?.controlFocusEffect.effectColor ?? |
148 | | - MoonEffectsTheme(tokens: MoonTokens.light) |
149 | | - .controlFocusEffect |
150 | | - .effectColor; |
151 | | - |
152 | | - final double effectiveFocusEffectExtent = |
153 | | - context.moonEffects?.controlFocusEffect.effectExtent ?? |
154 | | - MoonEffectsTheme(tokens: MoonTokens.light) |
155 | | - .controlFocusEffect |
156 | | - .effectExtent; |
157 | | - |
158 | | - final Duration effectiveFocusEffectDuration = |
159 | | - context.moonEffects?.controlFocusEffect.effectDuration ?? |
160 | | - MoonEffectsTheme(tokens: MoonTokens.light) |
161 | | - .controlFocusEffect |
162 | | - .effectDuration; |
163 | | - |
164 | | - final Curve effectiveFocusEffectCurve = |
165 | | - context.moonEffects?.controlFocusEffect.effectCurve ?? |
166 | | - MoonEffectsTheme(tokens: MoonTokens.light) |
167 | | - .controlFocusEffect |
168 | | - .effectCurve; |
| 132 | + final Curve effectiveFocusEffectCurve = focusEffect.effectCurve; |
169 | 133 |
|
170 | 134 | final double effectiveDisabledOpacityValue = |
171 | 135 | context.moonOpacities?.disabled ?? MoonOpacities.opacities.disabled; |
172 | 136 |
|
173 | | - final WidgetStateProperty<MouseCursor> effectiveMouseCursor = |
174 | | - WidgetStateProperty.resolveWith<MouseCursor>((Set<WidgetState> states) { |
175 | | - return WidgetStateMouseCursor.clickable.resolve(states); |
176 | | - }); |
177 | | - |
178 | | - return Semantics( |
179 | | - label: widget.semanticLabel, |
180 | | - inMutuallyExclusiveGroup: true, |
181 | | - checked: widget._selected, |
182 | | - child: TouchTargetPadding( |
183 | | - minSize: Size(widget.tapAreaSizeValue, widget.tapAreaSizeValue), |
184 | | - child: MoonFocusEffect( |
185 | | - show: states.contains(WidgetState.focused), |
186 | | - effectExtent: effectiveFocusEffectExtent, |
187 | | - childBorderRadius: BorderRadius.circular(8), |
188 | | - effectColor: effectiveFocusEffectColor, |
189 | | - effectCurve: effectiveFocusEffectCurve, |
190 | | - effectDuration: effectiveFocusEffectDuration, |
191 | | - child: RepaintBoundary( |
192 | | - child: AnimatedOpacity( |
193 | | - opacity: states.contains(WidgetState.disabled) |
194 | | - ? effectiveDisabledOpacityValue |
195 | | - : 1, |
196 | | - duration: effectiveFocusEffectDuration, |
197 | | - child: buildToggleable( |
198 | | - focusNode: widget.focusNode, |
199 | | - autofocus: widget.autofocus, |
200 | | - mouseCursor: effectiveMouseCursor, |
201 | | - size: size, |
202 | | - painter: _painter |
203 | | - ..position = position |
204 | | - ..activeColor = effectiveActiveColor |
205 | | - ..inactiveColor = effectiveInactiveColor, |
206 | | - ), |
207 | | - ), |
| 137 | + final Style dotStyle = Style( |
| 138 | + $box.chain |
| 139 | + ..width(_selected ? dotSizeValue : 0) |
| 140 | + ..height(_selected ? dotSizeValue : 0) |
| 141 | + ..color(effectiveActiveColor) |
| 142 | + ..shape.circle(), |
| 143 | + ).animate(duration: effectiveFocusEffectDuration); |
| 144 | + |
| 145 | + final Style baseStyle = Style( |
| 146 | + $box.chain |
| 147 | + ..height(sizeValue) |
| 148 | + ..width(sizeValue) |
| 149 | + ..border |
| 150 | + .color(_selected ? effectiveActiveColor : effectiveInactiveColor) |
| 151 | + ..alignment.center() |
| 152 | + ..shape.circle(), |
| 153 | + ).animate(duration: effectiveFocusEffectDuration); |
| 154 | + |
| 155 | + final Style effectsStyle = Style( |
| 156 | + $box.shapeDecoration.as(_getFocusDecoration(0, Colors.transparent)), |
| 157 | + $with.animatedOpacity( |
| 158 | + opacity: widget.onChanged == null ? effectiveDisabledOpacityValue : 1, |
| 159 | + duration: effectiveFocusEffectDuration, |
| 160 | + ), |
| 161 | + $on.focus( |
| 162 | + $box.shapeDecoration.as( |
| 163 | + _getFocusDecoration( |
| 164 | + effectiveFocusEffectExtent, |
| 165 | + effectiveFocusEffectColor, |
208 | 166 | ), |
209 | 167 | ), |
210 | 168 | ), |
| 169 | + ).animate( |
| 170 | + duration: effectiveFocusEffectDuration, |
| 171 | + curve: effectiveFocusEffectCurve, |
| 172 | + ); |
| 173 | + |
| 174 | + return MoonBaseSingleSelectWidget( |
| 175 | + value: widget.value, |
| 176 | + groupValue: widget.groupValue, |
| 177 | + toggleable: widget.toggleable, |
| 178 | + focusNode: widget.focusNode, |
| 179 | + autofocus: widget.autofocus, |
| 180 | + semanticLabel: widget.semanticLabel, |
| 181 | + tapAreaSizeValue: widget.tapAreaSizeValue, |
| 182 | + style: effectsStyle, |
| 183 | + onChanged: widget.onChanged, |
| 184 | + child: Box( |
| 185 | + style: baseStyle, |
| 186 | + child: Box( |
| 187 | + style: dotStyle, |
| 188 | + ), |
| 189 | + ), |
211 | 190 | ); |
212 | 191 | } |
213 | 192 | } |
0 commit comments