Skip to content

Commit ccdc394

Browse files
committed
This adds the ability to Cancel the Animation via the Promise returned via a play command.
1 parent 25852e9 commit ccdc394

7 files changed

Lines changed: 103 additions & 12 deletions

File tree

apps/tests/ui/animation/animation-tests.ts

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,21 +83,69 @@ export var test_CancellingAnimation = function (done) {
8383
// <snippet module="ui/animation" title="animation">
8484
// # Cancelling animation
8585
// ``` JavaScript
86-
var animation1 = label.createAnimation({ translate: { x: 100, y: 100 } });
86+
var animation1 = label.createAnimation({ translate: { x: 100, y: 100}, duration: 500 });
8787
animation1.play()
8888
.then(() => {
8989
////console.log("Animation finished");
9090
// <hide>
91-
assertIOSNativeTransformIsCorrect(label);
91+
throw new Error("Cancelling Animation - Should not be in the Promise Then()");
92+
// </hide>
93+
})
94+
.catch((e) => {
95+
////console.log("Animation cancelled");
96+
// <hide>
9297
helper.goBack();
93-
done();
98+
if (!e) {
99+
done(new Error("Cancel path did not have proper error"));
100+
} else if (e.toString() === "Error: Animation cancelled.") {
101+
done()
102+
} else {
103+
done(e);
104+
}
105+
// </hide>
106+
});
107+
animation1.cancel();
108+
// ```
109+
// </snippet>
110+
}
111+
112+
export var test_CancellingAnimate = function (done) {
113+
var mainPage: pageModule.Page;
114+
var label: labelModule.Label;
115+
var pageFactory = function (): pageModule.Page {
116+
label = new labelModule.Label();
117+
label.text = "label";
118+
var stackLayout = new stackLayoutModule.StackLayout();
119+
stackLayout.addChild(label);
120+
mainPage = new pageModule.Page();
121+
mainPage.content = stackLayout;
122+
return mainPage;
123+
};
124+
125+
helper.navigate(pageFactory);
126+
TKUnit.waitUntilReady(() => { return label.isLoaded });
127+
128+
// <snippet module="ui/animation" title="animation">
129+
// # Cancelling animation
130+
// ``` JavaScript
131+
var animation1 = label.animate({ translate: { x: 100, y: 100 }, duration: 500 })
132+
.then(() => {
133+
////console.log("Animation finished");
134+
// <hide>
135+
throw new Error("Cancelling Animate - Should not be in Promise Then()");
94136
// </hide>
95137
})
96138
.catch((e) => {
97139
////console.log("Animation cancelled");
98140
// <hide>
99141
helper.goBack();
100-
done();
142+
if (!e) {
143+
done(new Error("Cancel path did not have proper error"));
144+
} else if (e.toString() === "Error: Animation cancelled.") {
145+
done()
146+
} else {
147+
done(e);
148+
}
101149
// </hide>
102150
});
103151
animation1.cancel();

ui/animation/animation-common.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,59 @@ export class CubicBezierAnimationCurve implements definition.CubicBezierAnimatio
4242
}
4343
}
4444

45+
// This is a BOGUS Class to make TypeScript happy - This is not needed other than to make TS happy.
46+
// We didn't want to actually modify Promise; as the cancel() is ONLY valid for animations "Promise"
47+
export class AnimationPromise implements definition.AnimationPromise {
48+
public cancel(): void { /* Do Nothing */ }
49+
public then(onFulfilled?: (value?: any) => void, onRejected?: (error?: any) => void): AnimationPromise { return new AnimationPromise();}
50+
public catch(onRejected?: (error?: any) => void): AnimationPromise { return new AnimationPromise();}
51+
}
52+
4553
export class Animation implements definition.Animation {
4654
public _propertyAnimations: Array<PropertyAnimation>;
4755
public _playSequentially: boolean;
4856
private _isPlaying: boolean;
4957
private _resolve;
5058
private _reject;
5159

52-
public play(): Promise<void> {
60+
public play(): AnimationPromise {
5361
if (this.isPlaying) {
5462
throw new Error("Animation is already playing.");
5563
}
5664

57-
var animationFinishedPromise = new Promise<void>((resolve, reject) => {
65+
// We have to actually create a "Promise" due to a bug in the v8 engine and decedent promises
66+
// We just cast it to a animationPromise so that all the rest of the code works fine
67+
var animationFinishedPromise = <AnimationPromise>new Promise<void>((resolve, reject) => {
5868
this._resolve = resolve;
5969
this._reject = reject;
6070
});
6171

72+
this.fixupAnimationPromise(animationFinishedPromise);
73+
6274
this._isPlaying = true;
6375
return animationFinishedPromise;
6476
}
6577

78+
private fixupAnimationPromise(promise: AnimationPromise): void {
79+
// Since we are using function() below because of arguments, TS won't automatically do a _this for those functions.
80+
var _this = this;
81+
promise.cancel = () => {
82+
_this.cancel();
83+
};
84+
var _then = promise.then;
85+
promise.then = function() {
86+
var r = _then.apply(promise, arguments);
87+
_this.fixupAnimationPromise(r);
88+
return r;
89+
};
90+
var _catch = promise.catch;
91+
promise.catch = function() {
92+
var r = _catch.apply(promise, arguments);
93+
_this.fixupAnimationPromise(r);
94+
return r;
95+
};
96+
}
97+
6698
public cancel(): void {
6799
if (!this.isPlaying) {
68100
throw new Error("Animation is not currently playing.");

ui/animation/animation.android.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class Animation extends common.Animation implements definition.Animation
3131
private _propertyUpdateCallbacks: Array<Function>;
3232
private _propertyResetCallbacks: Array<Function>;
3333

34-
public play(): Promise<void> {
34+
public play(): definition.AnimationPromise {
3535
var animationFinishedPromise = super.play();
3636

3737
var i: number;

ui/animation/animation.d.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
declare module "ui/animation" {
22
import viewModule = require("ui/core/view");
33
import colorModule = require("color");
4-
4+
55
/**
66
* Defines animation options for the View.animate method.
77
*/
@@ -82,12 +82,23 @@
8282
y: number;
8383
}
8484

85+
/**
86+
* Create Promise that can cancel the animation, we have to pretend our returns itself along with the cancel
87+
*/
88+
export class AnimationPromise extends Promise<void> {
89+
cancel(): void;
90+
then(onFulfilled?: (value?: any) => Thenable<void>, onRejected?: (error?: any) => Thenable<void>): AnimationPromise;
91+
then(onFulfilled?: (value?: any) => void, onRejected?: (error?: any) => void): AnimationPromise;
92+
catch(onRejected?: (error?: any) => Thenable<void>): AnimationPromise;
93+
catch(onRejected?: (error?: any) => void): AnimationPromise;
94+
}
95+
8596
/**
8697
* Defines a animation set.
8798
*/
8899
export class Animation {
89100
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean);
90-
public play: () => Promise<void>;
101+
public play: () => AnimationPromise;
91102
public cancel: () => void;
92103
public isPlaying: boolean;
93104
}

ui/animation/animation.ios.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class Animation extends common.Animation implements definition.Animation
8888
private _cancelledAnimations: number;
8989
private _mergedPropertyAnimations: Array<common.PropertyAnimation>;
9090

91-
public play(): Promise<void> {
91+
public play(): definition.AnimationPromise {
9292
var animationFinishedPromise = super.play();
9393
this._finishedAnimations = 0;
9494
this._cancelledAnimations = 0;

ui/core/view-common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ export class View extends ProxyObject implements definition.View {
11641164
}
11651165
}
11661166

1167-
public animate(animation: any): Promise<void> {
1167+
public animate(animation: any): animModule.AnimationPromise {
11681168
return this.createAnimation(animation).play();
11691169
}
11701170

ui/core/view.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ declare module "ui/core/view" {
518518
/**
519519
* Animates one or more properties of the view based on the supplied options.
520520
*/
521-
public animate(options: animation.AnimationDefinition): Promise<void>;
521+
public animate(options: animation.AnimationDefinition): animation.AnimationPromise;
522522

523523
/**
524524
* Creates an Animation object based on the supplied options.

0 commit comments

Comments
 (0)