@@ -3,6 +3,45 @@ import 'dart:async';
33import 'package:flutter/material.dart' ;
44
55import '../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+ }
645
746class GestureMixStateWidget extends StatefulWidget {
847 const GestureMixStateWidget ({
@@ -83,15 +122,21 @@ class GestureMixStateWidget extends StatefulWidget {
83122 State createState () => _GestureMixStateWidgetState ();
84123}
85124
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;
90135
91136 @override
92137 void initState () {
93138 super .initState ();
94- _controller = widget.controller ?? MixWidgetStateController ();
139+ controller = widget.controller ?? MixWidgetStateController ();
95140 }
96141
97142 void _onPanUpdate (DragUpdateDetails event) {
@@ -102,42 +147,27 @@ class _GestureMixStateWidgetState extends State<GestureMixStateWidget> {
102147 widget.onPanDown? .call (details);
103148 }
104149
105- _handlePress (bool value) {
106- _controller.pressed = value;
107- if (value) {
108- _pressCount++ ;
109- final initialPressCount = _pressCount;
110- _unpressAfterDelay (initialPressCount);
111- }
112- }
113-
114150 void _onPanEnd (DragEndDetails details) {
115- _handlePress ( true );
151+ handlePress (value : true , delay : widget.unpressDelay );
116152 widget.onPanEnd? .call (details);
117153 }
118154
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-
129155 void _onLongPressStart (LongPressStartDetails details) {
130- _controller .longPressed = true ;
156+ controller .longPressed = true ;
131157 widget.onLongPressStart? .call (details);
132158 }
133159
134160 void _onLongPressEnd (LongPressEndDetails details) {
135- _controller.longPressed = false ;
161+ controller.longPressed = false ;
162+ controller.pressed = false ;
163+ setState (() {
164+ _event = PressEvent .idle;
165+ });
136166 widget.onLongPressEnd? .call (details);
137167 }
138168
139169 void _onLongPressCancel () {
140- _controller .longPressed = false ;
170+ controller .longPressed = false ;
141171 widget.onLongPressCancel? .call ();
142172 }
143173
@@ -149,28 +179,30 @@ class _GestureMixStateWidgetState extends State<GestureMixStateWidget> {
149179 widget.onPanStart? .call (details);
150180 }
151181
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);
158184
159- _timer? .cancel ();
185+ widget.onTap? .call ();
186+ if (widget.enableFeedback) Feedback .forTap (context);
187+ }
160188
161- final delay = widget.unpressDelay;
189+ void _onTapDown (TapDownDetails details) {
190+ setState (() {
191+ _event = PressEvent .onTapDown;
192+ });
193+ }
162194
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);
168201 }
169202
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 ();
174206 }
175207
176208 void _onLongPress () {
@@ -182,28 +214,40 @@ class _GestureMixStateWidgetState extends State<GestureMixStateWidget> {
182214 void dispose () {
183215 _timer? .cancel ();
184216 // Dispose if being managed internally
185- if (widget.controller == null ) _controller .dispose ();
217+ if (widget.controller == null ) controller .dispose ();
186218 super .dispose ();
187219 }
188220
221+ @override
222+ void pressCallback () {
223+ setState (() {
224+ _event = PressEvent .idle;
225+ });
226+ }
227+
189228 @override
190229 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+ ),
207251 );
208252 }
209253}
0 commit comments