Skip to content
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
7 changes: 5 additions & 2 deletions angular/src/directives/navigation/ion-back-button.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Directive, HostListener, Optional } from '@angular/core';
import { AnimationBuilder } from '@ionic/core';

import { Config } from '../../providers/config';
import { NavController } from '../../providers/nav-controller';
Expand All @@ -7,11 +8,12 @@ import { IonRouterOutlet } from './ion-router-outlet';

@Directive({
selector: 'ion-back-button',
inputs: ['defaultHref'],
inputs: ['defaultHref', 'routerAnimation'],
})
export class IonBackButtonDelegate {

defaultHref: string | undefined | null;
routerAnimation?: AnimationBuilder;

constructor(
@Optional() private routerOutlet: IonRouterOutlet,
Expand All @@ -27,10 +29,11 @@ export class IonBackButtonDelegate {
const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref');

if (this.routerOutlet && this.routerOutlet.canGoBack()) {
this.navCtrl.setDirection('back', undefined, undefined, this.routerAnimation);
this.routerOutlet.pop();
ev.preventDefault();
} else if (defaultHref != null) {
this.navCtrl.navigateBack(defaultHref);
this.navCtrl.navigateBack(defaultHref, { animation: this.routerAnimation });
ev.preventDefault();
}
}
Expand Down
7 changes: 4 additions & 3 deletions angular/src/directives/navigation/router-link-delegate.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { LocationStrategy } from '@angular/common';
import { Directive, ElementRef, HostListener, Optional } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
import { RouterDirection } from '@ionic/core';
import { AnimationBuilder, RouterDirection } from '@ionic/core';
import { Subscription } from 'rxjs';

import { NavController } from '../../providers/nav-controller';

@Directive({
selector: '[routerLink]',
inputs: ['routerDirection']
inputs: ['routerDirection', 'routerAnimation']
})
export class RouterLinkDelegate {

private subscription?: Subscription;

routerDirection: RouterDirection = 'forward';
routerAnimation?: AnimationBuilder;

constructor(
private locationStrategy: LocationStrategy,
Expand Down Expand Up @@ -50,7 +51,7 @@ export class RouterLinkDelegate {
*/
@HostListener('click', ['$event'])
onClick(ev: UIEvent) {
this.navCtrl.setDirection(this.routerDirection);
this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation);
ev.preventDefault();
}
}
42 changes: 35 additions & 7 deletions angular/src/directives/navigation/stack-controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Location } from '@angular/common';
import { ComponentRef, NgZone } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterDirection } from '@ionic/core';
import { AnimationBuilder, RouterDirection } from '@ionic/core';

import { bindLifecycleEvents } from '../../providers/angular-delegate';
import { NavController } from '../../providers/nav-controller';
Expand Down Expand Up @@ -52,7 +52,8 @@ export class StackController {
}

setActive(enteringView: RouteView): Promise<StackEvent> {
let { direction, animation } = this.navCtrl.consumeTransition();
const consumeResult = this.navCtrl.consumeTransition();
let { direction, animation, animationBuilder } = consumeResult;
const leavingView = this.activeView;
const tabSwitch = isTabSwitch(enteringView, leavingView);
if (tabSwitch) {
Expand Down Expand Up @@ -105,6 +106,31 @@ export class StackController {
enteringView.ref.changeDetectorRef.detectChanges();
}

/**
* If we are going back from a page that
* was presented using a custom animation
* we should default to using that
* unless the developer explicitly
* provided another animation.
*/
const customAnimation = enteringView.animationBuilder;
if (
animationBuilder === undefined &&
direction === 'back' &&
!tabSwitch &&
customAnimation !== undefined
) {
animationBuilder = customAnimation;
}

/**
* Save any custom animation so that navigating
* back will use this custom animation by default.
*/
if (animationBuilder !== undefined && leavingView) {
leavingView.animationBuilder = animationBuilder;
}

// Wait until previous transitions finish
return this.zone.runOutsideAngular(() => {
return this.wait(() => {
Expand All @@ -116,7 +142,7 @@ export class StackController {
// In case the enteringView is the same as the leavingPage we need to reattach()
enteringView.ref.changeDetectorRef.reattach();

return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false)
return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false, animationBuilder)
.then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location))
.then(() => ({
enteringView,
Expand Down Expand Up @@ -154,8 +180,8 @@ export class StackController {
url = primaryOutlet.route._routerState.snapshot.url;
}
}

return this.navCtrl.navigateBack(url, view.savedExtras).then(() => true);
const { animationBuilder } = this.navCtrl.consumeTransition();
return this.navCtrl.navigateBack(url, { ...view.savedExtras, animation: animationBuilder }).then(() => true);
});
}

Expand Down Expand Up @@ -225,7 +251,8 @@ export class StackController {
leavingView: RouteView | undefined,
direction: 'forward' | 'back' | undefined,
showGoBack: boolean,
progressAnimation: boolean
progressAnimation: boolean,
animationBuilder?: AnimationBuilder
) {
if (this.skipTransition) {
this.skipTransition = false;
Expand All @@ -250,7 +277,8 @@ export class StackController {
duration: direction === undefined ? 0 : undefined,
direction,
showGoBack,
progressAnimation
progressAnimation,
animationBuilder
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion angular/src/directives/navigation/stack-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ComponentRef } from '@angular/core';
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
import { NavDirection, RouterDirection } from '@ionic/core';
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';

export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => {
if (direction === 'root') {
Expand Down Expand Up @@ -96,4 +96,5 @@ export interface RouteView {
savedData?: any;
savedExtras?: NavigationExtras;
unlistenEvents: () => void;
animationBuilder?: AnimationBuilder;
}
24 changes: 12 additions & 12 deletions angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export class IonAvatar {
}
export declare interface IonBackButton extends Components.IonBackButton {
}
@ProxyCmp({ inputs: ["color", "defaultHref", "disabled", "icon", "mode", "text", "type"] })
@Component({ selector: "ion-back-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "text", "type"] })
@ProxyCmp({ inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] })
@Component({ selector: "ion-back-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] })
export class IonBackButton {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
Expand Down Expand Up @@ -61,8 +61,8 @@ export class IonBadge {
}
export declare interface IonButton extends Components.IonButton {
}
@ProxyCmp({ inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerDirection", "shape", "size", "strong", "target", "type"] })
@Component({ selector: "ion-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerDirection", "shape", "size", "strong", "target", "type"] })
@ProxyCmp({ inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] })
@Component({ selector: "ion-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] })
export class IonButton {
ionFocus!: EventEmitter<CustomEvent>;
ionBlur!: EventEmitter<CustomEvent>;
Expand All @@ -86,8 +86,8 @@ export class IonButtons {
}
export declare interface IonCard extends Components.IonCard {
}
@ProxyCmp({ inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "target", "type"] })
@Component({ selector: "ion-card", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "target", "type"] })
@ProxyCmp({ inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
@Component({ selector: "ion-card", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
export class IonCard {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
Expand Down Expand Up @@ -220,8 +220,8 @@ export class IonFab {
}
export declare interface IonFabButton extends Components.IonFabButton {
}
@ProxyCmp({ inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "show", "size", "target", "translucent", "type"] })
@Component({ selector: "ion-fab-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "show", "size", "target", "translucent", "type"] })
@ProxyCmp({ inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] })
@Component({ selector: "ion-fab-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] })
export class IonFabButton {
ionFocus!: EventEmitter<CustomEvent>;
ionBlur!: EventEmitter<CustomEvent>;
Expand Down Expand Up @@ -344,8 +344,8 @@ export class IonInput {
}
export declare interface IonItem extends Components.IonItem {
}
@ProxyCmp({ inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerDirection", "target", "type"] })
@Component({ selector: "ion-item", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerDirection", "target", "type"] })
@ProxyCmp({ inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
@Component({ selector: "ion-item", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] })
export class IonItem {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
Expand Down Expand Up @@ -498,8 +498,8 @@ export class IonNav {
}
export declare interface IonNavLink extends Components.IonNavLink {
}
@ProxyCmp({ inputs: ["component", "componentProps", "routerDirection"] })
@Component({ selector: "ion-nav-link", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["component", "componentProps", "routerDirection"] })
@ProxyCmp({ inputs: ["component", "componentProps", "routerAnimation", "routerDirection"] })
@Component({ selector: "ion-nav-link", changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content></ng-content>", inputs: ["component", "componentProps", "routerAnimation", "routerDirection"] })
export class IonNavLink {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
Expand Down
20 changes: 13 additions & 7 deletions angular/src/providers/nav-controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Location } from '@angular/common';
import { Injectable, Optional } from '@angular/core';
import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router';
import { NavDirection, RouterDirection } from '@ionic/core';
import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core';

import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet';

import { Platform } from './platform';

export interface AnimationOptions {
animated?: boolean;
animation?: AnimationBuilder;
animationDirection?: 'forward' | 'back';
}

Expand All @@ -22,6 +23,7 @@ export class NavController {
private topOutlet?: IonRouterOutlet;
private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION;
private animated?: NavDirection = DEFAULT_ANIMATED;
private animationBuilder?: AnimationBuilder;
private guessDirection: RouterDirection = 'forward';
private guessAnimation?: NavDirection;
private lastNavId = -1;
Expand Down Expand Up @@ -65,7 +67,7 @@ export class NavController {
* ```
*/
navigateForward(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
this.setDirection('forward', options.animated, options.animationDirection);
this.setDirection('forward', options.animated, options.animationDirection, options.animation);
return this.navigate(url, options);
}

Expand All @@ -88,7 +90,7 @@ export class NavController {
* ```
*/
navigateBack(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
this.setDirection('back', options.animated, options.animationDirection);
this.setDirection('back', options.animated, options.animationDirection, options.animation);
return this.navigate(url, options);
}

Expand All @@ -111,7 +113,7 @@ export class NavController {
* ```
*/
navigateRoot(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise<boolean> {
this.setDirection('root', options.animated, options.animationDirection);
this.setDirection('root', options.animated, options.animationDirection, options.animation);
return this.navigate(url, options);
}

Expand All @@ -121,7 +123,7 @@ export class NavController {
* by default.
*/
back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) {
this.setDirection('back', options.animated, options.animationDirection);
this.setDirection('back', options.animated, options.animationDirection, options.animation);
return this.location.back();
}

Expand Down Expand Up @@ -150,9 +152,10 @@ export class NavController {
*
* It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`.
*/
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') {
setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back', animationBuilder?: AnimationBuilder) {
this.direction = direction;
this.animated = getAnimation(direction, animated, animationDirection);
this.animationBuilder = animationBuilder;
}

/**
Expand All @@ -168,6 +171,7 @@ export class NavController {
consumeTransition() {
let direction: RouterDirection = 'root';
let animation: NavDirection | undefined;
const animationBuilder = this.animationBuilder;

if (this.direction === 'auto') {
direction = this.guessDirection;
Expand All @@ -178,10 +182,12 @@ export class NavController {
}
this.direction = DEFAULT_DIRECTION;
this.animated = DEFAULT_ANIMATED;
this.animationBuilder = undefined;

return {
direction,
animation
animation,
animationBuilder
};
}

Expand Down
3 changes: 3 additions & 0 deletions angular/test/test-app/src/app/alert/alert.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<ion-header>
<ion-toolbar>
<ion-buttons>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
Alert test
</ion-title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</ion-header>
<ion-content>
<ion-list>
<ion-item routerLink="/alerts">
<ion-item routerLink="/alerts" [routerAnimation]="routerAnimation">
<ion-label>
Alerts test
</ion-label>
Expand Down
16 changes: 16 additions & 0 deletions angular/test/test-app/src/app/home-page/home-page.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import { Component } from '@angular/core';
import { AnimationBuilder, AnimationController } from '@ionic/angular';

@Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
})
export class HomePageComponent {
routerAnimation: AnimationBuilder = (_, opts) => {
const { direction, enteringEl, leavingEl } = opts;
const animation = this.animationCtrl.create().duration(500).easing('ease-out');
const enteringAnimation = this.animationCtrl.create().addElement(enteringEl).beforeRemoveClass(['ion-page-invisible']);
const leavingAnimation = this.animationCtrl.create().addElement(leavingEl).beforeRemoveClass(['ion-page-invisible']);
if (direction === 'back') {
enteringAnimation.fromTo('transform', 'translateX(-100%)', 'translateX(0%)');
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(100%)');
} else {
enteringAnimation.fromTo('transform', 'translateX(100%)', 'translateX(0%)');
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(-100%)');
}
return animation.addAnimation([enteringAnimation, leavingAnimation]);
};

constructor(private animationCtrl: AnimationController) {}
}
Loading