Skip to content

Commit 9c7abb4

Browse files
committed
✨ Improve LoadSwitch and LoadSwitchController by refining value change handling in callbacks, ensuring onChanged is only called when the value changes, and enhancing tap handling for inactive switches to provide user feedback.
1 parent f83d997 commit 9c7abb4

2 files changed

Lines changed: 27 additions & 7 deletions

File tree

lib/src/load_switch.dart

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class LoadSwitch extends StatefulWidget {
3535
assert(width >= height, "Width can't be less than the height."),
3636
assert(
3737
thumbSizeRatio > 0 && thumbSizeRatio <= 1,
38-
'Thumb size ratio must be between 0 and 1.',
38+
'Thumb size ratio must be greater than 0 and at most 1.',
3939
);
4040

4141
const LoadSwitch.controlled({
@@ -64,7 +64,7 @@ class LoadSwitch extends StatefulWidget {
6464
assert(width >= height, "Width can't be less than the height."),
6565
assert(
6666
thumbSizeRatio > 0 && thumbSizeRatio <= 1,
67-
'Thumb size ratio must be between 0 and 1.',
67+
'Thumb size ratio must be greater than 0 and at most 1.',
6868
);
6969

7070
final _LoadSwitchMode _mode;
@@ -211,7 +211,17 @@ class _LoadSwitchState extends State<LoadSwitch> {
211211

212212
Future<void> _handleToggle() async {
213213
final controller = _controller;
214-
if (_isLoading(controller) || !controller.isActive) {
214+
215+
// Fire onTap whenever the user physically taps the switch, even if it is
216+
// inactive. This allows callers to show feedback (e.g. a tooltip or snackbar)
217+
// explaining why the switch is disabled. Loading is a transient lock — the
218+
// spinner makes it visually obvious, so onTap is suppressed there.
219+
if (!controller.isActive) {
220+
widget.onTap?.call(controller.value);
221+
return;
222+
}
223+
224+
if (_isLoading(controller)) {
215225
return;
216226
}
217227

@@ -241,8 +251,11 @@ class _LoadSwitchState extends State<LoadSwitch> {
241251
if (!_isCurrentOperation(controller, operationId)) {
242252
return;
243253
}
254+
final previousValue = controller.value;
244255
controller.value = nextValue;
245-
widget.onChanged?.call(nextValue);
256+
if (controller.value != previousValue) {
257+
widget.onChanged?.call(nextValue);
258+
}
246259
} catch (error, stackTrace) {
247260
if (_isCurrentOperation(controller, operationId)) {
248261
widget.onError?.call(error, stackTrace);
@@ -317,7 +330,10 @@ class _LoadSwitchState extends State<LoadSwitch> {
317330
child: GestureDetector(
318331
excludeFromSemantics: true,
319332
behavior: HitTestBehavior.opaque,
320-
onTap: isEnabled ? _handleToggle : null,
333+
// Always route taps to _handleToggle so onTap can fire for
334+
// inactive switches (e.g. to show a tooltip). Loading taps are
335+
// still suppressed inside _handleToggle.
336+
onTap: _isLoading(_controller) ? null : _handleToggle,
321337
child: AnimatedContainer(
322338
width: loading ? collapsedWidth : expandedWidth,
323339
height: switchSize,

lib/src/load_switch_controller.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,15 @@ class LoadSwitchController extends ChangeNotifier {
9292
isLoading = true;
9393

9494
try {
95-
value = await onToggle();
95+
final nextValue = await onToggle();
9696
if (_isDisposed) {
9797
return;
9898
}
99-
onChanged?.call(value);
99+
final previousValue = _value;
100+
value = nextValue;
101+
if (!_isDisposed && _value != previousValue) {
102+
onChanged?.call(_value);
103+
}
100104
} catch (error, stackTrace) {
101105
if (_isDisposed) {
102106
return;

0 commit comments

Comments
 (0)