Merge pull request #3357 from NoelDeMartin/MOBILE-4069

MOBILE-4069 core: Fix race condition in loading
main
Pau Ferrer Ocaña 2022-08-08 12:49:44 +02:00 committed by GitHub
commit 2407240134
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 28 deletions

View File

@ -50,15 +50,15 @@ import { AsyncComponent } from '@classes/async-component';
}) })
export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, AsyncComponent { export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, AsyncComponent {
@Input() hideUntil = false; // Determine when should the contents be shown. @Input() hideUntil: unknown = false; // Determine when should the contents be shown.
@Input() message?: string; // Message to show while loading. @Input() message?: string; // Message to show while loading.
@Input() fullscreen = true; // Use the whole screen. @Input() fullscreen = true; // Use the whole screen.
uniqueId: string; uniqueId: string;
loaded = false; loaded = false;
protected scroll = 0;
protected element: HTMLElement; // Current element. protected element: HTMLElement; // Current element.
protected lastScrollPosition = Promise.resolve<number | undefined>(undefined);
protected onReadyPromise = new CorePromisedValue<void>(); protected onReadyPromise = new CorePromisedValue<void>();
constructor(element: ElementRef) { constructor(element: ElementRef) {
@ -85,7 +85,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
* @inheritdoc * @inheritdoc
*/ */
ngAfterViewInit(): void { ngAfterViewInit(): void {
this.changeState(this.hideUntil); this.changeState(!!this.hideUntil);
} }
/** /**
@ -93,7 +93,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
*/ */
ngOnChanges(changes: { [name: string]: SimpleChange }): void { ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.hideUntil) { if (changes.hideUntil) {
this.changeState(this.hideUntil); this.changeState(!!this.hideUntil);
} }
} }
@ -103,7 +103,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
* @param loaded True to load, false otherwise. * @param loaded True to load, false otherwise.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
async changeState(loaded: boolean): Promise<void> { changeState(loaded: boolean): void {
this.element.classList.toggle('core-loading-loaded', loaded); this.element.classList.toggle('core-loading-loaded', loaded);
this.element.setAttribute('aria-busy', loaded ? 'false' : 'true'); this.element.setAttribute('aria-busy', loaded ? 'false' : 'true');
@ -111,16 +111,13 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
return; return;
} }
if (!loaded) {
await this.saveScrollPosition();
}
this.loaded = loaded; this.loaded = loaded;
if (loaded) { if (loaded) {
this.onReadyPromise.resolve(); this.onReadyPromise.resolve();
this.restoreScrollPosition();
// Recover last scroll. } else {
await this.recoverScrollPosition(); this.lastScrollPosition = this.getScrollPosition();
} }
// Event has been deprecated since app 4.0. // Event has been deprecated since app 4.0.
@ -131,41 +128,36 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
} }
/** /**
* Saves current scroll position. * Gets current scroll position.
*/ */
protected async saveScrollPosition(): Promise<void> { protected async getScrollPosition(): Promise<number | undefined> {
const content = this.element.closest('ion-content'); const content = this.element.closest('ion-content');
if (!content) { const scrollElement = await content?.getScrollElement();
return;
}
const scrollElement = await content.getScrollElement(); return scrollElement?.scrollTop;
this.scroll = scrollElement.scrollTop;
} }
/** /**
* Recovers last set scroll position. * Restores last known scroll position.
*/ */
protected async recoverScrollPosition(): Promise<void> { protected async restoreScrollPosition(): Promise<void> {
if (this.scroll <= 0) { const scrollPosition = await this.lastScrollPosition;
if (scrollPosition === undefined) {
return; return;
} }
const content = this.element.closest('ion-content'); const content = this.element.closest('ion-content');
if (!content) { const scrollElement = await content?.getScrollElement();
return;
}
const scrollElement = await content.getScrollElement(); scrollElement?.scrollTo({ top: scrollPosition });
scrollElement.scrollTo(0, this.scroll);
} }
/** /**
* @inheritdoc * @inheritdoc
*/ */
async ready(): Promise<void> { async ready(): Promise<void> {
return await this.onReadyPromise; await this.onReadyPromise;
} }
} }