#553 viewer: fix for single axis outer scope
This commit is contained in:
parent
ef74ef341e
commit
424ef96353
2 changed files with 38 additions and 109 deletions
|
@ -68,13 +68,38 @@ class MagnifierGestureRecognizer extends ScaleGestureRecognizer {
|
||||||
_initialSpan = _currentSpan;
|
_initialSpan = _currentSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event is PointerMoveEvent && (_areMultiPointers() || (_shouldMove() && _isOverSlop(event.kind)))) {
|
if (event is PointerMoveEvent) {
|
||||||
acceptGesture(pointer);
|
if (_areMultiPointers()) {
|
||||||
|
acceptGesture(pointer);
|
||||||
|
} else if (_isPriorityGesture() && _isOverSlop(event.kind)) {
|
||||||
|
acceptGesture(pointer);
|
||||||
|
} else {
|
||||||
|
final axis = scope.axis;
|
||||||
|
final isPriorityMove = (axis.contains(Axis.horizontal) && _canPanX()) || (axis.contains(Axis.vertical) && _canPanY());
|
||||||
|
if (isPriorityMove && _isOverSlop(event.kind)) {
|
||||||
|
acceptGesture(pointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.handleEvent(event);
|
super.handleEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void resolve(GestureDisposition disposition) {
|
||||||
|
switch (disposition) {
|
||||||
|
case GestureDisposition.accepted:
|
||||||
|
// do not let super `ScaleGestureRecognizer` accept gestures
|
||||||
|
// when it should yield to other recognizers
|
||||||
|
final canAccept = _areMultiPointers() || _isPriorityGesture() || _canPanX() || _canPanY();
|
||||||
|
super.resolve(canAccept ? GestureDisposition.accepted : GestureDisposition.rejected);
|
||||||
|
break;
|
||||||
|
case GestureDisposition.rejected:
|
||||||
|
super.resolve(disposition);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _updateDistances() {
|
void _updateDistances() {
|
||||||
// cf super._update
|
// cf super._update
|
||||||
final count = _pointerLocations.keys.length;
|
final count = _pointerLocations.keys.length;
|
||||||
|
@ -96,42 +121,29 @@ class MagnifierGestureRecognizer extends ScaleGestureRecognizer {
|
||||||
_currentSpan = count > 0 ? totalDeviation / count : 0.0;
|
_currentSpan = count > 0 ? totalDeviation / count : 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Offset get move => _initialFocalPoint! - _currentFocalPoint!;
|
||||||
|
|
||||||
// when there are multiple pointers, we always accept the gesture to scale
|
// when there are multiple pointers, we always accept the gesture to scale
|
||||||
// as this is not competing with single taps or other drag gestures
|
// as this is not competing with single taps or other drag gestures
|
||||||
bool _areMultiPointers() => _pointerLocations.keys.length >= 2;
|
bool _areMultiPointers() => _pointerLocations.keys.length >= 2;
|
||||||
|
|
||||||
bool _shouldMove() {
|
bool _isPriorityGesture() {
|
||||||
final move = _initialFocalPoint! - _currentFocalPoint!;
|
|
||||||
|
|
||||||
// e.g. vertical drag to adjust brightness instead of panning
|
// e.g. vertical drag to adjust brightness instead of panning
|
||||||
if (scope.acceptPointerEvent?.call(move) ?? false) return true;
|
if (scope.acceptPointerEvent?.call(move) ?? false) return true;
|
||||||
|
|
||||||
// e.g. double tap & drag for one finger zoom
|
// e.g. double tap & drag for one finger zoom
|
||||||
if (doubleTapDetails.value != null) return true;
|
if (doubleTapDetails.value != null) return true;
|
||||||
|
|
||||||
final validateAxis = scope.axis;
|
return false;
|
||||||
final canFling = scope.escapeByFling;
|
|
||||||
if (validateAxis.length == 2) {
|
|
||||||
// the image is the descendant of gesture detector(s) handling drag in both directions
|
|
||||||
final shouldMoveX = validateAxis.contains(Axis.horizontal) && hitDetector.shouldMoveX(move, canFling);
|
|
||||||
final shouldMoveY = validateAxis.contains(Axis.vertical) && hitDetector.shouldMoveY(move, canFling);
|
|
||||||
if (shouldMoveX == shouldMoveY) {
|
|
||||||
// consistently can/cannot pan the image in both direction the same way
|
|
||||||
return shouldMoveX;
|
|
||||||
} else {
|
|
||||||
// can pan the image in one direction, but should yield to an ascendant gesture detector in the other one
|
|
||||||
// the gesture direction angle is in ]-pi, pi], cf `Offset` doc for details
|
|
||||||
return (isXPan(move) && shouldMoveX) || (isYPan(move) && shouldMoveY);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// the image is the descendant of a gesture detector handling drag in one direction
|
|
||||||
return validateAxis.contains(Axis.vertical) ? hitDetector.shouldMoveY(move, canFling) : hitDetector.shouldMoveX(move, canFling);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _canPanX() => hitDetector.shouldMoveX(move, scope.escapeByFling) && isXPan(move);
|
||||||
|
|
||||||
|
bool _canPanY() => hitDetector.shouldMoveY(move, scope.escapeByFling) && isYPan(move);
|
||||||
|
|
||||||
bool _isOverSlop(PointerDeviceKind kind) {
|
bool _isOverSlop(PointerDeviceKind kind) {
|
||||||
final spanDelta = (_currentSpan! - _initialSpan!).abs();
|
final spanDelta = (_currentSpan! - _initialSpan!).abs();
|
||||||
final focalPointDelta = (_currentFocalPoint! - _initialFocalPoint!).distance;
|
final focalPointDelta = move.distance;
|
||||||
// warning: do not compare `focalPointDelta` to `kPanSlop`
|
// warning: do not compare `focalPointDelta` to `kPanSlop`
|
||||||
// `ScaleGestureRecognizer` uses `kPanSlop` (or platform settings, cf gestures/events.dart `computePanSlop`),
|
// `ScaleGestureRecognizer` uses `kPanSlop` (or platform settings, cf gestures/events.dart `computePanSlop`),
|
||||||
// but `HorizontalDragGestureRecognizer` uses `kTouchSlop` (or platform settings, cf gestures/events.dart `computeHitSlop`)
|
// but `HorizontalDragGestureRecognizer` uses `kTouchSlop` (or platform settings, cf gestures/events.dart `computeHitSlop`)
|
||||||
|
@ -141,27 +153,14 @@ class MagnifierGestureRecognizer extends ScaleGestureRecognizer {
|
||||||
return spanDelta > computeScaleSlop(kind) || focalPointDelta > computeHitSlop(kind, gestureSettings) * scope.touchSlopFactor;
|
return spanDelta > computeScaleSlop(kind) || focalPointDelta > computeHitSlop(kind, gestureSettings) * scope.touchSlopFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void resolve(GestureDisposition disposition) {
|
|
||||||
switch (disposition) {
|
|
||||||
case GestureDisposition.accepted:
|
|
||||||
// do not let super `ScaleGestureRecognizer` accept gestures
|
|
||||||
// when it should yield to other recognizers
|
|
||||||
final canAccept = _areMultiPointers() || _shouldMove();
|
|
||||||
super.resolve(canAccept ? GestureDisposition.accepted : GestureDisposition.rejected);
|
|
||||||
break;
|
|
||||||
case GestureDisposition.rejected:
|
|
||||||
super.resolve(disposition);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isXPan(Offset move) {
|
static bool isXPan(Offset move) {
|
||||||
|
// the gesture direction angle is in ]-pi, pi], cf `Offset` doc for details
|
||||||
final d = move.direction;
|
final d = move.direction;
|
||||||
return (-pi / 4 < d && d < pi / 4) || (3 / 4 * pi < d && d <= pi) || (-pi < d && d < -3 / 4 * pi);
|
return (-pi / 4 < d && d < pi / 4) || (3 / 4 * pi < d && d <= pi) || (-pi < d && d < -3 / 4 * pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isYPan(Offset move) {
|
static bool isYPan(Offset move) {
|
||||||
|
// the gesture direction angle is in ]-pi, pi], cf `Offset` doc for details
|
||||||
final d = move.direction;
|
final d = move.direction;
|
||||||
return (pi / 4 < d && d < 3 / 4 * pi) || (-3 / 4 * pi < d && d < -pi / 4);
|
return (pi / 4 < d && d < 3 / 4 * pi) || (-3 / 4 * pi < d && d < -pi / 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1258,14 +1258,6 @@
|
||||||
"tagEditorDiscardDialogMessage"
|
"tagEditorDiscardDialogMessage"
|
||||||
],
|
],
|
||||||
|
|
||||||
"es": [
|
|
||||||
"maxBrightnessNever",
|
|
||||||
"maxBrightnessAlways",
|
|
||||||
"videoResumptionModeNever",
|
|
||||||
"videoResumptionModeAlways",
|
|
||||||
"exportEntryDialogQuality"
|
|
||||||
],
|
|
||||||
|
|
||||||
"eu": [
|
"eu": [
|
||||||
"maxBrightnessNever",
|
"maxBrightnessNever",
|
||||||
"maxBrightnessAlways",
|
"maxBrightnessAlways",
|
||||||
|
@ -1775,14 +1767,6 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fr": [
|
|
||||||
"maxBrightnessNever",
|
|
||||||
"maxBrightnessAlways",
|
|
||||||
"videoResumptionModeNever",
|
|
||||||
"videoResumptionModeAlways",
|
|
||||||
"exportEntryDialogQuality"
|
|
||||||
],
|
|
||||||
|
|
||||||
"gl": [
|
"gl": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"chipActionGoToPlacePage",
|
"chipActionGoToPlacePage",
|
||||||
|
@ -3602,27 +3586,8 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
"hu": [
|
|
||||||
"maxBrightnessNever",
|
|
||||||
"maxBrightnessAlways",
|
|
||||||
"videoResumptionModeNever",
|
|
||||||
"videoResumptionModeAlways",
|
|
||||||
"exportEntryDialogQuality",
|
|
||||||
"settingsAskEverytime",
|
|
||||||
"settingsVideoPlaybackTile",
|
|
||||||
"settingsVideoPlaybackPageTitle",
|
|
||||||
"settingsVideoResumptionModeTile",
|
|
||||||
"settingsVideoResumptionModeDialogTitle",
|
|
||||||
"tagEditorDiscardDialogMessage"
|
|
||||||
],
|
|
||||||
|
|
||||||
"id": [
|
"id": [
|
||||||
"maxBrightnessNever",
|
|
||||||
"maxBrightnessAlways",
|
|
||||||
"videoResumptionModeNever",
|
|
||||||
"videoResumptionModeAlways",
|
|
||||||
"exportEntryDialogQuality",
|
"exportEntryDialogQuality",
|
||||||
"settingsAskEverytime",
|
|
||||||
"settingsVideoPlaybackTile",
|
"settingsVideoPlaybackTile",
|
||||||
"settingsVideoPlaybackPageTitle",
|
"settingsVideoPlaybackPageTitle",
|
||||||
"settingsVideoResumptionModeTile",
|
"settingsVideoResumptionModeTile",
|
||||||
|
@ -3687,14 +3652,6 @@
|
||||||
"tagEditorDiscardDialogMessage"
|
"tagEditorDiscardDialogMessage"
|
||||||
],
|
],
|
||||||
|
|
||||||
"ko": [
|
|
||||||
"maxBrightnessNever",
|
|
||||||
"maxBrightnessAlways",
|
|
||||||
"videoResumptionModeNever",
|
|
||||||
"videoResumptionModeAlways",
|
|
||||||
"exportEntryDialogQuality"
|
|
||||||
],
|
|
||||||
|
|
||||||
"lt": [
|
"lt": [
|
||||||
"columnCount",
|
"columnCount",
|
||||||
"chipActionGoToPlacePage",
|
"chipActionGoToPlacePage",
|
||||||
|
@ -3797,32 +3754,19 @@
|
||||||
"chipActionGoToPlacePage",
|
"chipActionGoToPlacePage",
|
||||||
"chipActionLock",
|
"chipActionLock",
|
||||||
"chipActionShowCountryStates",
|
"chipActionShowCountryStates",
|
||||||
"chipActionCreateVault",
|
|
||||||
"chipActionConfigureVault",
|
|
||||||
"entryActionShareImageOnly",
|
"entryActionShareImageOnly",
|
||||||
"entryActionShareVideoOnly",
|
"entryActionShareVideoOnly",
|
||||||
"viewerActionLock",
|
"viewerActionLock",
|
||||||
"viewerActionUnlock",
|
"viewerActionUnlock",
|
||||||
"entryInfoActionRemoveLocation",
|
|
||||||
"filterAspectRatioLandscapeLabel",
|
|
||||||
"filterAspectRatioPortraitLabel",
|
|
||||||
"filterNoAddressLabel",
|
|
||||||
"filterLocatedLabel",
|
"filterLocatedLabel",
|
||||||
"filterTaggedLabel",
|
|
||||||
"albumTierVaults",
|
"albumTierVaults",
|
||||||
"keepScreenOnVideoPlayback",
|
|
||||||
"lengthUnitPixel",
|
|
||||||
"maxBrightnessNever",
|
"maxBrightnessNever",
|
||||||
"maxBrightnessAlways",
|
"maxBrightnessAlways",
|
||||||
"subtitlePositionTop",
|
"subtitlePositionTop",
|
||||||
"subtitlePositionBottom",
|
"subtitlePositionBottom",
|
||||||
"vaultLockTypePattern",
|
"vaultLockTypePattern",
|
||||||
"vaultLockTypePassword",
|
|
||||||
"settingsVideoEnablePip",
|
|
||||||
"videoResumptionModeNever",
|
"videoResumptionModeNever",
|
||||||
"videoResumptionModeAlways",
|
"videoResumptionModeAlways",
|
||||||
"widgetDisplayedItemRandom",
|
|
||||||
"widgetDisplayedItemMostRecent",
|
|
||||||
"newVaultWarningDialogMessage",
|
"newVaultWarningDialogMessage",
|
||||||
"newVaultDialogTitle",
|
"newVaultDialogTitle",
|
||||||
"configureVaultDialogTitle",
|
"configureVaultDialogTitle",
|
||||||
|
@ -4802,20 +4746,6 @@
|
||||||
"filePickerUseThisFolder"
|
"filePickerUseThisFolder"
|
||||||
],
|
],
|
||||||
|
|
||||||
"pl": [
|
|
||||||
"maxBrightnessNever",
|
|
||||||
"maxBrightnessAlways",
|
|
||||||
"videoResumptionModeNever",
|
|
||||||
"videoResumptionModeAlways",
|
|
||||||
"exportEntryDialogQuality",
|
|
||||||
"settingsAskEverytime",
|
|
||||||
"settingsVideoPlaybackTile",
|
|
||||||
"settingsVideoPlaybackPageTitle",
|
|
||||||
"settingsVideoResumptionModeTile",
|
|
||||||
"settingsVideoResumptionModeDialogTitle",
|
|
||||||
"tagEditorDiscardDialogMessage"
|
|
||||||
],
|
|
||||||
|
|
||||||
"pt": [
|
"pt": [
|
||||||
"maxBrightnessNever",
|
"maxBrightnessNever",
|
||||||
"maxBrightnessAlways",
|
"maxBrightnessAlways",
|
||||||
|
|
Loading…
Reference in a new issue