MOBILE-4329 user: Rename user profile handler types

main
Pau Ferrer Ocaña 2024-02-20 15:49:25 +01:00
parent dddc95bfc6
commit cc2f238d68
19 changed files with 183 additions and 120 deletions

View File

@ -16,9 +16,9 @@ import { Injectable } from '@angular/core';
import { CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses'; import { CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses';
import { import {
CoreUserDelegateContext, CoreUserDelegateContext,
CoreUserDelegateService,
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
CoreUserProfileHandlerType,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
@ -33,7 +33,7 @@ export class AddonBadgesUserHandlerService implements CoreUserProfileHandler {
name = 'AddonBadges:fakename'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext. name = 'AddonBadges:fakename'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
priority = 300; priority = 300;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
/** /**
* @inheritdoc * @inheritdoc

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { import {
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserDelegateContext, CoreUserDelegateContext,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
@ -32,7 +32,7 @@ export class AddonBlogUserHandlerService implements CoreUserProfileHandler {
name = 'AddonBlog'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext. name = 'AddonBlog'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
priority = 200; priority = 200;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
/** /**
* @inheritdoc * @inheritdoc

View File

@ -18,7 +18,7 @@ import { COURSE_PAGE_NAME } from '@features/course/course.module';
import { CoreUserProfile } from '@features/user/services/user'; import { CoreUserProfile } from '@features/user/services/user';
import { import {
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
CoreUserDelegateContext, CoreUserDelegateContext,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
@ -36,7 +36,7 @@ export class AddonCompetencyUserHandlerService implements CoreUserProfileHandler
name = 'AddonCompetency'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext. name = 'AddonCompetency'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
priority = 100; priority = 100;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
cacheEnabled = true; cacheEnabled = true;
/** /**

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { CoreUserProfile } from '@features/user/services/user'; import { CoreUserProfile } from '@features/user/services/user';
import { import {
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
CoreUserDelegateContext, CoreUserDelegateContext,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
@ -31,7 +31,7 @@ import { AddonCourseCompletion } from '../coursecompletion';
export class AddonCourseCompletionUserHandlerService implements CoreUserProfileHandler { export class AddonCourseCompletionUserHandlerService implements CoreUserProfileHandler {
name = 'AddonCourseCompletion:viewCompletion'; name = 'AddonCourseCompletion:viewCompletion';
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
priority = 350; priority = 350;
cacheEnabled = true; cacheEnabled = true;

View File

@ -15,7 +15,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { CoreUserProfile } from '@features/user/services/user'; import { CoreUserProfile } from '@features/user/services/user';
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate'; import {
CoreUserProfileHandlerType,
CoreUserProfileHandler,
CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
@ -29,7 +33,7 @@ export class AddonMessagesSendMessageUserHandlerService implements CoreUserProfi
name = 'AddonMessages:sendMessage'; name = 'AddonMessages:sendMessage';
priority = 1000; priority = 1000;
type = CoreUserDelegateService.TYPE_COMMUNICATION; type = CoreUserProfileHandlerType.BUTTON;
/** /**
* @inheritdoc * @inheritdoc

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { CoreUserProfile } from '@features/user/services/user'; import { CoreUserProfile } from '@features/user/services/user';
import { import {
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
CoreUserDelegateContext, CoreUserDelegateContext,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
@ -33,7 +33,7 @@ export class AddonNotesUserHandlerService implements CoreUserProfileHandler {
name = 'AddonNotes:notes'; name = 'AddonNotes:notes';
priority = 250; priority = 250;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
cacheEnabled = true; cacheEnabled = true;
/** /**

View File

@ -18,7 +18,7 @@ import { AddonPrivateFiles } from '@addons/privatefiles/services/privatefiles';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { import {
CoreUserDelegateContext, CoreUserDelegateContext,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
@ -36,7 +36,7 @@ export class AddonPrivateFilesUserHandlerService implements CoreUserProfileHandl
name = 'AddonPrivateFiles'; name = 'AddonPrivateFiles';
priority = 400; priority = 400;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
cacheEnabled = true; cacheEnabled = true;
/** /**

View File

@ -13,7 +13,11 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate'; import {
CoreUserProfileHandlerType,
CoreUserProfileHandler,
CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { CoreDataPrivacy } from '../dataprivacy'; import { CoreDataPrivacy } from '../dataprivacy';
@ -27,7 +31,7 @@ export class CoreDataPrivacyUserHandlerService implements CoreUserProfileHandler
protected pageName = CORE_DATAPRIVACY_PAGE_NAME; protected pageName = CORE_DATAPRIVACY_PAGE_NAME;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ACCOUNT_ITEM;
name = 'CoreDataPrivacyDelegate'; name = 'CoreDataPrivacyDelegate';
priority = 100; priority = 100;

View File

@ -19,7 +19,7 @@ import { CoreGrades } from '@features/grades/services/grades';
import { CoreUserProfile } from '@features/user/services/user'; import { CoreUserProfile } from '@features/user/services/user';
import { import {
CoreUserDelegateContext, CoreUserDelegateContext,
CoreUserDelegateService , CoreUserProfileHandlerType ,
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
@ -38,7 +38,7 @@ export class CoreGradesUserHandlerService implements CoreUserProfileHandler {
name = 'CoreGrades'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext. name = 'CoreGrades'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
priority = 500; priority = 500;
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
cacheEnabled = true; cacheEnabled = true;
/** /**

View File

@ -40,7 +40,7 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item button class="core-usermenu-handler ion-text-wrap" *ngIf="siteInfo" lines="full" (click)="openUserProfile($event)" <ion-item button class="core-usermenu-profile ion-text-wrap" *ngIf="siteInfo" lines="full" (click)="openUserProfile($event)"
[detail]="true" [attr.aria-label]="'core.user.profile' | translate"> [detail]="true" [attr.aria-label]="'core.user.profile' | translate">
<core-user-avatar [site]="siteInfo" [userId]="siteInfo.userid" [linkProfile]="false" slot="start" /> <core-user-avatar [site]="siteInfo" [userId]="siteInfo.userid" [linkProfile]="false" slot="start" />
<ion-label> <ion-label>
@ -48,12 +48,7 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-center" *ngIf="(!handlers || !handlers.length) && !handlersLoaded"> @if (handlers.length + accountHandlers.length > 0) {
<ion-label>
<ion-spinner [attr.aria-label]="'core.loading' | translate" />
</ion-label>
</ion-item>
<ion-item button *ngFor="let handler of handlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)" <ion-item button *ngFor="let handler of handlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)"
[ngClass]="['core-user-menu-handler', handler.class || '']" [hidden]="handler.hidden" [ngClass]="['core-user-menu-handler', handler.class || '']" [hidden]="handler.hidden"
[attr.aria-label]="handler.title | translate" [detail]="true"> [attr.aria-label]="handler.title | translate" [detail]="true">
@ -70,8 +65,35 @@
<ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate" /> <ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate" />
</ion-item> </ion-item>
<ion-item button *ngFor="let handler of accountHandlers; let first = first" class="ion-text-wrap"
(click)="handlerClicked($event, handler)"
[ngClass]="['core-user-account-menu-handler', handler.class || '', first ? 'core-user-menu-separator' : '']"
[hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [detail]="true">
<ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true" />
<ion-label>
<p class="item-heading">{{ handler.title | translate }}</p>
</ion-label>
<ion-badge slot="end" *ngIf="handler.showBadge" [hidden]="handler.loading || !handler.badge" aria-hidden="true">
{{handler.badge}}
</ion-badge>
<span *ngIf="handler.showBadge && handler.badge && handler.badgeA11yText" class="sr-only">
{{ handler.badgeA11yText | translate: {$a : handler.badge } }}
</span>
<ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate" />
</ion-item>
} @else {
<ion-item class="ion-text-center">
<ion-label>
<ion-spinner [attr.aria-label]="'core.loading' | translate" />
</ion-label>
</ion-item>
}
<ion-item button (click)="openPreferences($event)" [attr.aria-label]="'core.settings.preferences' | translate" [detail]="true" <ion-item button (click)="openPreferences($event)" [attr.aria-label]="'core.settings.preferences' | translate" [detail]="true"
class="core-user-menu-preferences"> class="core-user-menu-preferences core-user-menu-separator">
<ion-icon name="fas-wrench" slot="start" aria-hidden="true" /> <ion-icon name="fas-wrench" slot="start" aria-hidden="true" />
<ion-label> <ion-label>
<p class="item-heading">{{ 'core.settings.preferences' | translate }}</p> <p class="item-heading">{{ 'core.settings.preferences' | translate }}</p>

View File

@ -1,7 +1,7 @@
@use "theme/globals" as *; @use "theme/globals" as *;
:host { :host {
.core-user-menu-preferences { .core-user-menu-separator {
--inner-border-width: 0; --inner-border-width: 0;
--border-width: 1px 0 0 0; --border-width: 1px 0 0 0;
} }

View File

@ -25,12 +25,13 @@ import { CoreUser, CoreUserProfile } from '@features/user/services/user';
import { import {
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
CoreUserDelegate, CoreUserDelegate,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserDelegateContext, CoreUserDelegateContext,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { ModalController, Translate } from '@singletons'; import { ModalController, Translate } from '@singletons';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@ -52,6 +53,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
siteUrl?: string; siteUrl?: string;
displaySiteUrl = false; displaySiteUrl = false;
handlers: CoreUserProfileHandlerData[] = []; handlers: CoreUserProfileHandlerData[] = [];
accountHandlers: CoreUserProfileHandlerData[] = [];
handlersLoaded = false; handlersLoaded = false;
user?: CoreUserProfile; user?: CoreUserProfile;
displaySwitchAccount = true; displaySwitchAccount = true;
@ -76,37 +78,48 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
this.loadSiteLogo(currentSite); this.loadSiteLogo(currentSite);
// Load the handlers. if (!this.siteInfo) {
if (this.siteInfo) { return;
try {
this.user = await CoreUser.getProfile(this.siteInfo.userid);
} catch {
this.user = {
id: this.siteInfo.userid,
fullname: this.siteInfo.fullname,
};
}
this.subscription = CoreUserDelegate.getProfileHandlersFor(this.user, CoreUserDelegateContext.USER_MENU)
.subscribe((handlers) => {
if (!handlers || !this.user) {
return;
}
const newHandlers = handlers
.filter((handler) => handler.type === CoreUserDelegateService.TYPE_NEW_PAGE)
.map((handler) => handler.data);
// Only update handlers if they have changed, to prevent a blink effect.
if (newHandlers.length !== this.handlers.length ||
JSON.stringify(newHandlers) !== JSON.stringify(this.handlers)) {
this.handlers = newHandlers;
}
this.handlersLoaded = CoreUserDelegate.areHandlersLoaded(this.user.id, CoreUserDelegateContext.USER_MENU);
});
} }
// Load the handlers.
try {
this.user = await CoreUser.getProfile(this.siteInfo.userid);
} catch {
this.user = {
id: this.siteInfo.userid,
fullname: this.siteInfo.fullname,
};
}
this.subscription = CoreUserDelegate.getProfileHandlersFor(this.user, CoreUserDelegateContext.USER_MENU)
.subscribe((handlers) => {
if (!handlers.length || !this.user) {
return;
}
let newHandlers = handlers
.filter((handler) => handler.type === CoreUserProfileHandlerType.LIST_ITEM)
.map((handler) => handler.data);
// Only update handlers if they have changed, to prevent a blink effect.
if (newHandlers.length !== this.handlers.length ||
JSON.stringify(newHandlers) !== JSON.stringify(this.handlers)) {
this.handlers = newHandlers;
}
newHandlers = handlers
.filter((handler) => handler.type === CoreUserProfileHandlerType.LIST_ACCOUNT_ITEM)
.map((handler) => handler.data);
// Only update handlers if they have changed, to prevent a blink effect.
if (newHandlers.length !== this.handlers.length ||
JSON.stringify(newHandlers) !== JSON.stringify(this.handlers)) {
this.accountHandlers = newHandlers;
}
this.handlersLoaded = CoreUserDelegate.areHandlersLoaded(this.user.id, CoreUserDelegateContext.USER_MENU);
});
} }
/** /**
@ -123,15 +136,9 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
return; return;
} }
try { const siteConfig = await CoreUtils.ignoreErrors(currentSite.getPublicConfig());
const siteConfig = await currentSite.getPublicConfig(); this.siteLogo = currentSite.getLogoUrl(siteConfig);
this.siteLogoLoaded = true;
this.siteLogo = currentSite.getLogoUrl(siteConfig);
} catch {
// Ignore errors.
} finally {
this.siteLogoLoaded = true;
}
} }
/** /**

View File

@ -13,7 +13,11 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate'; import {
CoreUserProfileHandlerType,
CoreUserProfileHandler,
CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { CoreReportBuilder } from '../reportbuilder'; import { CoreReportBuilder } from '../reportbuilder';
@ -26,7 +30,7 @@ export class CoreReportBuilderHandlerService implements CoreUserProfileHandler {
static readonly PAGE_NAME = 'reportbuilder'; static readonly PAGE_NAME = 'reportbuilder';
type = CoreUserDelegateService.TYPE_NEW_PAGE; type = CoreUserProfileHandlerType.LIST_ITEM;
cacheEnabled = true; cacheEnabled = true;
name = 'CoreReportBuilderDelegate'; name = 'CoreReportBuilderDelegate';
priority = 350; priority = 350;

View File

@ -22,7 +22,7 @@ import {
import { CoreUserProfile } from '@features/user/services/user'; import { CoreUserProfile } from '@features/user/services/user';
import { import {
CoreUserDelegateContext, CoreUserDelegateContext,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserProfileHandler, CoreUserProfileHandler,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
@ -36,7 +36,7 @@ import { CoreSitePluginsBaseHandler } from './base-handler';
export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandler implements CoreUserProfileHandler { export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandler implements CoreUserProfileHandler {
priority: number; priority: number;
type: string; type: CoreUserProfileHandlerType;
protected updatingDefer?: CorePromisedValue<void>; protected updatingDefer?: CorePromisedValue<void>;
@ -51,9 +51,10 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
this.priority = handlerSchema.priority || 0; this.priority = handlerSchema.priority || 0;
// Only support TYPE_COMMUNICATION and TYPE_NEW_PAGE. // Only support LIST_ITEM and BUTTON.
this.type = handlerSchema.type != CoreUserDelegateService.TYPE_COMMUNICATION ? this.type = !handlerSchema.type || handlerSchema.type === CoreUserProfileHandlerType.LIST_ACCOUNT_ITEM
CoreUserDelegateService.TYPE_NEW_PAGE : CoreUserDelegateService.TYPE_COMMUNICATION; ? CoreUserProfileHandlerType.LIST_ITEM
: handlerSchema.type;
} }
/** /**

View File

@ -33,6 +33,7 @@ import { CorePromisedValue } from '@classes/promised-value';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreEnrolAction, CoreEnrolInfoIcon } from '@features/enrol/services/enrol-delegate'; import { CoreEnrolAction, CoreEnrolInfoIcon } from '@features/enrol/services/enrol-delegate';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { CoreUserProfileHandlerType } from '@features/user/services/user-delegate';
const ROOT_CACHE_KEY = 'CoreSitePlugins:'; const ROOT_CACHE_KEY = 'CoreSitePlugins:';
@ -907,7 +908,7 @@ export type CoreSitePluginsUserHandlerData = CoreSitePluginsHandlerCommonData &
icon?: string; icon?: string;
class?: string; class?: string;
}; };
type?: string; type?: CoreUserProfileHandlerType;
priority?: number; priority?: number;
ptrenabled?: boolean; ptrenabled?: boolean;
}; };

View File

@ -33,11 +33,10 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<div class="core-user-communication-handlers" <div class="core-user-communication-handlers" *ngIf="(buttonHandlers && buttonHandlers.length) || isLoadingHandlers">
*ngIf="(communicationHandlers && communicationHandlers.length) || isLoadingHandlers"> <ion-item *ngIf="buttonHandlers && buttonHandlers.length">
<ion-item *ngIf="communicationHandlers && communicationHandlers.length">
<ion-label> <ion-label>
<ion-button *ngFor="let handler of communicationHandlers" expand="block" size="default" <ion-button *ngFor="let handler of buttonHandlers" expand="block" size="default"
[ngClass]="['core-user-profile-handler', handler.class || '']" (click)="handlerClicked($event, handler)" [ngClass]="['core-user-profile-handler', handler.class || '']" (click)="handlerClicked($event, handler)"
[hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [disabled]="handler.spinner"> [hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [disabled]="handler.spinner">
<ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true" /> <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true" />
@ -61,7 +60,7 @@
<ion-spinner [attr.aria-label]="'core.loading' | translate" /> <ion-spinner [attr.aria-label]="'core.loading' | translate" />
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item button *ngFor="let handler of newPageHandlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)" <ion-item button *ngFor="let handler of listItemHandlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)"
[ngClass]="['core-user-profile-handler', handler.class || '']" [hidden]="handler.hidden" [ngClass]="['core-user-profile-handler', handler.class || '']" [hidden]="handler.hidden"
[attr.aria-label]="handler.title | translate" [detail]="true"> [attr.aria-label]="handler.title | translate" [detail]="true">
<ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true" /> <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true" />
@ -76,17 +75,6 @@
</span> </span>
<ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate" /> <ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate" />
</ion-item> </ion-item>
<ion-item *ngIf="actionHandlers && actionHandlers.length">
<ion-label>
<ion-button *ngFor="let handler of actionHandlers" expand="block" fill="outline" size="default"
[ngClass]="['core-user-profile-handler', handler.class || '']" (click)="handlerClicked($event, handler)"
[hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [disabled]="handler.spinner">
<ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true" />
{{ handler.title | translate }}
<ion-spinner *ngIf="handler.spinner" slot="end" [attr.aria-label]="'core.loading' | translate" />
</ion-button>
</ion-label>
</ion-item>
</ion-list> </ion-list>
<core-empty-box *ngIf="!user && !isDeleted && isEnrolled" icon="far-user" <core-empty-box *ngIf="!user && !isDeleted && isEnrolled" icon="far-user"
[message]=" 'core.user.detailsnotavailable' | translate" /> [message]=" 'core.user.detailsnotavailable' | translate" />

View File

@ -25,7 +25,7 @@ import { CoreUserHelper } from '@features/user/services/user-helper';
import { import {
CoreUserDelegate, CoreUserDelegate,
CoreUserDelegateContext, CoreUserDelegateContext,
CoreUserDelegateService, CoreUserProfileHandlerType,
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
} from '@features/user/services/user-delegate'; } from '@features/user/services/user-delegate';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
@ -59,9 +59,8 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
isSuspended = false; isSuspended = false;
isEnrolled = true; isEnrolled = true;
rolesFormatted?: string; rolesFormatted?: string;
actionHandlers: CoreUserProfileHandlerData[] = []; listItemHandlers: CoreUserProfileHandlerData[] = [];
newPageHandlers: CoreUserProfileHandlerData[] = []; buttonHandlers: CoreUserProfileHandlerData[] = [];
communicationHandlers: CoreUserProfileHandlerData[] = [];
users?: CoreUserSwipeItemsManager; users?: CoreUserSwipeItemsManager;
@ -153,20 +152,19 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
const context = this.courseId ? CoreUserDelegateContext.COURSE : CoreUserDelegateContext.SITE; const context = this.courseId ? CoreUserDelegateContext.COURSE : CoreUserDelegateContext.SITE;
this.subscription = CoreUserDelegate.getProfileHandlersFor(user, context, this.courseId).subscribe((handlers) => { this.subscription = CoreUserDelegate.getProfileHandlersFor(user, context, this.courseId).subscribe((handlers) => {
this.actionHandlers = []; this.listItemHandlers = [];
this.newPageHandlers = []; this.buttonHandlers = [];
this.communicationHandlers = [];
handlers.forEach((handler) => { handlers.forEach((handler) => {
switch (handler.type) { switch (handler.type) {
case CoreUserDelegateService.TYPE_COMMUNICATION: case CoreUserProfileHandlerType.BUTTON:
this.communicationHandlers.push(handler.data); this.buttonHandlers.push(handler.data);
break; break;
case CoreUserDelegateService.TYPE_ACTION: case CoreUserProfileHandlerType.LIST_ACCOUNT_ITEM:
this.actionHandlers.push(handler.data); // Discard this for now.
break; break;
case CoreUserDelegateService.TYPE_NEW_PAGE: case CoreUserProfileHandlerType.LIST_ITEM:
default: default:
this.newPageHandlers.push(handler.data); this.listItemHandlers.push(handler.data);
break; break;
} }
}); });

View File

@ -14,7 +14,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '../user-delegate'; import {
CoreUserProfileHandlerType,
CoreUserProfileHandler,
CoreUserProfileHandlerData,
} from '../user-delegate';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreUserProfile } from '../user'; import { CoreUserProfile } from '../user';
@ -28,7 +32,7 @@ export class CoreUserProfileMailHandlerService implements CoreUserProfileHandler
name = 'CoreUserProfileMail'; name = 'CoreUserProfileMail';
priority = 700; priority = 700;
type = CoreUserDelegateService.TYPE_COMMUNICATION; type = CoreUserProfileHandlerType.BUTTON;
/** /**
* @inheritdoc * @inheritdoc

View File

@ -23,6 +23,12 @@ import { makeSingleton } from '@singletons';
import { CoreCourses, CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses'; import { CoreCourses, CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
export enum CoreUserProfileHandlerType {
LIST_ITEM = 'listitem', // User profile handler type to be shown as a list item.
LIST_ACCOUNT_ITEM = 'account_listitem', // User profile handler type to be shown as a list item and it's related to an account.
BUTTON = 'button', // User profile handler type to be shown as a button.
}
declare module '@singletons/events' { declare module '@singletons/events' {
/** /**
@ -46,13 +52,11 @@ export interface CoreUserProfileHandler extends CoreDelegateHandler {
priority: number; priority: number;
/** /**
* A type should be specified among these: * The type of Handler.
* - TYPE_COMMUNICATION: will be displayed under the user avatar. Should have icon. Spinner not used. *
* - TYPE_NEW_PAGE: will be displayed as a list of items. Should have icon. Spinner not used. * @see CoreUserProfileHandlerType for more info.
* Default value if none is specified.
* - TYPE_ACTION: will be displayed as a button and should not redirect to any state. Spinner use is recommended.
*/ */
type: string; type: CoreUserProfileHandlerType;
/** /**
* If isEnabledForUser Cache should be enabled. * If isEnabledForUser Cache should be enabled.
@ -106,7 +110,7 @@ export interface CoreUserProfileHandlerData {
title: string; title: string;
/** /**
* Name of the icon to display. Mandatory for TYPE_COMMUNICATION. * Name of the icon to display. Mandatory for CoreUserProfileHandlerType.BUTTON.
*/ */
icon?: string; icon?: string;
@ -116,32 +120,34 @@ export interface CoreUserProfileHandlerData {
class?: string; class?: string;
/** /**
* If enabled, element will be hidden. Only for TYPE_NEW_PAGE and TYPE_ACTION. * If enabled, element will be hidden. Only for CoreUserProfileHandlerType.LIST_ITEM.
*/ */
hidden?: boolean; hidden?: boolean;
/** /**
* If enabled will show an spinner. Only for TYPE_ACTION. * If enabled will show an spinner.
*
* @deprecated since 4.4. Not used anymore.
*/ */
spinner?: boolean; spinner?: boolean;
/** /**
* If the handler has badge to show or not. Only for TYPE_NEW_PAGE. * If the handler has badge to show or not. Only for CoreUserProfileHandlerType.LIST_ITEM.
*/ */
showBadge?: boolean; showBadge?: boolean;
/** /**
* Text to display on the badge. Only used if showBadge is true and only for TYPE_NEW_PAGE. * Text to display on the badge. Only used if showBadge is true and only for CoreUserProfileHandlerType.LIST_ITEM.
*/ */
badge?: string; badge?: string;
/** /**
* Accessibility text to add on the badge. Only used if showBadge is true and only for TYPE_NEW_PAGE. * Accessibility text to add on the badge. Only used if showBadge is true and only for CoreUserProfileHandlerType.LIST_ITEM.
*/ */
badgeA11yText?: string; badgeA11yText?: string;
/** /**
* If true, the badge number is being loaded. Only used if showBadge is true and only for TYPE_NEW_PAGE. * If true, the badge number is being loaded. Only used if showBadge is true and only for CoreUserProfileHandlerType.LIST_ITEM.
*/ */
loading?: boolean; loading?: boolean;
@ -195,14 +201,20 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
/** /**
* User profile handler type for communication. * User profile handler type for communication.
*
* @deprecated since 4.4. Use CoreUserProfileHandlerType.BUTTON instead.
*/ */
static readonly TYPE_COMMUNICATION = 'communication'; static readonly TYPE_COMMUNICATION = 'communication';
/** /**
* User profile handler type for new page. * User profile handler type for new page.
*
* @deprecated since 4.4. Use CoreUserProfileHandlerType.LIST_ITEM instead.
*/ */
static readonly TYPE_NEW_PAGE = 'newpage'; static readonly TYPE_NEW_PAGE = 'newpage';
/** /**
* User profile handler type for actions. * User profile handler type for actions.
*
* @deprecated since 4.4. Use CoreUserProfileHandlerType.BUTTON instead.
*/ */
static readonly TYPE_ACTION = 'action'; static readonly TYPE_ACTION = 'action';
@ -341,7 +353,7 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
name: name, name: name,
data: handler.getDisplayData(user, context, courseId), data: handler.getDisplayData(user, context, courseId),
priority: handler.priority || 0, priority: handler.priority || 0,
type: handler.type || CoreUserDelegateService.TYPE_NEW_PAGE, type: handler.type || CoreUserProfileHandlerType.LIST_ITEM,
}); });
} }
} catch { } catch {
@ -485,6 +497,24 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
return this.userHandlers[userId][contextKey]; return this.userHandlers[userId][contextKey];
} }
/**
* @inheritdoc
*/
registerHandler(handler: CoreUserProfileHandler): boolean {
const type = handler.type as string;
// eslint-disable-next-line deprecation/deprecation
if (type == CoreUserDelegateService.TYPE_COMMUNICATION || type == CoreUserDelegateService.TYPE_ACTION) {
handler.type = CoreUserProfileHandlerType.BUTTON;
// eslint-disable-next-line deprecation/deprecation
} else if (type == CoreUserDelegateService.TYPE_NEW_PAGE) {
handler.type = CoreUserProfileHandlerType.LIST_ITEM;
}
return super.registerHandler(handler);
}
} }
export const CoreUserDelegate = makeSingleton(CoreUserDelegateService); export const CoreUserDelegate = makeSingleton(CoreUserDelegateService);