Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nav): swipe to go back gesture #8951

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/animations/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -861,9 +861,32 @@ export class Animation {
* Start the animation with a user controlled progress.
*/
progressStart() {
// ensure all past transition end events have been cleared
this._clearAsync();

// fire off all the "before" function that have DOM READS in them
// elements will be in the DOM, however visibily hidden
// so we can read their dimensions if need be
// ******** DOM READ ****************
this._beforeReadFn();

// fire off all the "before" function that have DOM WRITES in them
// ******** DOM WRITE ****************
this._beforeWriteFn();

// ******** DOM WRITE ****************
this._progressStart();
}

/**
* @private
* DOM WRITE
* RECURSION
*/
_progressStart() {
for (var i = 0; i < this._cL; i++) {
// ******** DOM WRITE ****************
this._c[i].progressStart();
this._c[i]._progressStart();
}

// ******** DOM WRITE ****************
Expand Down Expand Up @@ -907,13 +930,14 @@ export class Animation {
/**
* End the progress animation.
*/
progressEnd(shouldComplete: boolean, currentStepValue: number) {
progressEnd(shouldComplete: boolean, currentStepValue: number, maxDelta: number = 0) {
console.debug('Animation, progressEnd, shouldComplete', shouldComplete, 'currentStepValue', currentStepValue);

this._isAsync = (currentStepValue > 0.05 && currentStepValue < 0.95);

const dur = 64;
const stepValue = shouldComplete ? 1 : 0;
const factor = Math.max(Math.abs(currentStepValue - stepValue), 0.5) * 2;
const dur = 64 + factor * maxDelta;

this._progressEnd(shouldComplete, stepValue, dur, this._isAsync);

Expand All @@ -922,7 +946,7 @@ export class Animation {
// set the async TRANSITION END event
// and run onFinishes when the transition ends
// ******** DOM WRITE ****************
this._asyncEnd(dur, true);
this._asyncEnd(dur, shouldComplete);

// this animation has a duration so we need another RAF
// for the CSS TRANSITION properties to kick in
Expand Down
2 changes: 1 addition & 1 deletion src/components/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class App {
// listen for hardware back button events
// register this back button action with a default priority
_platform.registerBackButtonAction(this.navPop.bind(this));
this._canDisableScroll = _config.get('canDisableScroll', true);
this._canDisableScroll = _config.get('canDisableScroll', false);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/components/app/test/gesture-collision/page1.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Menu
</ion-title>

<button ion-button menuToggle="right" right color="secondary">
<button ion-button menuToggle="right" right color="danger">
<ion-icon name="menu"></ion-icon>
</button>

Expand Down
25 changes: 3 additions & 22 deletions src/components/item/item-sliding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, ContentChildren, ContentChild, Dire

import { CSS, nativeRaf, nativeTimeout, clearNativeTimeout } from '../../util/dom';
import { Item } from './item';
import { isPresent, assert } from '../../util/util';
import { isPresent, swipeShouldReset, assert } from '../../util/util';
import { List } from '../list/list';

const SWIPE_MARGIN = 30;
Expand Down Expand Up @@ -320,10 +320,10 @@ export class ItemSliding {

// Check if the drag didn't clear the buttons mid-point
// and we aren't moving fast enough to swipe open
let isCloseDirection = (this._openAmount > 0) === !(velocity < 0);
let isResetDirection = (this._openAmount > 0) === !(velocity < 0);
let isMovingFast = Math.abs(velocity) > 0.3;
let isOnCloseZone = Math.abs(this._openAmount) < Math.abs(restingPoint / 2);
if (shouldClose(isCloseDirection, isMovingFast, isOnCloseZone)) {
if (swipeShouldReset(isResetDirection, isMovingFast, isOnCloseZone)) {
restingPoint = 0;
}

Expand Down Expand Up @@ -463,22 +463,3 @@ export class ItemSliding {
this._renderer.setElementClass(this._elementRef.nativeElement, cssClass, shouldAdd);
}
}

function shouldClose(isCloseDirection: boolean, isMovingFast: boolean, isOnCloseZone: boolean): boolean {
// The logic required to know when the sliding item should close (openAmount=0)
// depends on three booleans (isCloseDirection, isMovingFast, isOnCloseZone)
// and it ended up being too complicated to be written manually without errors
// so the truth table is attached below: (0=false, 1=true)
// isCloseDirection | isMovingFast | isOnCloseZone || shouldClose
// 0 | 0 | 0 || 0
// 0 | 0 | 1 || 1
// 0 | 1 | 0 || 0
// 0 | 1 | 1 || 0
// 1 | 0 | 0 || 0
// 1 | 0 | 1 || 1
// 1 | 1 | 0 || 1
// 1 | 1 | 1 || 1
// The resulting expression was generated by resolving the K-map (Karnaugh map):
let shouldClose = (!isMovingFast && isOnCloseZone) || (isCloseDirection && isMovingFast);
return shouldClose;
}
1 change: 0 additions & 1 deletion src/components/menu/menu-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ export class MenuController {
}
return menu.open();
}

return Promise.resolve(false);
}

Expand Down
4 changes: 3 additions & 1 deletion src/components/menu/menu-gestures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SlideEdgeGesture } from '../../gestures/slide-edge-gesture';
import { SlideData } from '../../gestures/slide-gesture';
import { assign } from '../../util/util';
import { GestureController, GesturePriority } from '../../gestures/gesture-controller';
import { NativeRafDebouncer } from '../../util/debouncer';

/**
* Gesture attached to the content which the menu is assigned to
Expand All @@ -11,15 +12,16 @@ export class MenuContentGesture extends SlideEdgeGesture {

constructor(
public menu: Menu,
gestureCtrl: GestureController,
contentEle: HTMLElement,
gestureCtrl: GestureController,
options: any = {}) {
super(contentEle, assign({
direction: 'x',
edge: menu.side,
threshold: 0,
maxEdgeStart: menu.maxEdgeStart || 50,
maxAngle: 40,
debouncer: new NativeRafDebouncer(),
gesture: gestureCtrl.create('menu-swipe', {
priority: GesturePriority.MenuSwipe,
})
Expand Down
21 changes: 15 additions & 6 deletions src/components/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export class Menu {
private _isPers: boolean = false;
private _init: boolean = false;
private _events: UIEventManager = new UIEventManager();
private _gestureID: number = 0;

/**
* @private
Expand Down Expand Up @@ -303,7 +304,11 @@ export class Menu {
private _keyboard: Keyboard,
private _zone: NgZone,
private _gestureCtrl: GestureController
) {}
) {
if (_gestureCtrl) {
this._gestureID = _gestureCtrl.newID();
}
}

/**
* @private
Expand Down Expand Up @@ -332,7 +337,7 @@ export class Menu {
this.setElementAttribute('type', this.type);

// add the gestures
this._cntGesture = new MenuContentGesture(this, this._gestureCtrl, document.body);
this._cntGesture = new MenuContentGesture(this, document.body, this._gestureCtrl);

// register listeners if this menu is enabled
// check if more than one menu is on the same side
Expand Down Expand Up @@ -471,7 +476,7 @@ export class Menu {
}

private _before() {
assert(this._isAnimating === false, '_before should be called when we are not animating');
assert(!this._isAnimating, '_before() should not be called while animating');

// this places the menu into the correct location before it animates in
// this css class doesn't actually kick off any animations
Expand All @@ -483,8 +488,7 @@ export class Menu {
}

private _after(isOpen: boolean) {
assert(this._isAnimating === true, '_after should be called when we are animating');

assert(this._isAnimating, '_before() should be called while animating');
// keep opening/closing the menu disabled for a touch more yet
// only add listeners/css if it's enabled and isOpen
// and only remove listeners/css if it's not open
Expand All @@ -494,8 +498,10 @@ export class Menu {

this._events.unlistenAll();
if (isOpen) {
this._cntEle.classList.add('menu-content-open');
// Disable swipe to go back gesture
this._gestureCtrl.disableGesture('goback-swipe', this._gestureID);

this._cntEle.classList.add('menu-content-open');
let callback = this.onBackdropClick.bind(this);
this._events.pointerEvents({
element: this._cntEle,
Expand All @@ -508,6 +514,9 @@ export class Menu {
this.ionOpen.emit(true);

} else {
// Enable swipe to go back gesture
this._gestureCtrl.enableGesture('goback-swipe', this._gestureID);

this._cntEle.classList.remove('menu-content-open');
this.setElementClass('show-menu', false);
this.backdrop.setElementClass('show-menu', false);
Expand Down
23 changes: 14 additions & 9 deletions src/components/modal/test/basic/app-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,16 @@ export class E2EPage {
</ion-item>
</ion-list>
<button ion-button full (click)="submit()">Submit</button>
<p>ionViewCanEnter ({{called.ionViewCanEnter}})</p>
<p>ionViewCanLeave ({{called.ionViewCanLeave}})</p>
<p>ionViewWillLoad ({{called.ionViewWillLoad}})</p>
<p>ionViewDidLoad ({{called.ionViewDidLoad}})</p>
<p>ionViewWillEnter ({{called.ionViewWillEnter}})</p>
<p>ionViewDidEnter ({{called.ionViewDidEnter}})</p>
<p>ionViewWillLeave ({{called.ionViewWillLeave}})</p>
<p>ionViewDidLeave ({{called.ionViewDidLeave}})</p>
<div padding>
<p>ionViewCanEnter ({{called.ionViewCanEnter}})</p>
<p>ionViewCanLeave ({{called.ionViewCanLeave}})</p>
<p>ionViewWillLoad ({{called.ionViewWillLoad}})</p>
<p>ionViewDidLoad ({{called.ionViewDidLoad}})</p>
<p>ionViewWillEnter ({{called.ionViewWillEnter}})</p>
<p>ionViewDidEnter ({{called.ionViewDidEnter}})</p>
<p>ionViewWillLeave ({{called.ionViewWillLeave}})</p>
<p>ionViewDidLeave ({{called.ionViewDidLeave}})</p>
</div>
</ion-content>
`,
providers: [SomeComponentProvider]
Expand Down Expand Up @@ -519,10 +521,12 @@ export class ModalFirstPage {
}

ionViewWillLeave() {
console.log('ModalFirstPage ionViewWillLeave fired');
this.called.ionViewWillLeave++;
}

ionViewDidLeave() {
console.log('ModalFirstPage ionViewDidLeave fired');
this.called.ionViewDidLeave++;
}

Expand Down Expand Up @@ -626,7 +630,8 @@ export class E2EApp {
],
imports: [
IonicModule.forRoot(E2EApp, {
statusbarPadding: true
statusbarPadding: true,
swipeBackEnabled: true
})
],
bootstrap: [IonicApp],
Expand Down
4 changes: 2 additions & 2 deletions src/components/range/range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import { clamp, isNumber, isPresent, isString, isTrueProperty } from '../../util/util';
import { Config } from '../../config/config';
import { Debouncer } from '../../util/debouncer';
import { TimeoutDebouncer } from '../../util/debouncer';
import { Form } from '../../util/form';
import { Ion } from '../ion';
import { Item } from '../item/item';
Expand Down Expand Up @@ -217,7 +217,7 @@ export class Range extends Ion implements AfterViewInit, ControlValueAccessor, O
_step: number = 1;
_snaps: boolean = false;

_debouncer: Debouncer = new Debouncer(0);
_debouncer: TimeoutDebouncer = new TimeoutDebouncer(0);
_events: UIEventManager = new UIEventManager();
/**
* @private
Expand Down
4 changes: 2 additions & 2 deletions src/components/searchbar/searchbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { NgControl } from '@angular/forms';
import { Config } from '../../config/config';
import { Ion } from '../ion';
import { isPresent, isTrueProperty } from '../../util/util';
import { Debouncer } from '../../util/debouncer';
import { TimeoutDebouncer } from '../../util/debouncer';


/**
Expand Down Expand Up @@ -61,7 +61,7 @@ export class Searchbar extends Ion {
_autocomplete: string = 'off';
_autocorrect: string = 'off';
_isActive: boolean = false;
_debouncer: Debouncer = new Debouncer(250);
_debouncer: TimeoutDebouncer = new TimeoutDebouncer(250);

/**
* @input {string} The predefined color to use. For example: `"primary"`, `"secondary"`, `"danger"`.
Expand Down
8 changes: 7 additions & 1 deletion src/components/tabs/test/advanced/app-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ export class Tab1Page1 {
templateUrl: './tab1page2.html'
})
export class Tab1Page2 {
constructor(public tabs: Tabs) { }

favoritesTab() {
// TODO fix this with tabsHideOnSubPages=true
this.tabs.select(1);
}

ionViewWillEnter() {
console.log('Tab1Page2, ionViewWillEnter');
Expand Down Expand Up @@ -346,7 +352,7 @@ export const deepLinkConfig: DeepLinkConfig = {
Tab3Page1
],
imports: [
IonicModule.forRoot(E2EApp, null, deepLinkConfig)
IonicModule.forRoot(E2EApp, {tabsHideOnSubPages: true}, deepLinkConfig)
],
bootstrap: [IonicApp],
entryComponents: [
Expand Down
1 change: 1 addition & 0 deletions src/components/tabs/test/advanced/tab1page2.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<ion-content padding>

<p><button ion-button navPush="Tab1Page3">Go to Tab 1, Page 3</button></p>
<p><button ion-button (click)="favoritesTab()">Favorites Tab</button></p>
<p><button ion-button class="e2eBackToTab1Page1" navPop>Back to Tab 1, Page 1</button></p>
<div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div>
<div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div>
Expand Down
Loading