Skip to content

Commit fa06942

Browse files
authoredJul 9, 2021
fix(router-outlet): improve reliability of swipe back gesture when quickly swiping back (#23527)
resolves #22895
1 parent 3b803eb commit fa06942

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed
 

‎core/src/components/router-outlet/route-outlet.tsx

+41-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
1919
private waitPromise?: Promise<void>;
2020
private gesture?: Gesture;
2121
private ani?: Animation;
22-
private animationEnabled = true;
22+
private gestureOrAnimationInProgress = false;
2323

2424
@Element() el!: HTMLElement;
2525

@@ -61,17 +61,22 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
6161
@Event({ bubbles: false }) ionNavDidChange!: EventEmitter<void>;
6262

6363
async connectedCallback() {
64+
const onStart = () => {
65+
this.gestureOrAnimationInProgress = true;
66+
if (this.swipeHandler) {
67+
this.swipeHandler.onStart();
68+
}
69+
}
70+
6471
this.gesture = (await import('../../utils/gesture/swipe-back')).createSwipeBackGesture(
6572
this.el,
66-
() => !!this.swipeHandler && this.swipeHandler.canStart() && this.animationEnabled,
67-
() => this.swipeHandler && this.swipeHandler.onStart(),
73+
() => !this.gestureOrAnimationInProgress && !!this.swipeHandler && this.swipeHandler.canStart(),
74+
() => onStart(),
6875
step => this.ani && this.ani.progressStep(step),
6976
(shouldComplete, step, dur) => {
7077
if (this.ani) {
71-
this.animationEnabled = false;
72-
7378
this.ani.onFinish(() => {
74-
this.animationEnabled = true;
79+
this.gestureOrAnimationInProgress = false;
7580

7681
if (this.swipeHandler) {
7782
this.swipeHandler.onEnd(shouldComplete);
@@ -97,7 +102,8 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
97102
}
98103

99104
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
100-
105+
} else {
106+
this.gestureOrAnimationInProgress = false;
101107
}
102108
}
103109
);
@@ -191,7 +197,34 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
191197
leavingEl,
192198
baseEl: el,
193199
progressCallback: (opts.progressAnimation
194-
? ani => this.ani = ani
200+
? ani => {
201+
/**
202+
* Because this progress callback is called asynchronously
203+
* it is possible for the gesture to start and end before
204+
* the animation is ever set. In that scenario, we should
205+
* immediately call progressEnd so that the transition promise
206+
* resolves and the gesture does not get locked up.
207+
*/
208+
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
209+
this.gestureOrAnimationInProgress = true;
210+
ani.onFinish(() => {
211+
this.gestureOrAnimationInProgress = false;
212+
if (this.swipeHandler) {
213+
this.swipeHandler.onEnd(false);
214+
}
215+
}, { oneTimeCallback: true });
216+
217+
/**
218+
* Playing animation to beginning
219+
* with a duration of 0 prevents
220+
* any flickering when the animation
221+
* is later cleaned up.
222+
*/
223+
ani.progressEnd(0, 0, 0);
224+
} else {
225+
this.ani = ani;
226+
}
227+
}
195228
: undefined
196229
),
197230
...opts,

‎packages/react-router/test-app/cypress/integration/swipe-to-go-back.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ describe('Swipe To Go Back', () => {
1010
cy.ionPageVisible('main');
1111
cy.ionNav('ion-item', 'Details');
1212
cy.ionPageVisible('details');
13+
cy.ionPageHidden('main');
1314
cy.ionSwipeToGoBack(true);
1415
cy.ionPageVisible('main');
1516
});

0 commit comments

Comments
 (0)
Please sign in to comment.