Skip to content

Commit 9de5e82

Browse files
committed
closes #41
1 parent e0e8898 commit 9de5e82

10 files changed

Lines changed: 119 additions & 47 deletions

example/lib/crazy_switch.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class _CrazySwitchState extends State<CrazySwitch> {
2828
animationDuration: const Duration(milliseconds: 350),
2929
animationCurve: Curves.bounceOut,
3030
iconBuilder: (context, local, global) => const SizedBox(),
31-
onTap: () => setState(() => current = !current),
31+
onTap: (_) => setState(() => current = !current),
3232
iconsTappable: false,
3333
onChanged: (b) => setState(() => current = b),
3434
height: height,

example/lib/main.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,11 @@ class _MyHomePageState extends State<MyHomePage> {
456456
current: nullableValue,
457457
allowUnlistedValues: true,
458458
values: const [0, 1, 2, 3],
459-
onTap: () => setState(() => nullableValue = null),
459+
onTap: (info) {
460+
if (nullableValue == info.tappedValue) {
461+
setState(() => nullableValue = null);
462+
}
463+
},
460464
onChanged: (i) => setState(() => nullableValue = i),
461465
iconBuilder: rollingIconBuilder,
462466
borderWidth: 4.5,
@@ -489,7 +493,7 @@ class _MyHomePageState extends State<MyHomePage> {
489493
return const SizedBox();
490494
},
491495
cursors: ToggleCursors(defaultCursor: SystemMouseCursors.click),
492-
onTap: () => setState(() => positive = !positive),
496+
onTap: (_) => setState(() => positive = !positive),
493497
iconsTappable: false,
494498
wrapperBuilder: (context, global, child) {
495499
return Stack(

lib/src/animations.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
part of 'package:animated_toggle_switch/animated_toggle_switch.dart';
22

3-
// this Animation is not covered because it contains not logic but
3+
// this Animation is not covered because it contains no logic but
44
// forwards all methods to its parent Animation.
55
// coverage:ignore-start
66
/// This class is a proxy for another animation.

lib/src/properties.dart

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
// coverage:ignore-file
22
part of 'package:animated_toggle_switch/animated_toggle_switch.dart';
33

4+
class ValueHolder<T> {
5+
final T value;
6+
7+
/// The index of [value] in [values].
8+
///
9+
/// If [values] does not contain [value], this value is set to [-1].
10+
final int index;
11+
12+
ValueHolder({required this.value, required this.index});
13+
}
14+
415
class GlobalToggleProperties<T> {
516
/// The position of the indicator relative to the indices of the values.
617
final double position;
@@ -13,7 +24,7 @@ class GlobalToggleProperties<T> {
1324

1425
/// The index of [current] in [values].
1526
///
16-
/// If [values] does not contain [current], this value is set to [-1].
27+
/// If [values] does not contain [current], [currentIndex] is set to [-1].
1728
final int currentIndex;
1829

1930
/// This value indicates if [values] does contain [current].
@@ -110,7 +121,7 @@ class LocalToggleProperties<T> {
110121

111122
/// The index of [value].
112123
///
113-
/// If [values] does not contain [value], this value is set to [-1].
124+
/// If [values] does not contain [value], this [index] is set to [-1].
114125
final int index;
115126

116127
/// This value indicates if [values] does contain [value].
@@ -194,3 +205,38 @@ class SeparatorProperties<T> {
194205
required this.index,
195206
});
196207
}
208+
209+
class TapInfo<T> {
210+
/// The value that the user has tapped.
211+
final T? tappedValue;
212+
213+
/// The index of [tappedValue] in [values].
214+
///
215+
/// If [tappedValue] is [null], this [tappedIndex] is set to [-1].
216+
final int tappedIndex;
217+
218+
/// The current value which is given to the switch.
219+
///
220+
/// Helpful if the value is generated e.g.
221+
/// when the switch constructor is called.
222+
final T current;
223+
224+
/// The index of [current] in [values].
225+
///
226+
/// If [values] does not contain [current], this value is set to [-1].
227+
final int currentIndex;
228+
229+
/// The values which are given to the switch.
230+
///
231+
/// Helpful if the list is generated e.g.
232+
/// when the switch constructor is called.
233+
final List<T> values;
234+
235+
const TapInfo({
236+
required this.tappedIndex,
237+
required this.tappedValue,
238+
required this.current,
239+
required this.currentIndex,
240+
required this.values,
241+
});
242+
}

lib/src/widgets/animated_toggle_switch.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
168168
final AnimationType indicatorAnimationType;
169169

170170
/// Callback for tapping anywhere on the widget.
171-
final TapCallback? onTap;
171+
final TapCallback<T>? onTap;
172172

173173
final IconArrangement _iconArrangement;
174174

@@ -864,7 +864,7 @@ class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
864864
this.styleAnimationType = AnimationType.onHover,
865865
this.indicatorAnimationType = AnimationType.onHover,
866866
this.fittingMode = FittingMode.preventHorizontalOverlapping,
867-
Function()? onTap,
867+
TapCallback<T>? onTap,
868868
this.minTouchTargetSize = 48.0,
869869
this.textDirection,
870870
this.cursors = const ToggleCursors(defaultCursor: SystemMouseCursors.click),
@@ -923,9 +923,9 @@ class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
923923
iconList: null,
924924
);
925925

926-
static Function() _dualOnTap<T>(
926+
static TapCallback<T> _dualOnTap<T>(
927927
ChangeCallback<T>? onChanged, List<T> values, T? current) {
928-
return () =>
928+
return (info) =>
929929
onChanged?.call(values.firstWhere((element) => element != current));
930930
}
931931

lib/src/widgets/custom_animated_toggle_switch.dart

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ typedef IndicatorAppearingBuilder = Widget Function(
2626

2727
typedef ChangeCallback<T> = FutureOr<void> Function(T value);
2828

29-
typedef TapCallback = FutureOr<void> Function();
29+
typedef TapCallback<T> = FutureOr<void> Function(TapInfo<T> info);
3030

3131
enum ToggleMode { animating, dragged, none }
3232

@@ -127,7 +127,7 @@ class CustomAnimatedToggleSwitch<T> extends StatefulWidget {
127127
final CustomSeparatorBuilder<T>? separatorBuilder;
128128

129129
/// Callback for tapping anywhere on the widget.
130-
final TapCallback? onTap;
130+
final TapCallback<T>? onTap;
131131

132132
/// Indicates if [onChanged] is called when an icon is tapped.
133133
///
@@ -357,9 +357,9 @@ class _CustomAnimatedToggleSwitchState<T>
357357

358358
/// This method is called in two [GestureDetector]s because only one
359359
/// [GestureDetector.onTapUp] will be triggered.
360-
void _onTap() {
360+
void _onTap(TapInfo<T> info) {
361361
if (!_isActive) return;
362-
final result = widget.onTap?.call();
362+
final result = widget.onTap?.call(info);
363363
if (result is Future) {
364364
_addLoadingFuture(result);
365365
}
@@ -409,12 +409,6 @@ class _CustomAnimatedToggleSwitchState<T>
409409
return _doubleFromPosition(x, properties).round();
410410
}
411411

412-
/// Returns the value by the local position of the cursor.
413-
/// It is mainly intended as a helper function for the build method.
414-
T _valueFromPosition(double x, DetailedGlobalToggleProperties<T> properties) {
415-
return widget.values[_indexFromPosition(x, properties)];
416-
}
417-
418412
@override
419413
Widget build(BuildContext context) {
420414
double spacing = widget.spacing;
@@ -439,7 +433,13 @@ class _CustomAnimatedToggleSwitchState<T>
439433
cursor: defaultCursor,
440434
child: GestureDetector(
441435
behavior: HitTestBehavior.deferToChild,
442-
onTapUp: (_) => _onTap(),
436+
onTapUp: (_) => _onTap(TapInfo(
437+
tappedIndex: -1,
438+
tappedValue: null,
439+
current: widget.current,
440+
currentIndex: _currentIndex,
441+
values: widget.values,
442+
)),
443443
child: TweenAnimationBuilder<double>(
444444
duration:
445445
widget.loadingAnimationDuration ?? widget.animationDuration,
@@ -648,12 +648,20 @@ class _CustomAnimatedToggleSwitchState<T>
648648
behavior: HitTestBehavior.translucent,
649649
dragStartBehavior: DragStartBehavior.down,
650650
onTapUp: (details) {
651-
_onTap();
652-
if (!widget.iconsTappable) return;
653-
T newValue = _valueFromPosition(
651+
int tappedIndex = _indexFromPosition(
654652
details.localPosition.dx, properties);
655-
if (newValue == widget.current) return;
656-
_onChanged(newValue);
653+
T tappedValue =
654+
widget.values[tappedIndex];
655+
_onTap(TapInfo(
656+
tappedIndex: tappedIndex,
657+
tappedValue: tappedValue,
658+
current: widget.current,
659+
currentIndex: _currentIndex,
660+
values: widget.values,
661+
));
662+
if (!widget.iconsTappable) return;
663+
if (tappedValue == widget.current) return;
664+
_onChanged(tappedValue);
657665
},
658666
onHorizontalDragStart: (details) {
659667
if (!isHoveringIndicator(

test/gesture_test.dart

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@ void main() {
2121
onChanged: changedFunction,
2222
),
2323
));
24-
verifyNever(() => tapFunction.call());
24+
verifyNever(() => tapFunction.call(any()));
2525
final currentFinder = find.byKey(iconKey(current));
2626
final nextFinder = find.byKey(iconKey(next));
2727

2828
await tester.tap(currentFinder, warnIfMissed: false);
29-
verify(() => tapFunction()).called(1);
29+
verify(() => tapFunction(any(
30+
that: isA<TapInfo<int>>()
31+
.having((i) => i.tappedValue, 'value', current)))).called(1);
3032

3133
await tester.tap(nextFinder, warnIfMissed: false);
3234
verify(() => changedFunction(next)).called(1);
33-
verify(() => tapFunction()).called(1);
35+
verify(() => tapFunction(any(
36+
that: isA<TapInfo<int>>()
37+
.having((i) => i.tappedValue, 'value', next)))).called(1);
3438

3539
verifyNoMoreInteractions(changedFunction);
3640
}, testDual: false);
@@ -109,15 +113,15 @@ void main() {
109113
iconsTappable: false,
110114
),
111115
));
112-
verifyNever(() => tapFunction.call());
116+
verifyNever(() => tapFunction.call(any()));
113117
final currentFinder = find.byKey(iconKey(current));
114118
final nextFinder = find.byKey(iconKey(next));
115119

116120
await tester.tap(currentFinder, warnIfMissed: false);
117-
verify(() => tapFunction()).called(1);
121+
verify(() => tapFunction(any())).called(1);
118122

119123
await tester.tap(nextFinder, warnIfMissed: false);
120-
verify(() => tapFunction()).called(1);
124+
verify(() => tapFunction(any())).called(1);
121125

122126
verifyNoMoreInteractions(changedFunction);
123127
}, testDual: false);

test/helper.dart

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:async';
33
import 'package:animated_toggle_switch/animated_toggle_switch.dart';
44
import 'package:flutter/material.dart';
55
import 'package:flutter_test/flutter_test.dart';
6+
import 'package:mocktail/mocktail.dart';
67

78
import 'keys.dart';
89

@@ -75,7 +76,7 @@ typedef SwitchBuilder<T> = AnimatedToggleSwitch<T> Function({
7576
List<Widget>? iconList,
7677
TextDirection? textDirection,
7778
ChangeCallback<T>? onChanged,
78-
TapCallback? onTap,
79+
TapCallback<T>? onTap,
7980
bool? loading,
8081
bool allowUnlistedValues,
8182
ToggleStyle? style,
@@ -95,7 +96,7 @@ typedef SimpleSwitchBuilder<T> = AnimatedToggleSwitch<T> Function({
9596
List<Widget>? iconList,
9697
TextDirection? textDirection,
9798
ChangeCallback<T>? onChanged,
98-
TapCallback? onTap,
99+
TapCallback<T>? onTap,
99100
bool? loading,
100101
bool allowUnlistedValues,
101102
ToggleStyle? style,
@@ -122,6 +123,14 @@ void defaultTestAllSwitches(
122123
bool testCustom = true,
123124
bool testSize = true,
124125
}) {
126+
registerFallbackValue(const TapInfo<int>(
127+
tappedIndex: -1,
128+
tappedValue: -1,
129+
current: -1,
130+
currentIndex: -1,
131+
values: [],
132+
));
133+
125134
testAllSwitches<int>(
126135
description,
127136
(tester, buildSwitch, type) => test(
@@ -132,7 +141,7 @@ void defaultTestAllSwitches(
132141
List<Widget>? iconList,
133142
TextDirection? textDirection,
134143
ChangeCallback<int>? onChanged,
135-
TapCallback? onTap,
144+
TapCallback<int>? onTap,
136145
bool? loading,
137146
bool allowUnlistedValues = false,
138147
ToggleStyle? style,
@@ -183,7 +192,7 @@ void defaultTestAllSwitches(
183192
List<Widget>? iconList,
184193
TextDirection? textDirection,
185194
ChangeCallback<int>? onChanged,
186-
TapCallback? onTap,
195+
TapCallback<int>? onTap,
187196
bool? loading,
188197
bool allowUnlistedValues = false,
189198
ToggleStyle? style,
@@ -246,7 +255,7 @@ void testAllSwitches<T>(
246255
List<Widget>? iconList,
247256
TextDirection? textDirection,
248257
ChangeCallback<T>? onChanged,
249-
TapCallback? onTap,
258+
TapCallback<T>? onTap,
250259
bool? loading,
251260
bool allowUnlistedValues = false,
252261
ToggleStyle? style,
@@ -295,7 +304,7 @@ void testAllSwitches<T>(
295304
List<Widget>? iconList,
296305
TextDirection? textDirection,
297306
ChangeCallback<T>? onChanged,
298-
TapCallback? onTap,
307+
TapCallback<T>? onTap,
299308
bool? loading,
300309
bool allowUnlistedValues = false,
301310
ToggleStyle? style,
@@ -348,7 +357,7 @@ void testAllSwitches<T>(
348357
List<Widget>? iconList,
349358
TextDirection? textDirection,
350359
ChangeCallback<T>? onChanged,
351-
TapCallback? onTap,
360+
TapCallback<T>? onTap,
352361
bool? loading,
353362
bool allowUnlistedValues = false,
354363
ToggleStyle? style,
@@ -399,7 +408,7 @@ void testAllSwitches<T>(
399408
List<Widget>? iconList,
400409
TextDirection? textDirection,
401410
ChangeCallback<T>? onChanged,
402-
TapCallback? onTap,
411+
TapCallback<T>? onTap,
403412
bool? loading,
404413
bool allowUnlistedValues = false,
405414
ToggleStyle? style,
@@ -457,7 +466,7 @@ void testAllSwitches<T>(
457466
List<Widget>? iconList,
458467
TextDirection? textDirection,
459468
ChangeCallback<T>? onChanged,
460-
TapCallback? onTap,
469+
TapCallback<T>? onTap,
461470
bool? loading,
462471
bool allowUnlistedValues = false,
463472
ToggleStyle? style,
@@ -507,7 +516,7 @@ void testAllSwitches<T>(
507516
List<Widget>? iconList,
508517
TextDirection? textDirection,
509518
ChangeCallback<T>? onChanged,
510-
TapCallback? onTap,
519+
TapCallback<T>? onTap,
511520
bool? loading,
512521
bool allowUnlistedValues = false,
513522
ToggleStyle? style,

0 commit comments

Comments
 (0)