mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00

* chore: move tns-core-modules to nativescript-core * chore: preparing compat generate script * chore: add missing definitions * chore: no need for http-request to be private * chore: packages chore * test: generate tests for tns-core-modules * chore: add anroid module for consistency * chore: add .npmignore * chore: added privateModulesWhitelist * chore(webpack): added bundle-entry-points * chore: scripts * chore: tests changed to use @ns/core * test: add scoped-packages test project * test: fix types * test: update test project * chore: build scripts * chore: update build script * chore: npm scripts cleanup * chore: make the compat pgk work with old wp config * test: generate diff friendly tests * chore: create barrel exports * chore: move files after rebase * chore: typedoc config * chore: compat mode * chore: review of barrels * chore: remove tns-core-modules import after rebase * chore: dev workflow setup * chore: update developer-workflow * docs: experiment with API extractor * chore: api-extractor and barrel exports * chore: api-extractor configs * chore: generate d.ts rollup with api-extractor * refactor: move methods inside Frame * chore: fic tests to use Frame static methods * refactor: create Builder class * refactor: use Builder class in tests * refactor: include Style in ui barrel * chore: separate compat build script * chore: fix tslint errors * chore: update NATIVESCRIPT_CORE_ARGS * chore: fix compat pack * chore: fix ui-test-app build with linked modules * chore: Application, ApplicationSettings, Connectivity and Http * chore: export Trace, Profiling and Utils * refactor: Static create methods for ImageSource * chore: fix deprecated usages of ImageSource * chore: move Span and FormattedString to ui * chore: add events-args and ImageSource to index files * chore: check for CLI >= 6.2 when building for IOS * chore: update travis build * chore: copy Pod file to compat package * chore: update error msg ui-tests-app * refactor: Apply suggestions from code review Co-Authored-By: Martin Yankov <m.i.yankov@gmail.com> * chore: typings and refs * chore: add missing d.ts files for public API * chore: adress code review FB * chore: update api-report * chore: dev-workflow for other apps * chore: api update * chore: update api-report
293 lines
11 KiB
TypeScript
293 lines
11 KiB
TypeScript
// Definitions.
|
|
import {
|
|
CubicBezierAnimationCurve as CubicBezierAnimationCurveDefinition,
|
|
AnimationPromise as AnimationPromiseDefinition,
|
|
Animation as AnimationBaseDefinition,
|
|
AnimationDefinition,
|
|
Pair
|
|
} from ".";
|
|
import { View } from "../core/view";
|
|
|
|
// Types.
|
|
import { Color } from "../../color";
|
|
import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceType } from "../../trace";
|
|
import { PercentLength } from "../styling/style-properties";
|
|
|
|
export { Color, traceEnabled, traceWrite, traceCategories, traceType };
|
|
|
|
export module Properties {
|
|
export const opacity = "opacity";
|
|
export const backgroundColor = "backgroundColor";
|
|
export const translate = "translate";
|
|
export const rotate = "rotate";
|
|
export const scale = "scale";
|
|
export const height = "height";
|
|
export const width = "width";
|
|
}
|
|
|
|
export interface PropertyAnimation {
|
|
target: View;
|
|
property: string;
|
|
value: any;
|
|
duration?: number;
|
|
delay?: number;
|
|
iterations?: number;
|
|
curve?: any;
|
|
}
|
|
|
|
export class CubicBezierAnimationCurve implements CubicBezierAnimationCurveDefinition {
|
|
|
|
public x1: number;
|
|
public y1: number;
|
|
public x2: number;
|
|
public y2: number;
|
|
|
|
constructor(x1: number, y1: number, x2: number, y2: number) {
|
|
this.x1 = x1;
|
|
this.y1 = y1;
|
|
this.x2 = x2;
|
|
this.y2 = y2;
|
|
}
|
|
}
|
|
|
|
export abstract class AnimationBase implements AnimationBaseDefinition {
|
|
public _propertyAnimations: Array<PropertyAnimation>;
|
|
public _playSequentially: boolean;
|
|
private _isPlaying: boolean;
|
|
private _resolve;
|
|
private _reject;
|
|
|
|
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean) {
|
|
if (!animationDefinitions || animationDefinitions.length === 0) {
|
|
throw new Error("No animation definitions specified");
|
|
}
|
|
|
|
if (traceEnabled()) {
|
|
traceWrite("Analyzing " + animationDefinitions.length + " animation definitions...", traceCategories.Animation);
|
|
}
|
|
|
|
this._propertyAnimations = new Array<PropertyAnimation>();
|
|
for (let i = 0, length = animationDefinitions.length; i < length; i++) {
|
|
if (animationDefinitions[i].curve) {
|
|
animationDefinitions[i].curve = this._resolveAnimationCurve(animationDefinitions[i].curve);
|
|
}
|
|
this._propertyAnimations = this._propertyAnimations.concat(AnimationBase._createPropertyAnimations(animationDefinitions[i]));
|
|
}
|
|
|
|
if (this._propertyAnimations.length === 0) {
|
|
throw new Error("Nothing to animate.");
|
|
}
|
|
if (traceEnabled()) {
|
|
traceWrite("Created " + this._propertyAnimations.length + " individual property animations.", traceCategories.Animation);
|
|
}
|
|
|
|
this._playSequentially = playSequentially;
|
|
}
|
|
|
|
abstract _resolveAnimationCurve(curve: any): any;
|
|
|
|
protected _rejectAlreadyPlaying(): AnimationPromiseDefinition {
|
|
const reason = "Animation is already playing.";
|
|
traceWrite(reason, traceCategories.Animation, traceType.warn);
|
|
|
|
return <AnimationPromiseDefinition>new Promise<void>((resolve, reject) => {
|
|
reject(reason);
|
|
});
|
|
}
|
|
|
|
public play(): AnimationPromiseDefinition {
|
|
// We have to actually create a "Promise" due to a bug in the v8 engine and decedent promises
|
|
// We just cast it to a animationPromise so that all the rest of the code works fine
|
|
const animationFinishedPromise = <AnimationPromiseDefinition>new Promise<void>((resolve, reject) => {
|
|
this._resolve = resolve;
|
|
this._reject = reject;
|
|
});
|
|
|
|
this.fixupAnimationPromise(animationFinishedPromise);
|
|
|
|
this._isPlaying = true;
|
|
|
|
return animationFinishedPromise;
|
|
}
|
|
|
|
private fixupAnimationPromise(promise: AnimationPromiseDefinition): void {
|
|
// Since we are using function() below because of arguments, TS won't automatically do a _this for those functions.
|
|
const _this = this;
|
|
promise.cancel = () => {
|
|
_this.cancel();
|
|
};
|
|
const _then = promise.then;
|
|
promise.then = function () {
|
|
const r = _then.apply(promise, arguments);
|
|
_this.fixupAnimationPromise(r);
|
|
|
|
return r;
|
|
};
|
|
const _catch = promise.catch;
|
|
promise.catch = function () {
|
|
const r = _catch.apply(promise, arguments);
|
|
_this.fixupAnimationPromise(r);
|
|
|
|
return r;
|
|
};
|
|
}
|
|
|
|
public cancel(): void {
|
|
// Implemented in platform specific files
|
|
}
|
|
|
|
public get isPlaying(): boolean {
|
|
return this._isPlaying;
|
|
}
|
|
|
|
public _resolveAnimationFinishedPromise() {
|
|
this._isPlaying = false;
|
|
this._resolve();
|
|
}
|
|
|
|
public _rejectAnimationFinishedPromise() {
|
|
this._isPlaying = false;
|
|
this._reject(new Error("Animation cancelled."));
|
|
}
|
|
|
|
private static _createPropertyAnimations(animationDefinition: AnimationDefinition): Array<PropertyAnimation> {
|
|
if (!animationDefinition.target) {
|
|
throw new Error("No animation target specified.");
|
|
}
|
|
|
|
for (let item in animationDefinition) {
|
|
if (animationDefinition[item] === undefined) {
|
|
continue;
|
|
}
|
|
|
|
if ((item === Properties.opacity ||
|
|
item === Properties.rotate ||
|
|
item === "duration" ||
|
|
item === "delay" ||
|
|
item === "iterations") && typeof animationDefinition[item] !== "number") {
|
|
throw new Error(`Property ${item} must be valid number. Value: ${animationDefinition[item]}`);
|
|
} else if ((item === Properties.scale || item === Properties.translate) &&
|
|
(typeof (<Pair>animationDefinition[item]).x !== "number" || typeof (<Pair>animationDefinition[item]).y !== "number")) {
|
|
throw new Error(`Property ${item} must be valid Pair. Value: ${animationDefinition[item]}`);
|
|
} else if (item === Properties.backgroundColor && !Color.isValid(animationDefinition.backgroundColor)) {
|
|
throw new Error(`Property ${item} must be valid color. Value: ${animationDefinition[item]}`);
|
|
} else if (item === Properties.width || item === Properties.height) {
|
|
// Coerce input into a PercentLength object in case it's a string.
|
|
animationDefinition[item] = PercentLength.parse(<any>animationDefinition[item]);
|
|
}
|
|
}
|
|
|
|
const propertyAnimations = new Array<PropertyAnimation>();
|
|
|
|
// opacity
|
|
if (animationDefinition.opacity !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.opacity,
|
|
value: animationDefinition.opacity,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
// backgroundColor
|
|
if (animationDefinition.backgroundColor !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.backgroundColor,
|
|
value: typeof animationDefinition.backgroundColor === "string" ?
|
|
new Color(<any>animationDefinition.backgroundColor) : animationDefinition.backgroundColor,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
// translate
|
|
if (animationDefinition.translate !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.translate,
|
|
value: animationDefinition.translate,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
// scale
|
|
if (animationDefinition.scale !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.scale,
|
|
value: animationDefinition.scale,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
// rotate
|
|
if (animationDefinition.rotate !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.rotate,
|
|
value: animationDefinition.rotate,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
// height
|
|
if (animationDefinition.height !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.height,
|
|
value: animationDefinition.height,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
// width
|
|
if (animationDefinition.width !== undefined) {
|
|
propertyAnimations.push({
|
|
target: animationDefinition.target,
|
|
property: Properties.width,
|
|
value: animationDefinition.width,
|
|
duration: animationDefinition.duration,
|
|
delay: animationDefinition.delay,
|
|
iterations: animationDefinition.iterations,
|
|
curve: animationDefinition.curve
|
|
});
|
|
}
|
|
|
|
if (propertyAnimations.length === 0) {
|
|
throw new Error("No known animation properties specified");
|
|
}
|
|
|
|
return propertyAnimations;
|
|
}
|
|
|
|
public static _getAnimationInfo(animation: PropertyAnimation): string {
|
|
return JSON.stringify({
|
|
target: animation.target.id,
|
|
property: animation.property,
|
|
value: animation.value,
|
|
duration: animation.duration,
|
|
delay: animation.delay,
|
|
iterations: animation.iterations,
|
|
curve: animation.curve
|
|
});
|
|
}
|
|
}
|