MOBILE-3153 usertours: Dismiss on removed elements
parent
0db4781814
commit
2e473ee55d
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue