MOBILE-3807 usermenu: Change UI and texts

main
Pau Ferrer Ocaña 2021-10-29 12:36:42 +02:00
parent b9bf018966
commit d3ffc45be3
10 changed files with 71 additions and 88 deletions

View File

@ -2255,6 +2255,7 @@
"core.user.participants": "moodle", "core.user.participants": "moodle",
"core.user.phone1": "moodle", "core.user.phone1": "moodle",
"core.user.phone2": "moodle", "core.user.phone2": "moodle",
"core.user.profile": "moodle",
"core.user.roles": "moodle", "core.user.roles": "moodle",
"core.user.sendemail": "local_moodlemobileapp", "core.user.sendemail": "local_moodlemobileapp",
"core.user.student": "moodle/defaultcoursestudent", "core.user.student": "moodle/defaultcoursestudent",

View File

@ -26,7 +26,8 @@
<core-format-text [text]="accountsList.currentSite.siteName" clean="true" <core-format-text [text]="accountsList.currentSite.siteName" clean="true"
[siteId]="accountsList.currentSite.id"></core-format-text> [siteId]="accountsList.currentSite.id"></core-format-text>
</h2> </h2>
<p><a [href]="accountsList.currentSite.siteUrl" core-link autoLogin="yes">{{ accountsList.currentSite.siteUrl }}</a> <p><a [href]="accountsList.currentSite.siteUrl" core-link autoLogin="yes">{{
accountsList.currentSite.siteUrlWithoutProtocol }}</a>
</p> </p>
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>
@ -52,7 +53,7 @@
<h2> <h2>
<core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text> <core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text>
</h2> </h2>
<p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrl }}</a></p> <p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p>
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>

View File

@ -26,7 +26,7 @@
<h2> <h2>
<core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text> <core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text>
</h2> </h2>
<p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrl }}</a></p> <p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p>
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>

View File

@ -1357,25 +1357,23 @@ export class CoreLoginHelperProvider {
const index = sites.findIndex((site) => site.id == currentSiteId); const index = sites.findIndex((site) => site.id == currentSiteId);
accountsList.currentSite = sites.splice(index, 1)[0]; accountsList.currentSite = sites.splice(index, 1)[0];
siteUrl = accountsList.currentSite.siteUrl.replace(/^https?:\/\//, '').toLowerCase(); siteUrl = accountsList.currentSite.siteUrlWithoutProtocol;
accountsList.currentSite.siteUrl = siteUrl;
} }
const otherSites: Record<string, CoreSiteBasicInfo[]> = {}; const otherSites: Record<string, CoreSiteBasicInfo[]> = {};
// Add site counter and classify sites. // Add site counter and classify sites.
await Promise.all(sites.map(async (site) => { await Promise.all(sites.map(async (site) => {
site.siteUrl = site.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
site.badge = await CoreUtils.ignoreErrors(CorePushNotifications.getSiteCounter(site.id)) || 0; site.badge = await CoreUtils.ignoreErrors(CorePushNotifications.getSiteCounter(site.id)) || 0;
if (site.siteUrl == siteUrl) { if (site.siteUrlWithoutProtocol == siteUrl) {
accountsList.sameSite.push(site); accountsList.sameSite.push(site);
} else { } else {
if (!otherSites[site.siteUrl]) { if (!otherSites[site.siteUrlWithoutProtocol]) {
otherSites[site.siteUrl] = []; otherSites[site.siteUrlWithoutProtocol] = [];
} }
otherSites[site.siteUrl].push(site); otherSites[site.siteUrlWithoutProtocol].push(site);
} }
return; return;
@ -1396,11 +1394,11 @@ export class CoreLoginHelperProvider {
async deleteAccountFromList(accountsList: CoreAccountsList, site: CoreSiteBasicInfo): Promise<void> { async deleteAccountFromList(accountsList: CoreAccountsList, site: CoreSiteBasicInfo): Promise<void> {
await CoreSites.deleteSite(site.id); await CoreSites.deleteSite(site.id);
const siteUrl = site.siteUrl; const siteUrl = site.siteUrlWithoutProtocol;
let index = 0; let index = 0;
// Found on same site. // Found on same site.
if (accountsList.sameSite.length > 0 && accountsList.sameSite[0].siteUrl == siteUrl) { if (accountsList.sameSite.length > 0 && accountsList.sameSite[0].siteUrlWithoutProtocol == siteUrl) {
index = accountsList.sameSite.findIndex((listedSite) => listedSite.id == site.id); index = accountsList.sameSite.findIndex((listedSite) => listedSite.id == site.id);
if (index >= 0) { if (index >= 0) {
accountsList.sameSite.splice(index, 1); accountsList.sameSite.splice(index, 1);
@ -1410,7 +1408,8 @@ export class CoreLoginHelperProvider {
return; return;
} }
const otherSiteIndex = accountsList.otherSites.findIndex((sites) => sites.length > 0 && sites[0].siteUrl == siteUrl); const otherSiteIndex = accountsList.otherSites.findIndex((sites) =>
sites.length > 0 && sites[0].siteUrlWithoutProtocol == siteUrl);
if (otherSiteIndex < 0) { if (otherSiteIndex < 0) {
// Site Url not found. // Site Url not found.
return; return;

View File

@ -8,32 +8,19 @@
<h1> <h1>
{{'core.user.account' | translate}} {{'core.user.account' | translate}}
</h1> </h1>
<ion-buttons slot="end" *ngIf="loaded">
<ion-button fill="clear" *ngIf="moreSites" (click)="switchAccounts($event)"
[attr.aria-label]="'core.mainmenu.changeaccount' | translate">
<ion-icon name="fas-exchange-alt" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button>
<ion-button fill="clear" *ngIf="!moreSites" (click)="addAccount($event)"
[attr.aria-label]="'core.login.add' | translate">
<ion-icon name="fas-user-plus" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
<ion-list> <ion-list>
<ion-item class="ion-text-center core-user-profile-maininfo" *ngIf="siteInfo" lines="none"> <ion-item button class="core-user-profile-maininfo" *ngIf="siteInfo" lines="full" (click)="switchAccounts($event)" detail="true"
<core-user-avatar [user]="siteInfo" [userId]="siteInfo.userid" [linkProfile]="false"></core-user-avatar> [attr.aria-label]="'core.mainmenu.switchaccount' | translate">
<core-user-avatar [user]="siteInfo" [userId]="siteInfo.userid" [linkProfile]="false" slot="start"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ siteInfo.fullname }}</h2> <h2>{{ siteInfo.fullname }}</h2>
<p class="core-usermenu-siteinfo core-usermenu-sitename"> <p class="core-usermenu-siteinfo core-usermenu-sitename">
<core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [wsNotFiltered]="true">
[wsNotFiltered]="true">
</core-format-text> </core-format-text>
</p> </p>
<p class="core-usermenu-siteinfo core-usermenu-siteurl">
<a [href]="siteUrl" core-link autoLogin="yes">{{ siteUrl }}</a>
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -41,7 +28,7 @@
[attr.aria-label]="'core.user.details' | translate" detail="true" lines="none"> [attr.aria-label]="'core.user.details' | translate" detail="true" lines="none">
<ion-icon name="fas-user" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-user" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p class="item-heading">{{ 'core.user.details' | translate }}</p> <p class="item-heading">{{ 'core.user.profile' | translate }}</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -51,17 +38,17 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item button *ngFor="let handler of handlers" class="ion-text-wrap" <ion-item button *ngFor="let handler of handlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)"
(click)="handlerClicked($event, handler)" [ngClass]="['core-user-menu-handler', handler.class || '']" [ngClass]="['core-user-menu-handler', handler.class || '']" [hidden]="handler.hidden"
[hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" detail="true" lines="none"> [attr.aria-label]="handler.title | translate" detail="true" lines="none">
<ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p class="item-heading">{{ handler.title | translate }}</p> <p class="item-heading">{{ handler.title | translate }}</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item button (click)="openPreferences($event)" [attr.aria-label]="'core.settings.preferences' | translate" <ion-item button (click)="openPreferences($event)" [attr.aria-label]="'core.settings.preferences' | translate" detail="true"
detail="true" class="core-user-menu-preferences"> class="core-user-menu-preferences">
<ion-icon name="fas-wrench" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-wrench" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p class="item-heading">{{ 'core.settings.preferences' | translate }}</p> <p class="item-heading">{{ 'core.settings.preferences' | translate }}</p>
@ -70,8 +57,8 @@
</ion-list> </ion-list>
</ion-content> </ion-content>
<ion-footer class="ion-padding"> <ion-footer class="ion-padding">
<ion-button (click)="logout($event)" expand="block" color="danger" <ion-button (click)="logout($event)" expand="block" color="danger" [attr.aria-label]="'core.mainmenu.logout' | translate"
[attr.aria-label]="'core.mainmenu.logout' | translate" class="ion-text-wrap"> class="ion-text-wrap">
<ion-icon name="fas-sign-out-alt" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-sign-out-alt" slot="start" aria-hidden="true"></ion-icon>
{{ 'core.mainmenu.logout' | translate }} {{ 'core.mainmenu.logout' | translate }}
</ion-button> </ion-button>

View File

@ -1,22 +1,6 @@
@import "~theme/globals"; @import "~theme/globals";
:host { :host {
.core-user-profile-maininfo::part(native) {
flex-direction: column;
}
::ng-deep {
core-user-avatar {
display: block;
--core-avatar-size: var(--core-large-avatar-size);
height: calc(var(--core-avatar-size) + 16px);
img {
margin: 8px auto;
}
}
}
.core-user-menu-preferences { .core-user-menu-preferences {
--inner-border-width: 0; --inner-border-width: 0;
--border-width: 1px 0 0 0; --border-width: 1px 0 0 0;

View File

@ -25,7 +25,7 @@
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text> <core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
</p> </p>
<p class="ion-text-wrap">{{ site.fullName }}</p> <p class="ion-text-wrap">{{ site.fullName }}</p>
<p>{{ site.siteUrl }}</p> <p>{{ site.siteUrlWithoutProtocol }}</p>
</ion-label> </ion-label>
<p *ngIf="site.spaceUsage !== undefined" slot="end"> <p *ngIf="site.spaceUsage !== undefined" slot="end">
{{ site.spaceUsage | coreBytesToSize }} {{ site.spaceUsage | coreBytesToSize }}

View File

@ -37,7 +37,7 @@
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text> <core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
</p> </p>
<p>{{ site.fullName }}</p> <p>{{ site.fullName }}</p>
<p>{{ site.siteUrl }}</p> <p>{{ site.siteUrlWithoutProtocol }}</p>
</ion-label> </ion-label>
<core-button-with-spinner [loading]="isSynchronizing(site.id)" slot="end"> <core-button-with-spinner [loading]="isSynchronizing(site.id)" slot="end">
<ion-button fill="clear" (click)="synchronize(site.id)" [title]="site.siteName" <ion-button fill="clear" (click)="synchronize(site.id)" [title]="site.siteName"

View File

@ -3,7 +3,7 @@
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [text]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<h1>{{ 'core.user.details' | translate }}</h1> <h1>{{ 'core.user.profile' | translate }}</h1>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
@ -14,30 +14,29 @@
<ion-list *ngIf="user"> <ion-list *ngIf="user">
<ion-item class="ion-text-center core-user-profile-maininfo" lines="full"> <ion-item class="ion-text-center core-user-profile-maininfo" lines="full">
<core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true"> <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true">
<ion-button <ion-button class="edit-avatar" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()"
class="edit-avatar" [attr.aria-label]="'core.user.newpicture' | translate" fill="clear" color="dark">
*ngIf="canChangeProfilePicture"
(click)="changeProfilePicture()"
[attr.aria-label]="'core.user.newpicture' | translate"
fill="clear"
color="dark"
>
<ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</core-user-avatar> </core-user-avatar>
<ion-label> <ion-label>
<h2>{{ user.fullname }}</h2> <h2>{{ user.fullname }}</h2>
<p *ngIf="user.address"><ion-icon name="fas-map-marker-alt" [attr.aria-hidden]="true"></ion-icon> {{ user.address }}</p> <p *ngIf="user.address">
<ion-icon name="fas-map-marker-alt" [attr.aria-hidden]="true"></ion-icon> {{ user.address }}
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item-group *ngIf="hasContact"> <ion-item-group *ngIf="hasContact">
<ion-item-divider><ion-label><h2>{{ 'core.user.contact' | translate}}</h2></ion-label></ion-item-divider> <ion-item-divider>
<ion-label>
<h2>{{ 'core.user.contact' | translate}}</h2>
</ion-label>
</ion-item-divider>
<ion-item class="ion-text-wrap" *ngIf="user.email"> <ion-item class="ion-text-wrap" *ngIf="user.email">
<ion-label> <ion-label>
<h2>{{ 'core.user.email' | translate }}</h2> <h2>{{ 'core.user.email' | translate }}</h2>
<p><a class="core-anchor" href="mailto:{{user.email}}" core-link auto-login="no" <p><a class="core-anchor" href="mailto:{{user.email}}" core-link auto-login="no" [showBrowserWarning]="false">
[showBrowserWarning]="false">
{{ user.email }} {{ user.email }}
</a></p> </a></p>
</ion-label> </ion-label>
@ -80,7 +79,11 @@
</ion-item> </ion-item>
</ion-item-group> </ion-item-group>
<ion-item-group *ngIf="hasDetails"> <ion-item-group *ngIf="hasDetails">
<ion-item-divider><ion-label><h2>{{ 'core.userdetails' | translate}}</h2></ion-label></ion-item-divider> <ion-item-divider>
<ion-label>
<h2>{{ 'core.userdetails' | translate}}</h2>
</ion-label>
</ion-item-divider>
<ion-item class="ion-text-wrap" *ngIf="user.url"> <ion-item class="ion-text-wrap" *ngIf="user.url">
<ion-label> <ion-label>
<h2>{{ 'core.user.webpage' | translate}}</h2> <h2>{{ 'core.user.webpage' | translate}}</h2>
@ -100,11 +103,17 @@
</core-user-profile-field> </core-user-profile-field>
</ion-item-group> </ion-item-group>
<ion-item-group *ngIf="user.description"> <ion-item-group *ngIf="user.description">
<ion-item-divider><ion-label><h2>{{ 'core.user.description' | translate}}</h2></ion-label></ion-item-divider> <ion-item-divider>
<ion-label>
<h2>{{ 'core.user.description' | translate}}</h2>
</ion-label>
</ion-item-divider>
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<p><core-format-text [text]="user.description" contextLevel="user" [contextInstanceId]="user.id"> <p>
</core-format-text></p> <core-format-text [text]="user.description" contextLevel="user" [contextInstanceId]="user.id">
</core-format-text>
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
</ion-item-group> </ion-item-group>

View File

@ -1052,8 +1052,10 @@ export class CoreSitesProvider {
* @param siteId The site ID. If not defined, current site (if available). * @param siteId The site ID. If not defined, current site (if available).
* @return Promise resolved with site home ID. * @return Promise resolved with site home ID.
*/ */
getSiteHomeId(siteId?: string): Promise<number> { async getSiteHomeId(siteId?: string): Promise<number> {
return this.getSite(siteId).then((site) => site.getSiteHomeId()); const site = await this.getSite(siteId);
return site.getSiteHomeId();
} }
/** /**
@ -1074,6 +1076,7 @@ export class CoreSitesProvider {
const basicInfo: CoreSiteBasicInfo = { const basicInfo: CoreSiteBasicInfo = {
id: site.id, id: site.id,
siteUrl: site.siteUrl, siteUrl: site.siteUrl,
siteUrlWithoutProtocol: site.siteUrl.replace(/^https?:\/\//, '').toLowerCase(),
fullName: siteInfo?.fullname, fullName: siteInfo?.fullname,
siteName: CoreConstants.CONFIG.sitename == '' ? siteInfo?.sitename: CoreConstants.CONFIG.sitename, siteName: CoreConstants.CONFIG.sitename == '' ? siteInfo?.sitename: CoreConstants.CONFIG.sitename,
avatar: siteInfo?.userpictureurl, avatar: siteInfo?.userpictureurl,
@ -1098,9 +1101,7 @@ export class CoreSitesProvider {
// Sort sites by url and fullname. // Sort sites by url and fullname.
sites.sort((a, b) => { sites.sort((a, b) => {
// First compare by site url without the protocol. // First compare by site url without the protocol.
const urlA = a.siteUrl.replace(/^https?:\/\//, '').toLowerCase(); const compare = a.siteUrlWithoutProtocol.localeCompare(b.siteUrlWithoutProtocol);
const urlB = b.siteUrl.replace(/^https?:\/\//, '').toLowerCase();
const compare = urlA.localeCompare(urlB);
if (compare !== 0) { if (compare !== 0) {
return compare; return compare;
@ -1756,6 +1757,7 @@ export type CoreSiteUserTokenResponse = {
export type CoreSiteBasicInfo = { export type CoreSiteBasicInfo = {
id: string; // Site ID. id: string; // Site ID.
siteUrl: string; // Site URL. siteUrl: string; // Site URL.
siteUrlWithoutProtocol: string; // Site URL without protocol.
fullName?: string; // User's full name. fullName?: string; // User's full name.
siteName?: string; // Site's name. siteName?: string; // Site's name.
avatar?: string; // User's avatar. avatar?: string; // User's avatar.