MOBILE-3153 mainmenu: Implement User Menu tour
parent
58e6be64e4
commit
c5f6b058db
|
@ -2003,6 +2003,8 @@
|
|||
"core.mainmenu.home": "moodle",
|
||||
"core.mainmenu.logout": "moodle",
|
||||
"core.mainmenu.switchaccount": "local_moodlemobileapp",
|
||||
"core.mainmenu.usermenutourdescription": "local_moodlemobileapp",
|
||||
"core.mainmenu.usermenutourtitle": "local_moodlemobileapp",
|
||||
"core.maxfilesize": "moodle",
|
||||
"core.maxsizeandattachments": "moodle",
|
||||
"core.min": "moodle",
|
||||
|
@ -2335,6 +2337,7 @@
|
|||
"core.usernotfullysetup": "error",
|
||||
"core.users": "moodle",
|
||||
"core.usersuspended": "tool_reportbuilder",
|
||||
"core.endonesteptour": "tool_usertours",
|
||||
"core.view": "moodle",
|
||||
"core.viewcode": "local_moodlemobileapp",
|
||||
"core.vieweditor": "local_moodlemobileapp",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 269 173"><path d="M130.298 171.955a1.999 1.999 0 1 0 2.404-3.196l-2.404 3.196Zm137.887-153.65a2 2 0 0 0 .426-2.796l-10.665-14.5a2 2 0 1 0-3.222 2.37l9.48 12.89-12.889 9.48a2 2 0 1 0 2.37 3.222l14.5-10.665ZM124.847 36.115c14.837-13.515 33.816-20.396 57.372-22.633 23.592-2.242 51.644.187 84.48 5.19l.602-3.954c-32.918-5.016-61.365-7.507-85.46-5.218-24.131 2.292-44.025 9.391-59.688 23.657l2.694 2.958Zm34.44 79.302c-13.382 1.869-23.94-.552-31.827-5.493-7.898-4.946-13.278-12.519-16.124-21.225-5.717-17.49-1.113-39.265 13.511-52.584l-2.694-2.958c-15.876 14.46-20.786 37.916-14.619 56.785 3.096 9.473 9.008 17.864 17.803 23.372 8.804 5.515 20.34 8.043 34.504 6.064l-.554-3.961Zm-26.585 53.343c-25.76-19.374-35.531-44.979-33.124-66.267 2.404-21.255 16.912-38.345 40.27-41.227l-.49-3.97c-25.369 3.13-41.163 21.836-43.754 44.747-2.587 22.876 7.954 49.803 34.694 69.913l2.404-3.196Zm7.146-107.494c23.592-2.91 41.413 9.316 46.813 22.682 2.682 6.636 2.305 13.48-1.745 19.109-4.087 5.679-12.172 10.48-25.629 12.36l.554 3.961c14.089-1.968 23.372-7.107 28.321-13.985 4.986-6.928 5.312-15.26 2.208-22.943-6.171-15.272-25.876-28.255-51.012-25.154l.49 3.97Z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -32,6 +32,7 @@ import { CoreSwipeNavigationDirective } from './swipe-navigation';
|
|||
import { CoreCollapsibleItemDirective } from './collapsible-item';
|
||||
import { CoreCollapsibleFooterDirective } from './collapsible-footer';
|
||||
import { CoreContentDirective } from './content';
|
||||
import { CoreOnAppearDirective } from './on-appear';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -46,6 +47,7 @@ import { CoreContentDirective } from './content';
|
|||
CoreSupressEventsDirective,
|
||||
CoreUserLinkDirective,
|
||||
CoreAriaButtonClickDirective,
|
||||
CoreOnAppearDirective,
|
||||
CoreOnResizeDirective,
|
||||
CoreDownloadFileDirective,
|
||||
CoreCollapsibleHeaderDirective,
|
||||
|
@ -66,6 +68,7 @@ import { CoreContentDirective } from './content';
|
|||
CoreSupressEventsDirective,
|
||||
CoreUserLinkDirective,
|
||||
CoreAriaButtonClickDirective,
|
||||
CoreOnAppearDirective,
|
||||
CoreOnResizeDirective,
|
||||
CoreDownloadFileDirective,
|
||||
CoreCollapsibleHeaderDirective,
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Directive, ElementRef, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
||||
/**
|
||||
* Directive to listen when an element becomes visible.
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[onAppear]',
|
||||
})
|
||||
export class CoreOnAppearDirective implements OnInit, OnDestroy {
|
||||
|
||||
@Output() onAppear = new EventEmitter();
|
||||
|
||||
private element: HTMLElement;
|
||||
private interval?: number;
|
||||
|
||||
constructor(element: ElementRef) {
|
||||
this.element = element.nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.interval = window.setInterval(() => {
|
||||
if (!CoreDomUtils.isElementVisible(this.element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onAppear.emit();
|
||||
window.clearInterval(this.interval);
|
||||
|
||||
delete this.interval;
|
||||
}, 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.interval && window.clearInterval(this.interval);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,11 +17,13 @@ import { CoreSharedModule } from '@/core/shared.module';
|
|||
import { CoreMainMenuUserButtonComponent } from './user-menu-button/user-menu-button';
|
||||
import { CoreMainMenuUserMenuComponent } from './user-menu/user-menu';
|
||||
import { CoreLoginComponentsModule } from '@features/login/components/components.module';
|
||||
import { CoreMainMenuUserMenuTourComponent } from './user-menu-tour/user-menu-tour';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreMainMenuUserButtonComponent,
|
||||
CoreMainMenuUserMenuComponent,
|
||||
CoreMainMenuUserMenuTourComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
|
@ -30,6 +32,7 @@ import { CoreLoginComponentsModule } from '@features/login/components/components
|
|||
exports: [
|
||||
CoreMainMenuUserButtonComponent,
|
||||
CoreMainMenuUserMenuComponent,
|
||||
CoreMainMenuUserMenuTourComponent,
|
||||
],
|
||||
})
|
||||
export class CoreMainMenuComponentsModule {}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<core-user-avatar *ngIf="isMainScreen && siteInfo" [user]="siteInfo" class="core-bar-button-image clickable" [linkProfile]="false"
|
||||
(ariaButtonClick)="openUserMenu($event)" role="button" tabindex="0" [attr.aria-label]="'core.user.useraccount' | translate">
|
||||
(ariaButtonClick)="openUserMenu($event)" (onAppear)="showTour()" role="button" tabindex="0"
|
||||
[attr.aria-label]="'core.user.useraccount' | translate" #avatar>
|
||||
</core-user-avatar>
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { CoreSiteInfo } from '@classes/site';
|
||||
import { CoreUserTours, CoreUserToursStyle } from '@features/usertours/services/user-tours';
|
||||
import { IonRouterOutlet } from '@ionic/angular';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreMainMenuUserMenuTourComponent } from '../user-menu-tour/user-menu-tour';
|
||||
import { CoreMainMenuUserMenuComponent } from '../user-menu/user-menu';
|
||||
|
||||
/**
|
||||
|
@ -34,6 +36,8 @@ export class CoreMainMenuUserButtonComponent implements OnInit {
|
|||
siteInfo?: CoreSiteInfo;
|
||||
isMainScreen = false;
|
||||
|
||||
@ViewChild('avatar', { read: ElementRef }) avatar?: ElementRef<HTMLElement>;
|
||||
|
||||
constructor(protected routerOutlet: IonRouterOutlet) {
|
||||
const currentSite = CoreSites.getRequiredCurrentSite();
|
||||
|
||||
|
@ -61,4 +65,20 @@ export class CoreMainMenuUserButtonComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show User Tour.
|
||||
*/
|
||||
async showTour(): Promise<void> {
|
||||
if (!this.avatar) {
|
||||
return;
|
||||
}
|
||||
|
||||
await CoreUserTours.showIfPending({
|
||||
id: 'user-menu',
|
||||
component: CoreMainMenuUserMenuTourComponent,
|
||||
focus: this.avatar.nativeElement,
|
||||
style: CoreUserToursStyle.Overlay,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<img src="assets/img/user-tours/user-menu.svg" alt="" />
|
||||
<h2>{{ 'core.mainmenu.usermenutourtitle' | translate }}</h2>
|
||||
<p>{{ 'core.mainmenu.usermenutourdescription' | translate }}</p>
|
||||
<ion-button (click)="dismiss()" expand="block">
|
||||
{{ 'core.endonesteptour' | translate }}
|
||||
</ion-button>
|
|
@ -0,0 +1,26 @@
|
|||
:host {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
max-width: 85vw;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
img {
|
||||
width: calc(100vw - var(--core-avatar-size) * 2 - 16px);
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ion-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
:host-context([dir=rtl]) img {
|
||||
transform: scaleX(-1);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreUserTours } from '@features/usertours/services/user-tours';
|
||||
|
||||
/**
|
||||
* Component showing the User Tour for the User Menu feature.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-mainmenu-user-menu-tour',
|
||||
templateUrl: 'user-menu-tour.html',
|
||||
styleUrls: ['user-menu-tour.scss'],
|
||||
})
|
||||
export class CoreMainMenuUserMenuTourComponent {
|
||||
|
||||
/**
|
||||
* Dismiss the User Tour.
|
||||
*/
|
||||
async dismiss(): Promise<void> {
|
||||
await CoreUserTours.dismiss();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"home": "Home",
|
||||
"logout": "Log out",
|
||||
"switchaccount": "Switch account"
|
||||
"switchaccount": "Switch account",
|
||||
"usermenutourdescription": "The place to check your grades, change your preferences or switch accounts.",
|
||||
"usermenutourtitle": "Explore your personal area"
|
||||
}
|
||||
|
|
|
@ -329,6 +329,7 @@
|
|||
"usernotfullysetup": "User not fully set-up",
|
||||
"usernologin": "Authentication has been revoked for this account",
|
||||
"usersuspended": "Registration suspended",
|
||||
"endonesteptour": "Got it",
|
||||
"users": "Users",
|
||||
"view": "View",
|
||||
"viewcode": "View code",
|
||||
|
|
|
@ -806,6 +806,24 @@ export class CoreDomUtilsProvider {
|
|||
return elementPoint > window.innerHeight || elementPoint < scrollTopPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an element is visible or not.
|
||||
*
|
||||
* @param element Element.
|
||||
*/
|
||||
isElementVisible(element: HTMLElement): boolean {
|
||||
if (element.clientWidth === 0 || element.clientHeight === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const style = getComputedStyle(element);
|
||||
if (style.opacity === '0' || style.display === 'none' || style.visibility === 'hidden') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return element.offsetParent !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if rich text editor is enabled.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue