From 32377e7ed22f555b1c518b7b22c297734d3fa01e Mon Sep 17 00:00:00 2001 From: Lucas Lima Date: Tue, 26 Mar 2024 23:27:50 -0300 Subject: [PATCH] Add custom long tap delay --- .../component_mixins/tap_callbacks.dart | 7 +++++- .../multi_tap_dispatcher.dart | 15 +++++++++---- .../game_mixins/multi_touch_tap_detector.dart | 2 +- .../events/interfaces/multi_tap_listener.dart | 2 +- .../game_widget/gesture_detector_builder.dart | 2 +- .../component_mixins/tap_callbacks_test.dart | 20 +++++++++++++++++ .../multi_touch_tap_detector_test.dart | 22 +++++++++++++++++++ 7 files changed, 62 insertions(+), 8 deletions(-) diff --git a/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart b/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart index 0bb2479ade1..a161a8482ab 100644 --- a/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart +++ b/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart @@ -16,13 +16,18 @@ mixin TapCallbacks on Component { void onTapUp(TapUpEvent event) {} void onTapCancel(TapCancelEvent event) {} + /// The delay (in milliseconds) after which a tap is considered a long tap. + int get longTapDelay => 300; + @override @mustCallSuper void onMount() { super.onMount(); final game = findRootGame()!; if (game.findByKey(const MultiTapDispatcherKey()) == null) { - final dispatcher = MultiTapDispatcher(); + final dispatcher = MultiTapDispatcher( + longTapDelay: longTapDelay, + ); game.registerKey(const MultiTapDispatcherKey(), dispatcher); game.add(dispatcher); } diff --git a/packages/flame/lib/src/events/flame_game_mixins/multi_tap_dispatcher.dart b/packages/flame/lib/src/events/flame_game_mixins/multi_tap_dispatcher.dart index 20c7480e6c8..3cd0105387b 100644 --- a/packages/flame/lib/src/events/flame_game_mixins/multi_tap_dispatcher.dart +++ b/packages/flame/lib/src/events/flame_game_mixins/multi_tap_dispatcher.dart @@ -23,9 +23,16 @@ class MultiTapDispatcherKey implements ComponentKey { @internal class MultiTapDispatcher extends Component implements MultiTapListener { + MultiTapDispatcher({ + int longTapDelay = 300, + }) : _longTapDelay = longTapDelay; + /// The record of all components currently being touched. final Set> _record = {}; + /// The delay (in milliseconds) after which a tap is considered a long tap. + final int _longTapDelay; + FlameGame get game => parent! as FlameGame; /// Called when the user touches the device screen within the game canvas, @@ -50,7 +57,7 @@ class MultiTapDispatcher extends Component implements MultiTapListener { } /// Called after the user has been touching the screen for [longTapDelay] - /// seconds without the tap being cancelled. + /// milliseconds without the tap being cancelled. /// /// This event will be delivered to all the components that previously /// received the `onTapDown` event, and who remain at the point where the user @@ -118,9 +125,9 @@ class MultiTapDispatcher extends Component implements MultiTapListener { //#region MultiTapListener API - /// The delay (in seconds) after which a tap is considered a long tap. + /// The delay (in milliseconds) after which a tap is considered a long tap. @override - double get longTapDelay => 0.300; + int get longTapDelay => _longTapDelay; @override void handleTap(int pointerId) {} @@ -157,7 +164,7 @@ class MultiTapDispatcher extends Component implements MultiTapListener { MultiTapGestureRecognizer.new, (MultiTapGestureRecognizer instance) { instance.longTapDelay = Duration( - milliseconds: (longTapDelay * 1000).toInt(), + milliseconds: longTapDelay, ); instance.onTap = handleTap; instance.onTapDown = handleTapDown; diff --git a/packages/flame/lib/src/events/game_mixins/multi_touch_tap_detector.dart b/packages/flame/lib/src/events/game_mixins/multi_touch_tap_detector.dart index ca510d81629..41e952083cb 100644 --- a/packages/flame/lib/src/events/game_mixins/multi_touch_tap_detector.dart +++ b/packages/flame/lib/src/events/game_mixins/multi_touch_tap_detector.dart @@ -22,7 +22,7 @@ mixin MultiTouchTapDetector on Game implements MultiTapListener { //#region MultiTapListener API @override - double get longTapDelay => 0.300; + int get longTapDelay => 300; @override void handleTap(int pointerId) => onTap(pointerId); diff --git a/packages/flame/lib/src/events/interfaces/multi_tap_listener.dart b/packages/flame/lib/src/events/interfaces/multi_tap_listener.dart index 0ed1cc49d68..2bc3d03116f 100644 --- a/packages/flame/lib/src/events/interfaces/multi_tap_listener.dart +++ b/packages/flame/lib/src/events/interfaces/multi_tap_listener.dart @@ -10,7 +10,7 @@ import 'package:flutter/gestures.dart'; /// - [MultiTouchTapDetector] for a custom `Game` abstract class MultiTapListener { /// The amount of time before the "long tap down" event is triggered. - double get longTapDelay; + int get longTapDelay; /// A tap has occurred. void handleTap(int pointerId); diff --git a/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart b/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart index 1689ef1832f..901fddc2049 100644 --- a/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart +++ b/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart @@ -157,7 +157,7 @@ class GestureDetectorBuilder { (MultiTapGestureRecognizer instance) { final g = game as MultiTapListener; instance.longTapDelay = Duration( - milliseconds: (g.longTapDelay * 1000).toInt(), + milliseconds: g.longTapDelay, ); instance.onTap = g.handleTap; instance.onTapDown = g.handleTapDown; diff --git a/packages/flame/test/events/component_mixins/tap_callbacks_test.dart b/packages/flame/test/events/component_mixins/tap_callbacks_test.dart index 995205a0f82..8051b80121c 100644 --- a/packages/flame/test/events/component_mixins/tap_callbacks_test.dart +++ b/packages/flame/test/events/component_mixins/tap_callbacks_test.dart @@ -134,6 +134,20 @@ void main() { }, ); + testWidgets( + 'TapCallbacks default long tap delay is 300ms', + (tester) async { + expect(_TapCallbacksComponent().longTapDelay, 300); + }, + ); + + testWidgets( + 'Custom TapCallbacks can override default long tap delay', + (tester) async { + expect(_CustomDelayTapCallbacksComponent().longTapDelay, 500); + }, + ); + testWidgets( 'tap outside of component is not registered as handled', (tester) async { @@ -511,4 +525,10 @@ mixin _TapCounter on TapCallbacks { class _TapCallbacksComponent extends PositionComponent with TapCallbacks, _TapCounter {} +class _CustomDelayTapCallbacksComponent extends PositionComponent + with TapCallbacks, _TapCounter { + @override + int get longTapDelay => 500; +} + class _TapCallbacksGame extends FlameGame with TapCallbacks, _TapCounter {} diff --git a/packages/flame/test/events/game_mixins/multi_touch_tap_detector_test.dart b/packages/flame/test/events/game_mixins/multi_touch_tap_detector_test.dart index 06508d670c0..39ee85e9e06 100644 --- a/packages/flame/test/events/game_mixins/multi_touch_tap_detector_test.dart +++ b/packages/flame/test/events/game_mixins/multi_touch_tap_detector_test.dart @@ -84,6 +84,23 @@ void main() { expect(game.nOnTapCancel, 2); }, ); + + test( + 'default longTapDelay is 300ms', + () { + final detector = _GameWithMultiTouchTapDetector(); + expect(detector.longTapDelay, 300); + }, + ); + + test( + 'longTapDelay can be customized', + () { + final detector = _GameWithMultiTouchTapDetector(); + detector.longTapDelayValue = 500; + expect(detector.longTapDelay, 500); + }, + ); }); } @@ -97,6 +114,11 @@ class _GameWithMultiTouchTapDetector extends Game with MultiTouchTapDetector { int nOnTap = 0; int nOnTapCancel = 0; + int? longTapDelayValue; + + @override + int get longTapDelay => longTapDelayValue ?? super.longTapDelay; + @override void render(Canvas canvas) => rendered = true;