@@ -3,6 +3,45 @@ import 'dart:async';
3
3
import 'package:flutter/material.dart' ;
4
4
5
5
import '../widget_state_controller.dart' ;
6
+ import '../press_event_mix_state.dart' ;
7
+
8
+ abstract interface class WidgetStateHandler {
9
+ @visibleForTesting
10
+ late final MixWidgetStateController controller;
11
+ }
12
+
13
+ mixin HandlePress on WidgetStateHandler {
14
+ int _pressCount = 0 ;
15
+ Timer ? _timer;
16
+
17
+ void pressCallback ();
18
+
19
+ void handlePress ({required bool value, required Duration delay}) {
20
+ controller.pressed = value;
21
+ if (value) {
22
+ _pressCount++ ;
23
+ final initialPressCount = _pressCount;
24
+ _unpressAfterDelay (initialPressCount, delay: delay);
25
+ }
26
+ }
27
+
28
+ void _unpressAfterDelay (int initialPressCount, {required Duration delay}) {
29
+ void unpressCallback () {
30
+ if (controller.pressed && _pressCount == initialPressCount) {
31
+ controller.pressed = false ;
32
+ pressCallback ();
33
+ }
34
+ }
35
+
36
+ _timer? .cancel ();
37
+
38
+ if (delay != Duration .zero) {
39
+ _timer = Timer (delay, unpressCallback);
40
+ } else {
41
+ unpressCallback ();
42
+ }
43
+ }
44
+ }
6
45
7
46
class GestureMixStateWidget extends StatefulWidget {
8
47
const GestureMixStateWidget ({
@@ -83,15 +122,21 @@ class GestureMixStateWidget extends StatefulWidget {
83
122
State createState () => _GestureMixStateWidgetState ();
84
123
}
85
124
86
- class _GestureMixStateWidgetState extends State <GestureMixStateWidget > {
87
- int _pressCount = 0 ;
88
- Timer ? _timer;
89
- late final MixWidgetStateController _controller;
125
+ abstract class _GestureMixStateWidgetStateWithController
126
+ extends State <GestureMixStateWidget > implements WidgetStateHandler {}
127
+
128
+ class _GestureMixStateWidgetState
129
+ extends _GestureMixStateWidgetStateWithController with HandlePress {
130
+ PressEvent _event = PressEvent .idle;
131
+
132
+ @override
133
+ @protected
134
+ late final MixWidgetStateController controller;
90
135
91
136
@override
92
137
void initState () {
93
138
super .initState ();
94
- _controller = widget.controller ?? MixWidgetStateController ();
139
+ controller = widget.controller ?? MixWidgetStateController ();
95
140
}
96
141
97
142
void _onPanUpdate (DragUpdateDetails event) {
@@ -102,42 +147,27 @@ class _GestureMixStateWidgetState extends State<GestureMixStateWidget> {
102
147
widget.onPanDown? .call (details);
103
148
}
104
149
105
- _handlePress (bool value) {
106
- _controller.pressed = value;
107
- if (value) {
108
- _pressCount++ ;
109
- final initialPressCount = _pressCount;
110
- _unpressAfterDelay (initialPressCount);
111
- }
112
- }
113
-
114
150
void _onPanEnd (DragEndDetails details) {
115
- _handlePress ( true );
151
+ handlePress (value : true , delay : widget.unpressDelay );
116
152
widget.onPanEnd? .call (details);
117
153
}
118
154
119
- void _onTapUp (TapUpDetails details) {
120
- _controller.longPressed = false ;
121
- widget.onTapUp? .call (details);
122
- }
123
-
124
- void _onTapCancel () {
125
- _controller.longPressed = false ;
126
- widget.onTapCancel? .call ();
127
- }
128
-
129
155
void _onLongPressStart (LongPressStartDetails details) {
130
- _controller .longPressed = true ;
156
+ controller .longPressed = true ;
131
157
widget.onLongPressStart? .call (details);
132
158
}
133
159
134
160
void _onLongPressEnd (LongPressEndDetails details) {
135
- _controller.longPressed = false ;
161
+ controller.longPressed = false ;
162
+ controller.pressed = false ;
163
+ setState (() {
164
+ _event = PressEvent .idle;
165
+ });
136
166
widget.onLongPressEnd? .call (details);
137
167
}
138
168
139
169
void _onLongPressCancel () {
140
- _controller .longPressed = false ;
170
+ controller .longPressed = false ;
141
171
widget.onLongPressCancel? .call ();
142
172
}
143
173
@@ -149,28 +179,30 @@ class _GestureMixStateWidgetState extends State<GestureMixStateWidget> {
149
179
widget.onPanStart? .call (details);
150
180
}
151
181
152
- void _unpressAfterDelay (int initialPressCount) {
153
- void unpressCallback () {
154
- if (_controller.pressed && _pressCount == initialPressCount) {
155
- _controller.pressed = false ;
156
- }
157
- }
182
+ void _onTap () {
183
+ handlePress (value: true , delay: widget.unpressDelay);
158
184
159
- _timer? .cancel ();
185
+ widget.onTap? .call ();
186
+ if (widget.enableFeedback) Feedback .forTap (context);
187
+ }
160
188
161
- final delay = widget.unpressDelay;
189
+ void _onTapDown (TapDownDetails details) {
190
+ setState (() {
191
+ _event = PressEvent .onTapDown;
192
+ });
193
+ }
162
194
163
- if (delay != Duration .zero) {
164
- _timer = Timer (delay, unpressCallback);
165
- } else {
166
- unpressCallback ();
167
- }
195
+ void _onTapUp (TapUpDetails details) {
196
+ setState (() {
197
+ _event = PressEvent .onTapUp;
198
+ });
199
+ controller.longPressed = false ;
200
+ widget.onTapUp? .call (details);
168
201
}
169
202
170
- void _onTap () {
171
- _handlePress (true );
172
- widget.onTap? .call ();
173
- if (widget.enableFeedback) Feedback .forTap (context);
203
+ void _onTapCancel () {
204
+ controller.longPressed = false ;
205
+ widget.onTapCancel? .call ();
174
206
}
175
207
176
208
void _onLongPress () {
@@ -182,28 +214,40 @@ class _GestureMixStateWidgetState extends State<GestureMixStateWidget> {
182
214
void dispose () {
183
215
_timer? .cancel ();
184
216
// Dispose if being managed internally
185
- if (widget.controller == null ) _controller .dispose ();
217
+ if (widget.controller == null ) controller .dispose ();
186
218
super .dispose ();
187
219
}
188
220
221
+ @override
222
+ void pressCallback () {
223
+ setState (() {
224
+ _event = PressEvent .idle;
225
+ });
226
+ }
227
+
189
228
@override
190
229
Widget build (BuildContext context) {
191
- return GestureDetector (
192
- onTapUp: widget.onTap != null ? _onTapUp : null ,
193
- onTap: widget.onTap != null ? _onTap : null ,
194
- onTapCancel: widget.onTap != null ? _onTapCancel : null ,
195
- onLongPressCancel: widget.onLongPress != null ? _onLongPressCancel : null ,
196
- onLongPress: widget.onLongPress != null ? _onLongPress : null ,
197
- onLongPressStart: widget.onLongPress != null ? _onLongPressStart : null ,
198
- onLongPressEnd: widget.onLongPress != null ? _onLongPressEnd : null ,
199
- onPanDown: widget.onPanDown != null ? _onPanDown : null ,
200
- onPanStart: widget.onPanStart != null ? _onPanStart : null ,
201
- onPanUpdate: widget.onPanUpdate != null ? _onPanUpdate : null ,
202
- onPanEnd: widget.onPanEnd != null ? _onPanEnd : null ,
203
- onPanCancel: widget.onPanCancel != null ? _onPanCancel : null ,
204
- behavior: widget.hitTestBehavior,
205
- excludeFromSemantics: widget.excludeFromSemantics,
206
- child: widget.child,
230
+ return PressEventMixWidgetState (
231
+ _event,
232
+ child: GestureDetector (
233
+ onTapDown: widget.onTap != null ? _onTapDown : null ,
234
+ onTapUp: widget.onTap != null ? _onTapUp : null ,
235
+ onTap: widget.onTap != null ? _onTap : null ,
236
+ onTapCancel: widget.onTap != null ? _onTapCancel : null ,
237
+ onLongPressCancel:
238
+ widget.onLongPress != null ? _onLongPressCancel : null ,
239
+ onLongPress: widget.onLongPress != null ? _onLongPress : null ,
240
+ onLongPressStart: widget.onLongPress != null ? _onLongPressStart : null ,
241
+ onLongPressEnd: widget.onLongPress != null ? _onLongPressEnd : null ,
242
+ onPanDown: widget.onPanDown != null ? _onPanDown : null ,
243
+ onPanStart: widget.onPanStart != null ? _onPanStart : null ,
244
+ onPanUpdate: widget.onPanUpdate != null ? _onPanUpdate : null ,
245
+ onPanEnd: widget.onPanEnd != null ? _onPanEnd : null ,
246
+ onPanCancel: widget.onPanCancel != null ? _onPanCancel : null ,
247
+ behavior: widget.hitTestBehavior,
248
+ excludeFromSemantics: widget.excludeFromSemantics,
249
+ child: widget.child,
250
+ ),
207
251
);
208
252
}
209
253
}
0 commit comments