mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 12:58:38 +08:00 
			
		
		
		
	fix(core): RootLayout shade cover asynchronous execution (#10228)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							6779cdcb55
						
					
				
				
					commit
					a19568c0d0
				
			@ -42,7 +42,9 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
 | 
			
		||||
	// ability to add any view instance to composite views like layers
 | 
			
		||||
	open(view: View, options: RootLayoutOptions = {}): Promise<void> {
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
		const enterAnimationDefinition = options.animation ? options.animation.enterFrom : null;
 | 
			
		||||
 | 
			
		||||
		return new Promise<void>((resolve, reject) => {
 | 
			
		||||
			if (!(view instanceof View)) {
 | 
			
		||||
				return reject(new Error(`Invalid open view: ${view}`));
 | 
			
		||||
			}
 | 
			
		||||
@ -51,8 +53,9 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
				return reject(new Error(`${view} has already been added`));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			const enterAnimationDefinition = options.animation ? options.animation.enterFrom : null;
 | 
			
		||||
 | 
			
		||||
			resolve();
 | 
			
		||||
		})
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				// keep track of the views locally to be able to use their options later
 | 
			
		||||
				this.popupViews.push({ view: view, options: options });
 | 
			
		||||
 | 
			
		||||
@ -61,15 +64,16 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
					// we just update properties if needed by additional overlaid views
 | 
			
		||||
					if (this.shadeCover) {
 | 
			
		||||
						// overwrite current shadeCover options if topmost popupview has additional shadeCover configurations
 | 
			
		||||
					this.updateShadeCover(this.shadeCover, options.shadeCover);
 | 
			
		||||
				} else {
 | 
			
		||||
					this.openShadeCover(options.shadeCover);
 | 
			
		||||
						return this.updateShadeCover(this.shadeCover, options.shadeCover);
 | 
			
		||||
					}
 | 
			
		||||
					return this.openShadeCover(options.shadeCover);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			})
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				view.opacity = 0; // always begin with view invisible when adding dynamically
 | 
			
		||||
				this.insertChild(view, this.getChildrenCount() + 1);
 | 
			
		||||
 | 
			
		||||
				return new Promise((resolve, reject) => {
 | 
			
		||||
					setTimeout(() => {
 | 
			
		||||
						// only apply initial state and animate after the first tick - ensures safe areas and other measurements apply correctly
 | 
			
		||||
						this.applyInitialState(view, enterAnimationDefinition);
 | 
			
		||||
@ -85,12 +89,21 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
							});
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// optional animation parameter to overwrite close animation declared when opening popup
 | 
			
		||||
	// ability to remove any view instance from composite views
 | 
			
		||||
	close(view: View, exitTo?: TransitionAnimation): Promise<void> {
 | 
			
		||||
		return new Promise((resolve, reject) => {
 | 
			
		||||
		const cleanupAndFinish = () => {
 | 
			
		||||
			view.notify({ eventName: 'closed', object: view });
 | 
			
		||||
			this.removeChild(view);
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// use exitAnimation that is passed in and fallback to the exitAnimation passed in when opening
 | 
			
		||||
		let exitAnimationDefinition = exitTo;
 | 
			
		||||
 | 
			
		||||
		return new Promise<void>((resolve, reject) => {
 | 
			
		||||
			if (!(view instanceof View)) {
 | 
			
		||||
				return reject(new Error(`Invalid close view: ${view}`));
 | 
			
		||||
			}
 | 
			
		||||
@ -99,15 +112,15 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
				return reject(new Error(`Unable to close popup. ${view} not found`));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			resolve();
 | 
			
		||||
		})
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				const popupIndex = this.getPopupIndex(view);
 | 
			
		||||
				const poppedView = this.popupViews[popupIndex];
 | 
			
		||||
			const cleanupAndFinish = () => {
 | 
			
		||||
				view.notify({ eventName: 'closed', object: view });
 | 
			
		||||
				this.removeChild(view);
 | 
			
		||||
				resolve();
 | 
			
		||||
			};
 | 
			
		||||
			// use exitAnimation that is passed in and fallback to the exitAnimation passed in when opening
 | 
			
		||||
			const exitAnimationDefinition = exitTo || poppedView?.options?.animation?.exitTo;
 | 
			
		||||
 | 
			
		||||
				if (!exitAnimationDefinition) {
 | 
			
		||||
					exitAnimationDefinition = poppedView?.options?.animation?.exitTo;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Remove view from tracked popupviews
 | 
			
		||||
				this.popupViews.splice(popupIndex, 1);
 | 
			
		||||
@ -117,33 +130,33 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
					if (!poppedView?.options?.shadeCover?.ignoreShadeRestore) {
 | 
			
		||||
						const shadeCoverOptions = this.popupViews[this.popupViews.length - 1]?.options?.shadeCover;
 | 
			
		||||
						if (shadeCoverOptions) {
 | 
			
		||||
						this.updateShadeCover(this.shadeCover, shadeCoverOptions);
 | 
			
		||||
							return this.updateShadeCover(this.shadeCover, shadeCoverOptions);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					// remove shade cover animation if this is the last opened popup view
 | 
			
		||||
					if (this.popupViews.length === 0) {
 | 
			
		||||
					this.closeShadeCover(poppedView?.options?.shadeCover);
 | 
			
		||||
						return this.closeShadeCover(poppedView?.options?.shadeCover);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			})
 | 
			
		||||
			.then(() => {
 | 
			
		||||
				if (exitAnimationDefinition) {
 | 
			
		||||
				this.getExitAnimation(view, exitAnimationDefinition)
 | 
			
		||||
					return this.getExitAnimation(view, exitAnimationDefinition)
 | 
			
		||||
						.play()
 | 
			
		||||
						.then(cleanupAndFinish.bind(this))
 | 
			
		||||
					.catch((ex) => {
 | 
			
		||||
						reject(new Error(`Error playing exit animation: ${ex}`));
 | 
			
		||||
					});
 | 
			
		||||
			} else {
 | 
			
		||||
				cleanupAndFinish();
 | 
			
		||||
						.catch((ex) => Promise.reject(new Error(`Error playing exit animation: ${ex}`)));
 | 
			
		||||
				}
 | 
			
		||||
				cleanupAndFinish();
 | 
			
		||||
			});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	closeAll(): Promise<void[]> {
 | 
			
		||||
		const toClose = [];
 | 
			
		||||
		const views = this.popupViews.map((popupView) => popupView.view);
 | 
			
		||||
 | 
			
		||||
		// Close all views at the same time and wait for all of them
 | 
			
		||||
		while (this.popupViews.length > 0) {
 | 
			
		||||
			toClose.push(this.close(this.popupViews[this.popupViews.length - 1].view));
 | 
			
		||||
		for (const view of views) {
 | 
			
		||||
			toClose.push(this.close(view));
 | 
			
		||||
		}
 | 
			
		||||
		return Promise.all(toClose);
 | 
			
		||||
	}
 | 
			
		||||
@ -342,7 +355,7 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
		return shadeCover;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private updateShadeCover(shade: View, shadeOptions: ShadeCoverOptions = {}): void {
 | 
			
		||||
	private updateShadeCover(shade: View, shadeOptions: ShadeCoverOptions = {}): Promise<void> {
 | 
			
		||||
		if (shadeOptions.tapToClose !== undefined && shadeOptions.tapToClose !== null) {
 | 
			
		||||
			shade.off('tap');
 | 
			
		||||
			if (shadeOptions.tapToClose) {
 | 
			
		||||
@ -351,7 +364,7 @@ export class RootLayoutBase extends GridLayout {
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		this._updateShadeCover(shade, shadeOptions);
 | 
			
		||||
		return this._updateShadeCover(shade, shadeOptions);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private hasChild(view: View): boolean {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user