MOBILE-3153 usertours: Dismiss on removed elements

main
Noel De Martin 2022-03-17 11:46:45 +01:00
parent 0db4781814
commit 2e473ee55d
2 changed files with 37 additions and 17 deletions

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AfterViewInit, Component, ElementRef, HostBinding, Input, ViewChild } from '@angular/core';
import { AfterViewInit, Component, ElementRef, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core';
import { CorePromisedValue } from '@classes/promised-value';
import { CoreUserToursFocusLayout } from '@features/usertours/classes/focus-layout';
import { CoreUserToursPopoverLayout } from '@features/usertours/classes/popover-layout';
@ -42,6 +42,8 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
@Input() focus?: HTMLElement;
@Input() side?: CoreUserToursSide;
@Input() alignment?: CoreUserToursAlignment;
@Output() beforeDismiss = new EventEmitter<void>();
@Output() afterDismiss = new EventEmitter<void>();
@HostBinding('class.is-active') active = false;
@HostBinding('class.is-popover') popover = false;
@ViewChild('wrapper') wrapper?: ElementRef<HTMLElement>;
@ -80,6 +82,13 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
await CoreDomUtils.waitForImages(tour);
// Calculate focus styles or dismiss if the element is gone.
if (this.focus && !CoreDomUtils.isElementVisible(this.focus)) {
await this.dismiss(false);
return;
}
this.calculateStyles();
// Show tour.
@ -94,11 +103,15 @@ export class CoreUserToursUserTourComponent implements AfterViewInit {
* @param acknowledge Whether to confirm that the user has seen the User Tour.
*/
async dismiss(acknowledge: boolean = true): Promise<void> {
this.beforeDismiss.emit();
await this.playLeaveAnimation();
await Promise.all<unknown>([
AngularFrameworkDelegate.removeViewFromDom(this.container, this.element),
acknowledge && CoreUserTours.acknowledge(this.id),
]);
AngularFrameworkDelegate.removeViewFromDom(this.container, this.element);
acknowledge && CoreUserTours.acknowledge(this.id);
this.afterDismiss.emit();
}
/**

View File

@ -21,6 +21,7 @@ import { CoreApp } from '@services/app';
import { CoreUtils } from '@services/utils/utils';
import { AngularFrameworkDelegate, makeSingleton } from '@singletons';
import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreSubscriptions } from '@singletons/subscriptions';
import { CoreUserToursUserTourComponent } from '../components/user-tour/user-tour';
import { APP_SCHEMA, CoreUserToursDBEntry, USER_TOURS_TABLE_NAME } from './database/user-tours';
@ -106,8 +107,10 @@ export class CoreUserToursService {
protected async show(options: CoreUserToursBasicOptions | CoreUserToursFocusedOptions): Promise<void> {
const { delay, ...componentOptions } = options;
// Delay start.
await CoreUtils.wait(delay ?? 200);
// Create tour.
const container = document.querySelector('ion-app') ?? document.body;
const element = await AngularFrameworkDelegate.attachViewToDom(
container,
@ -117,6 +120,22 @@ export class CoreUserToursService {
const tour = CoreComponentsRegistry.require(element, CoreUserToursUserTourComponent);
this.tours.push(tour);
// Handle present/dismiss lifecycle.
CoreSubscriptions.once(tour.beforeDismiss, () => {
const index = this.tours.indexOf(tour);
if (index === -1) {
return;
}
this.tours.splice(index, 1);
const nextTour = this.tours[0] as CoreUserToursUserTourComponent | undefined;
nextTour?.present().then(() => this.tourReadyCallbacks.get(nextTour)?.());
});
this.tours.length > 1
? await new Promise<void>(resolve => this.tourReadyCallbacks.set(tour, resolve))
: await tour.present();
@ -128,19 +147,7 @@ export class CoreUserToursService {
* @param acknowledge Whether to acknowledge that the user has seen this User Tour or not.
*/
async dismiss(acknowledge: boolean = true): Promise<void> {
if (this.tours.length === 0) {
return;
}
const activeTour = this.tours.shift() as CoreUserToursUserTourComponent;
const nextTour = this.tours[0] as CoreUserToursUserTourComponent | undefined;
await Promise.all([
activeTour.dismiss(acknowledge),
nextTour?.present(),
]);
nextTour && this.tourReadyCallbacks.get(nextTour)?.();
await this.tours[0]?.dismiss(acknowledge);
}
}