Make TapTracker and TapGesture private classes
We don't want to expose these from the gesture package. This patch moves DoubleTapGestureRecognizer into tap.dart so we can make TapTracker and TapGesture private to that file.
This commit is contained in:
@@ -8,7 +8,6 @@ library gestures;
|
||||
export 'src/gestures/arena.dart';
|
||||
export 'src/gestures/constants.dart';
|
||||
export 'src/gestures/drag.dart';
|
||||
export 'src/gestures/double_tap.dart';
|
||||
export 'src/gestures/events.dart';
|
||||
export 'src/gestures/long_press.dart';
|
||||
export 'src/gestures/pointer_router.dart';
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'arena.dart';
|
||||
import 'constants.dart';
|
||||
import 'events.dart';
|
||||
import 'recognizer.dart';
|
||||
import 'tap.dart';
|
||||
|
||||
class DoubleTapGestureRecognizer extends DisposableArenaMember {
|
||||
|
||||
DoubleTapGestureRecognizer({ this.router, this.onDoubleTap });
|
||||
|
||||
// Implementation notes:
|
||||
// The double tap recognizer can be in one of four states. There's no
|
||||
// explicit enum for the states, because they are already captured by
|
||||
// the state of existing fields. Specifically:
|
||||
// Waiting on first tap: In this state, the _trackers list is empty, and
|
||||
// _firstTap is null.
|
||||
// First tap in progress: In this state, the _trackers list contains all
|
||||
// the states for taps that have begun but not completed. This list can
|
||||
// have more than one entry if two pointers begin to tap.
|
||||
// Waiting on second tap: In this state, one of the in-progress taps has
|
||||
// completed successfully. The _trackers list is again empty, and
|
||||
// _firstTap records the successful tap.
|
||||
// Second tap in progress: Much like the "first tap in progress" state, but
|
||||
// _firstTap is non-null. If a tap completes successfully while in this
|
||||
// state, the callback is invoked and the state is reset.
|
||||
// There are various other scenarios that cause the state to reset:
|
||||
// - All in-progress taps are rejected (by time, distance, pointercancel, etc)
|
||||
// - The long timer between taps expires
|
||||
// - The gesture arena decides we have been rejected wholesale
|
||||
|
||||
PointerRouter router;
|
||||
GestureTapCallback onDoubleTap;
|
||||
|
||||
Timer _doubleTapTimer;
|
||||
TapTracker _firstTap;
|
||||
final Map<int, TapTracker> _trackers = new Map<int, TapTracker>();
|
||||
|
||||
void addPointer(PointerInputEvent event) {
|
||||
// Ignore out-of-bounds second taps
|
||||
if (_firstTap != null &&
|
||||
!_firstTap.isWithinTolerance(event, kDoubleTapTouchSlop))
|
||||
return;
|
||||
_stopDoubleTapTimer();
|
||||
TapTracker tracker = new TapTracker(
|
||||
event: event,
|
||||
entry: GestureArena.instance.add(event.pointer, this)
|
||||
);
|
||||
_trackers[event.pointer] = tracker;
|
||||
tracker.startTrackingPointer(router, handleEvent);
|
||||
}
|
||||
|
||||
void handleEvent(PointerInputEvent event) {
|
||||
TapTracker tracker = _trackers[event.pointer];
|
||||
assert(tracker != null);
|
||||
if (event.type == 'pointerup') {
|
||||
if (_firstTap == null)
|
||||
_registerFirstTap(tracker);
|
||||
else
|
||||
_registerSecondTap(tracker);
|
||||
} else if (event.type == 'pointermove' &&
|
||||
!tracker.isWithinTolerance(event, kTouchSlop)) {
|
||||
_reject(tracker);
|
||||
} else if (event.type == 'pointercancel') {
|
||||
_reject(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
void acceptGesture(int pointer) {}
|
||||
|
||||
void rejectGesture(int pointer) {
|
||||
TapTracker tracker = _trackers[pointer];
|
||||
// If tracker isn't in the list, check if this is the first tap tracker
|
||||
if (tracker == null &&
|
||||
_firstTap != null &&
|
||||
_firstTap.pointer == pointer)
|
||||
tracker = _firstTap;
|
||||
// If tracker is still null, we rejected ourselves already
|
||||
if (tracker != null)
|
||||
_reject(tracker);
|
||||
}
|
||||
|
||||
void _reject(TapTracker tracker) {
|
||||
_trackers.remove(tracker.pointer);
|
||||
tracker.entry.resolve(GestureDisposition.rejected);
|
||||
_freezeTracker(tracker);
|
||||
// If the first tap is in progress, and we've run out of taps to track,
|
||||
// reset won't have any work to do. But if we're in the second tap, we need
|
||||
// to clear intermediate state.
|
||||
if (_firstTap != null &&
|
||||
(_trackers.isEmpty || tracker == _firstTap))
|
||||
_reset();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_reset();
|
||||
router = null;
|
||||
}
|
||||
|
||||
void _reset() {
|
||||
_stopDoubleTapTimer();
|
||||
if (_firstTap != null) {
|
||||
// Note, order is important below in order for the resolve -> reject logic
|
||||
// to work properly
|
||||
TapTracker tracker = _firstTap;
|
||||
_firstTap = null;
|
||||
_reject(tracker);
|
||||
GestureArena.instance.release(tracker.pointer);
|
||||
}
|
||||
_clearTrackers();
|
||||
}
|
||||
|
||||
void _registerFirstTap(TapTracker tracker) {
|
||||
_startDoubleTapTimer();
|
||||
GestureArena.instance.hold(tracker.pointer);
|
||||
// Note, order is important below in order for the clear -> reject logic to
|
||||
// work properly.
|
||||
_freezeTracker(tracker);
|
||||
_trackers.remove(tracker.pointer);
|
||||
_clearTrackers();
|
||||
_firstTap = tracker;
|
||||
}
|
||||
|
||||
void _registerSecondTap(TapTracker tracker) {
|
||||
_firstTap.entry.resolve(GestureDisposition.accepted);
|
||||
tracker.entry.resolve(GestureDisposition.accepted);
|
||||
_freezeTracker(tracker);
|
||||
_trackers.remove(tracker.pointer);
|
||||
if (onDoubleTap != null)
|
||||
onDoubleTap();
|
||||
_reset();
|
||||
}
|
||||
|
||||
void _clearTrackers() {
|
||||
List<TapTracker> localTrackers = new List<TapTracker>.from(_trackers.values);
|
||||
for (TapTracker tracker in localTrackers)
|
||||
_reject(tracker);
|
||||
assert(_trackers.isEmpty);
|
||||
}
|
||||
|
||||
void _freezeTracker(TapTracker tracker) {
|
||||
tracker.stopTrackingPointer(router, handleEvent);
|
||||
}
|
||||
|
||||
void _startDoubleTapTimer() {
|
||||
_doubleTapTimer ??= new Timer(kDoubleTapTimeout, () => _reset());
|
||||
}
|
||||
|
||||
void _stopDoubleTapTimer() {
|
||||
if (_doubleTapTimer != null) {
|
||||
_doubleTapTimer.cancel();
|
||||
_doubleTapTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'arena.dart';
|
||||
@@ -66,9 +67,9 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
|
||||
/// TapTracker helps track individual tap sequences as part of a
|
||||
/// larger gesture.
|
||||
class TapTracker {
|
||||
class _TapTracker {
|
||||
|
||||
TapTracker({ PointerInputEvent event, this.entry })
|
||||
_TapTracker({ PointerInputEvent event, this.entry })
|
||||
: pointer = event.pointer,
|
||||
_initialPosition = event.position,
|
||||
_isTrackingPointer = false {
|
||||
@@ -109,9 +110,9 @@ enum TapResolution {
|
||||
/// TapGesture represents a full gesture resulting from a single tap
|
||||
/// sequence. Tap gestures are passive, meaning that they will not
|
||||
/// pre-empt any other arena member in play.
|
||||
class TapGesture extends TapTracker {
|
||||
class _TapGesture extends _TapTracker {
|
||||
|
||||
TapGesture({ this.gestureRecognizer, PointerInputEvent event })
|
||||
_TapGesture({ this.gestureRecognizer, PointerInputEvent event })
|
||||
: super(event: event) {
|
||||
entry = GestureArena.instance.add(event.pointer, gestureRecognizer);
|
||||
_wonArena = false;
|
||||
@@ -175,11 +176,11 @@ class MultiTapGestureRecognizer extends DisposableArenaMember {
|
||||
GestureTapCallback onTapDown;
|
||||
GestureTapCallback onTapCancel;
|
||||
|
||||
Map<int, TapGesture> _gestureMap = new Map<int, TapGesture>();
|
||||
Map<int, _TapGesture> _gestureMap = new Map<int, _TapGesture>();
|
||||
|
||||
void addPointer(PointerInputEvent event) {
|
||||
assert(!_gestureMap.containsKey(event.pointer));
|
||||
_gestureMap[event.pointer] = new TapGesture(
|
||||
_gestureMap[event.pointer] = new _TapGesture(
|
||||
gestureRecognizer: this,
|
||||
event: event
|
||||
);
|
||||
@@ -209,8 +210,8 @@ class MultiTapGestureRecognizer extends DisposableArenaMember {
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
List<TapGesture> localGestures = new List<TapGesture>.from(_gestureMap.values);
|
||||
for (TapGesture gesture in localGestures)
|
||||
List<_TapGesture> localGestures = new List<_TapGesture>.from(_gestureMap.values);
|
||||
for (_TapGesture gesture in localGestures)
|
||||
gesture.cancel();
|
||||
// Rejection of each gesture should cause it to be removed from our map
|
||||
assert(_gestureMap.isEmpty);
|
||||
@@ -218,3 +219,153 @@ class MultiTapGestureRecognizer extends DisposableArenaMember {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DoubleTapGestureRecognizer extends DisposableArenaMember {
|
||||
|
||||
DoubleTapGestureRecognizer({ this.router, this.onDoubleTap });
|
||||
|
||||
// Implementation notes:
|
||||
// The double tap recognizer can be in one of four states. There's no
|
||||
// explicit enum for the states, because they are already captured by
|
||||
// the state of existing fields. Specifically:
|
||||
// Waiting on first tap: In this state, the _trackers list is empty, and
|
||||
// _firstTap is null.
|
||||
// First tap in progress: In this state, the _trackers list contains all
|
||||
// the states for taps that have begun but not completed. This list can
|
||||
// have more than one entry if two pointers begin to tap.
|
||||
// Waiting on second tap: In this state, one of the in-progress taps has
|
||||
// completed successfully. The _trackers list is again empty, and
|
||||
// _firstTap records the successful tap.
|
||||
// Second tap in progress: Much like the "first tap in progress" state, but
|
||||
// _firstTap is non-null. If a tap completes successfully while in this
|
||||
// state, the callback is invoked and the state is reset.
|
||||
// There are various other scenarios that cause the state to reset:
|
||||
// - All in-progress taps are rejected (by time, distance, pointercancel, etc)
|
||||
// - The long timer between taps expires
|
||||
// - The gesture arena decides we have been rejected wholesale
|
||||
|
||||
PointerRouter router;
|
||||
GestureTapCallback onDoubleTap;
|
||||
|
||||
Timer _doubleTapTimer;
|
||||
_TapTracker _firstTap;
|
||||
final Map<int, _TapTracker> _trackers = new Map<int, _TapTracker>();
|
||||
|
||||
void addPointer(PointerInputEvent event) {
|
||||
// Ignore out-of-bounds second taps
|
||||
if (_firstTap != null &&
|
||||
!_firstTap.isWithinTolerance(event, kDoubleTapTouchSlop))
|
||||
return;
|
||||
_stopDoubleTapTimer();
|
||||
_TapTracker tracker = new _TapTracker(
|
||||
event: event,
|
||||
entry: GestureArena.instance.add(event.pointer, this)
|
||||
);
|
||||
_trackers[event.pointer] = tracker;
|
||||
tracker.startTrackingPointer(router, handleEvent);
|
||||
}
|
||||
|
||||
void handleEvent(PointerInputEvent event) {
|
||||
_TapTracker tracker = _trackers[event.pointer];
|
||||
assert(tracker != null);
|
||||
if (event.type == 'pointerup') {
|
||||
if (_firstTap == null)
|
||||
_registerFirstTap(tracker);
|
||||
else
|
||||
_registerSecondTap(tracker);
|
||||
} else if (event.type == 'pointermove' &&
|
||||
!tracker.isWithinTolerance(event, kTouchSlop)) {
|
||||
_reject(tracker);
|
||||
} else if (event.type == 'pointercancel') {
|
||||
_reject(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
void acceptGesture(int pointer) {}
|
||||
|
||||
void rejectGesture(int pointer) {
|
||||
_TapTracker tracker = _trackers[pointer];
|
||||
// If tracker isn't in the list, check if this is the first tap tracker
|
||||
if (tracker == null &&
|
||||
_firstTap != null &&
|
||||
_firstTap.pointer == pointer)
|
||||
tracker = _firstTap;
|
||||
// If tracker is still null, we rejected ourselves already
|
||||
if (tracker != null)
|
||||
_reject(tracker);
|
||||
}
|
||||
|
||||
void _reject(_TapTracker tracker) {
|
||||
_trackers.remove(tracker.pointer);
|
||||
tracker.entry.resolve(GestureDisposition.rejected);
|
||||
_freezeTracker(tracker);
|
||||
// If the first tap is in progress, and we've run out of taps to track,
|
||||
// reset won't have any work to do. But if we're in the second tap, we need
|
||||
// to clear intermediate state.
|
||||
if (_firstTap != null &&
|
||||
(_trackers.isEmpty || tracker == _firstTap))
|
||||
_reset();
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_reset();
|
||||
router = null;
|
||||
}
|
||||
|
||||
void _reset() {
|
||||
_stopDoubleTapTimer();
|
||||
if (_firstTap != null) {
|
||||
// Note, order is important below in order for the resolve -> reject logic
|
||||
// to work properly
|
||||
_TapTracker tracker = _firstTap;
|
||||
_firstTap = null;
|
||||
_reject(tracker);
|
||||
GestureArena.instance.release(tracker.pointer);
|
||||
}
|
||||
_clearTrackers();
|
||||
}
|
||||
|
||||
void _registerFirstTap(_TapTracker tracker) {
|
||||
_startDoubleTapTimer();
|
||||
GestureArena.instance.hold(tracker.pointer);
|
||||
// Note, order is important below in order for the clear -> reject logic to
|
||||
// work properly.
|
||||
_freezeTracker(tracker);
|
||||
_trackers.remove(tracker.pointer);
|
||||
_clearTrackers();
|
||||
_firstTap = tracker;
|
||||
}
|
||||
|
||||
void _registerSecondTap(_TapTracker tracker) {
|
||||
_firstTap.entry.resolve(GestureDisposition.accepted);
|
||||
tracker.entry.resolve(GestureDisposition.accepted);
|
||||
_freezeTracker(tracker);
|
||||
_trackers.remove(tracker.pointer);
|
||||
if (onDoubleTap != null)
|
||||
onDoubleTap();
|
||||
_reset();
|
||||
}
|
||||
|
||||
void _clearTrackers() {
|
||||
List<_TapTracker> localTrackers = new List<_TapTracker>.from(_trackers.values);
|
||||
for (_TapTracker tracker in localTrackers)
|
||||
_reject(tracker);
|
||||
assert(_trackers.isEmpty);
|
||||
}
|
||||
|
||||
void _freezeTracker(_TapTracker tracker) {
|
||||
tracker.stopTrackingPointer(router, handleEvent);
|
||||
}
|
||||
|
||||
void _startDoubleTapTimer() {
|
||||
_doubleTapTimer ??= new Timer(kDoubleTapTimeout, () => _reset());
|
||||
}
|
||||
|
||||
void _stopDoubleTapTimer() {
|
||||
if (_doubleTapTimer != null) {
|
||||
_doubleTapTimer.cancel();
|
||||
_doubleTapTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user