forked from CIT/Vmeda.Online
		
	MOBILE-3807 user: Edit avatar only from details
This commit is contained in:
		
							parent
							
								
									434a2a90f2
								
							
						
					
					
						commit
						0bbfb898d1
					
				@ -18,7 +18,6 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@if ($core-user-hide-siteinfo) {
 | 
			
		||||
    .core-usermenu-siteinfo {
 | 
			
		||||
        display: none;
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [text]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <h1 *ngIf="title">{{ title }}</h1>
 | 
			
		||||
        <h1>{{ 'core.user.details' | translate }}</h1>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
@ -12,6 +12,25 @@
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
    <core-loading [hideUntil]="userLoaded">
 | 
			
		||||
        <ion-list *ngIf="user">
 | 
			
		||||
            <ion-item class="ion-text-center core-user-profile-maininfo">
 | 
			
		||||
                <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true">
 | 
			
		||||
                        <ion-button
 | 
			
		||||
                            class="edit-avatar"
 | 
			
		||||
                            *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-button>
 | 
			
		||||
                </core-user-avatar>
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h2>{{ user.fullname }}</h2>
 | 
			
		||||
                    <p *ngIf="user.address"><ion-icon name="fas-map-marker-alt" [attr.aria-hidden]="true"></ion-icon> {{ user.address }}</p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item-group *ngIf="hasContact">
 | 
			
		||||
                <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">
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
			
		||||
import { SafeUrl } from '@angular/platform-browser';
 | 
			
		||||
import { IonRefresher } from '@ionic/angular';
 | 
			
		||||
 | 
			
		||||
@ -20,10 +20,15 @@ import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreUser, CoreUserProfile, CoreUserProvider } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserHelper } from '@features/user/services/user-helper';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
 | 
			
		||||
import { CoreSite } from '@classes/site';
 | 
			
		||||
import { CoreFileUploaderHelper } from '@features/fileuploader/services/fileuploader-helper';
 | 
			
		||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
			
		||||
import { Translate } from '@singletons';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays info about a user.
 | 
			
		||||
@ -31,11 +36,9 @@ import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-core-user-about',
 | 
			
		||||
    templateUrl: 'about.html',
 | 
			
		||||
    styleUrls: ['about.scss'],
 | 
			
		||||
})
 | 
			
		||||
export class CoreUserAboutPage implements OnInit {
 | 
			
		||||
 | 
			
		||||
    protected userId!: number;
 | 
			
		||||
    protected siteId: string;
 | 
			
		||||
export class CoreUserAboutPage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    courseId!: number;
 | 
			
		||||
    userLoaded = false;
 | 
			
		||||
@ -45,20 +48,46 @@ export class CoreUserAboutPage implements OnInit {
 | 
			
		||||
    title?: string;
 | 
			
		||||
    formattedAddress?: string;
 | 
			
		||||
    encodedAddress?: SafeUrl;
 | 
			
		||||
    canChangeProfilePicture = false;
 | 
			
		||||
 | 
			
		||||
    protected userId!: number;
 | 
			
		||||
    protected site!: CoreSite;
 | 
			
		||||
    protected obsProfileRefreshed?: CoreEventObserver;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.siteId = CoreSites.getCurrentSiteId();
 | 
			
		||||
        try {
 | 
			
		||||
            this.site = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
            CoreNavigator.back();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.obsProfileRefreshed = CoreEvents.on(CoreUserProvider.PROFILE_REFRESHED, (data) => {
 | 
			
		||||
            if (!this.user || !data.user) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.user.email = data.user.email;
 | 
			
		||||
            this.user.address = CoreUserHelper.formatAddress('', data.user.city, data.user.country);
 | 
			
		||||
        }, CoreSites.getCurrentSiteId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * On init.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        this.userId = CoreNavigator.getRouteNumberParam('userId') || 0;
 | 
			
		||||
        this.courseId = CoreNavigator.getRouteNumberParam('courseId') || 0;
 | 
			
		||||
 | 
			
		||||
        // Allow to change the profile image only in the app profile page.
 | 
			
		||||
        this.canChangeProfilePicture =
 | 
			
		||||
            !this.courseId &&
 | 
			
		||||
            this.userId == this.site.getUserId() &&
 | 
			
		||||
            this.site.canUploadFiles() &&
 | 
			
		||||
            !CoreUser.isUpdatePictureDisabledInSite(this.site);
 | 
			
		||||
 | 
			
		||||
        this.fetchUser().finally(() => {
 | 
			
		||||
            this.userLoaded = true;
 | 
			
		||||
        });
 | 
			
		||||
@ -83,11 +112,85 @@ export class CoreUserAboutPage implements OnInit {
 | 
			
		||||
 | 
			
		||||
            this.user = user;
 | 
			
		||||
            this.title = user.fullname;
 | 
			
		||||
 | 
			
		||||
            this.user.address = CoreUserHelper.formatAddress('', user.city, user.country);
 | 
			
		||||
 | 
			
		||||
            await this.checkUserImageUpdated();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModalDefault(error, 'core.user.errorloaduser', true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if current user image has changed.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async checkUserImageUpdated(): Promise<void> {
 | 
			
		||||
        if (!this.site || !this.site.getInfo() || !this.user) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.userId != this.site.getUserId() || !this.isUserAvatarDirty()) {
 | 
			
		||||
            // Not current user or hasn't changed.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The current user image received is different than the one stored in site info. Assume the image was updated.
 | 
			
		||||
        // Update the site info to get the right avatar in there.
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreSites.updateSiteInfo(this.site.getId());
 | 
			
		||||
        } catch {
 | 
			
		||||
            // Cannot update site info. Assume the profile image is the right one.
 | 
			
		||||
            CoreEvents.trigger(CoreUserProvider.PROFILE_PICTURE_UPDATED, {
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                picture: this.user.profileimageurl,
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.isUserAvatarDirty()) {
 | 
			
		||||
            // The image is still different, this means that the good one is the one in site info.
 | 
			
		||||
            await this.refreshUser();
 | 
			
		||||
        } else {
 | 
			
		||||
            // Now they're the same, send event to use the right avatar in the rest of the app.
 | 
			
		||||
            CoreEvents.trigger(CoreUserProvider.PROFILE_PICTURE_UPDATED, {
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                picture: this.user.profileimageurl,
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens dialog to change profile picture.
 | 
			
		||||
     */
 | 
			
		||||
    async changeProfilePicture(): Promise<void> {
 | 
			
		||||
        const maxSize = -1;
 | 
			
		||||
        const title = Translate.instant('core.user.newpicture');
 | 
			
		||||
        const mimetypes = CoreMimetypeUtils.getGroupMimeInfo('image', 'mimetypes');
 | 
			
		||||
        let modal: CoreIonLoadingElement | undefined;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await CoreFileUploaderHelper.selectAndUploadFile(maxSize, title, mimetypes);
 | 
			
		||||
 | 
			
		||||
            modal = await CoreDomUtils.showModalLoading('core.sending', true);
 | 
			
		||||
 | 
			
		||||
            const profileImageURL = await CoreUser.changeProfilePicture(result.itemid, this.userId, this.site.getId());
 | 
			
		||||
 | 
			
		||||
            CoreEvents.trigger(CoreUserProvider.PROFILE_PICTURE_UPDATED, {
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                picture: profileImageURL,
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
 | 
			
		||||
            CoreSites.updateSiteInfo(this.site.getId());
 | 
			
		||||
 | 
			
		||||
            this.refreshUser();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        } finally {
 | 
			
		||||
            modal?.dismiss();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh the user data.
 | 
			
		||||
     *
 | 
			
		||||
@ -106,8 +209,52 @@ export class CoreUserAboutPage implements OnInit {
 | 
			
		||||
                courseId: this.courseId,
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                user: this.user,
 | 
			
		||||
            }, this.siteId);
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether the user avatar is not up to date with site info.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether the user avatar differs from site info cache.
 | 
			
		||||
     */
 | 
			
		||||
    protected isUserAvatarDirty(): boolean {
 | 
			
		||||
        if (!this.user || !this.site) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const courseAvatarUrl = this.normalizeAvatarUrl(this.user.profileimageurl);
 | 
			
		||||
        const siteAvatarUrl = this.normalizeAvatarUrl(this.site.getInfo()?.userpictureurl);
 | 
			
		||||
 | 
			
		||||
        return courseAvatarUrl !== siteAvatarUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Normalize an avatar url regardless of theme.
 | 
			
		||||
     *
 | 
			
		||||
     * Given that the default image is the only one that can be changed per theme, any other url will stay the same. Note that
 | 
			
		||||
     * the values returned by this function may not be valid urls, given that they are intended for string comparison.
 | 
			
		||||
     *
 | 
			
		||||
     * @param avatarUrl Avatar url.
 | 
			
		||||
     * @return Normalized avatar string (may not be a valid url).
 | 
			
		||||
     */
 | 
			
		||||
    protected normalizeAvatarUrl(avatarUrl?: string): string {
 | 
			
		||||
        if (!avatarUrl) {
 | 
			
		||||
            return 'undefined';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (avatarUrl.startsWith(`${this.site?.siteUrl}/theme/image.php`)) {
 | 
			
		||||
            return 'default';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return avatarUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.obsProfileRefreshed?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								src/core/features/user/pages/about/about.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/features/user/pages/about/about.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
: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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .contact-status {
 | 
			
		||||
                width: 24px !important;
 | 
			
		||||
                height: 24px !important;
 | 
			
		||||
                right: calc(50% - 12px -  var(--core-avatar-size) / 2) !important;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .edit-avatar {
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                right: calc(50% - 15px -  var(--core-avatar-size) / 2);
 | 
			
		||||
                bottom: -12px;
 | 
			
		||||
 | 
			
		||||
                :host-context([dir="rtl"]) & {
 | 
			
		||||
                    left: 0;
 | 
			
		||||
                    right: unset;
 | 
			
		||||
                }
 | 
			
		||||
                &::part(native) {
 | 
			
		||||
                    border-radius: 50%;
 | 
			
		||||
                    background: var(--ion-item-background);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:host-context([dir="rtl"]) ::ng-deep core-user-avatar .edit-avatar {
 | 
			
		||||
    left: -24px;
 | 
			
		||||
    right: unset;
 | 
			
		||||
}
 | 
			
		||||
@ -14,20 +14,10 @@
 | 
			
		||||
        <ion-list *ngIf="user && !isDeleted && isEnrolled">
 | 
			
		||||
            <ion-item class="ion-text-center core-user-profile-maininfo">
 | 
			
		||||
                <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true">
 | 
			
		||||
                    <ion-button
 | 
			
		||||
                        class="edit-avatar"
 | 
			
		||||
                        *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-button>
 | 
			
		||||
                </core-user-avatar>
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h2>{{ user.fullname }}</h2>
 | 
			
		||||
                    <p *ngIf="user.address">{{ user.address }}</p>
 | 
			
		||||
                    <p *ngIf="user.address"><ion-icon name="fas-map-marker-alt" [attr.aria-hidden]="true"></ion-icon> {{ user.address }}</p>
 | 
			
		||||
                    <p *ngIf="rolesFormatted" class="ion-text-wrap">
 | 
			
		||||
                        <strong>{{ 'core.user.roles' | translate}}</strong>{{'core.labelsep' | translate}}
 | 
			
		||||
                        {{ rolesFormatted }}
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,6 @@ import { Subscription } from 'rxjs';
 | 
			
		||||
import { CoreSite } from '@classes/site';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
			
		||||
import { Translate } from '@singletons';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUser,
 | 
			
		||||
@ -29,8 +27,6 @@ import {
 | 
			
		||||
} from '@features/user/services/user';
 | 
			
		||||
import { CoreUserHelper } from '@features/user/services/user-helper';
 | 
			
		||||
import { CoreUserDelegate, CoreUserDelegateService, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreFileUploaderHelper } from '@features/fileuploader/services/fileuploader-helper';
 | 
			
		||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreCourses } from '@features/courses/services/courses';
 | 
			
		||||
@ -54,7 +50,6 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
    title?: string;
 | 
			
		||||
    isDeleted = false;
 | 
			
		||||
    isEnrolled = true;
 | 
			
		||||
    canChangeProfilePicture = false;
 | 
			
		||||
    rolesFormatted?: string;
 | 
			
		||||
    actionHandlers: CoreUserProfileHandlerData[] = [];
 | 
			
		||||
    newPageHandlers: CoreUserProfileHandlerData[] = [];
 | 
			
		||||
@ -72,7 +67,7 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * On init.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
@ -91,13 +86,6 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
            this.courseId = undefined;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allow to change the profile image only in the app profile page.
 | 
			
		||||
        this.canChangeProfilePicture =
 | 
			
		||||
            !this.courseId &&
 | 
			
		||||
            this.userId == this.site.getUserId() &&
 | 
			
		||||
            this.site.canUploadFiles() &&
 | 
			
		||||
            !CoreUser.isUpdatePictureDisabledInSite(this.site);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await this.fetchUser();
 | 
			
		||||
 | 
			
		||||
@ -154,84 +142,12 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
                this.isLoadingHandlers = !CoreUserDelegate.areHandlersLoaded(user.id);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            await this.checkUserImageUpdated();
 | 
			
		||||
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // Error is null for deleted users, do not show the modal.
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if current user image has changed.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async checkUserImageUpdated(): Promise<void> {
 | 
			
		||||
        if (!this.site || !this.site.getInfo() || !this.user) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.userId != this.site.getUserId() || !this.isUserAvatarDirty()) {
 | 
			
		||||
            // Not current user or hasn't changed.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // The current user image received is different than the one stored in site info. Assume the image was updated.
 | 
			
		||||
        // Update the site info to get the right avatar in there.
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreSites.updateSiteInfo(this.site.getId());
 | 
			
		||||
        } catch {
 | 
			
		||||
            // Cannot update site info. Assume the profile image is the right one.
 | 
			
		||||
            CoreEvents.trigger(CoreUserProvider.PROFILE_PICTURE_UPDATED, {
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                picture: this.user.profileimageurl,
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.isUserAvatarDirty()) {
 | 
			
		||||
            // The image is still different, this means that the good one is the one in site info.
 | 
			
		||||
            await this.refreshUser();
 | 
			
		||||
        } else {
 | 
			
		||||
            // Now they're the same, send event to use the right avatar in the rest of the app.
 | 
			
		||||
            CoreEvents.trigger(CoreUserProvider.PROFILE_PICTURE_UPDATED, {
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                picture: this.user.profileimageurl,
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens dialog to change profile picture.
 | 
			
		||||
     */
 | 
			
		||||
    async changeProfilePicture(): Promise<void> {
 | 
			
		||||
        const maxSize = -1;
 | 
			
		||||
        const title = Translate.instant('core.user.newpicture');
 | 
			
		||||
        const mimetypes = CoreMimetypeUtils.getGroupMimeInfo('image', 'mimetypes');
 | 
			
		||||
        let modal: CoreIonLoadingElement | undefined;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await CoreFileUploaderHelper.selectAndUploadFile(maxSize, title, mimetypes);
 | 
			
		||||
 | 
			
		||||
            modal = await CoreDomUtils.showModalLoading('core.sending', true);
 | 
			
		||||
 | 
			
		||||
            const profileImageURL = await CoreUser.changeProfilePicture(result.itemid, this.userId, this.site.getId());
 | 
			
		||||
 | 
			
		||||
            CoreEvents.trigger(CoreUserProvider.PROFILE_PICTURE_UPDATED, {
 | 
			
		||||
                userId: this.userId,
 | 
			
		||||
                picture: profileImageURL,
 | 
			
		||||
            }, this.site.getId());
 | 
			
		||||
 | 
			
		||||
            CoreSites.updateSiteInfo(this.site.getId());
 | 
			
		||||
 | 
			
		||||
            this.refreshUser();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        } finally {
 | 
			
		||||
            modal?.dismiss();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh the user.
 | 
			
		||||
     *
 | 
			
		||||
@ -285,48 +201,11 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Page destroyed.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.subscription?.unsubscribe();
 | 
			
		||||
        this.obsProfileRefreshed.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether the user avatar is not up to date with site info.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether the user avatar differs from site info cache.
 | 
			
		||||
     */
 | 
			
		||||
    private isUserAvatarDirty(): boolean {
 | 
			
		||||
        if (!this.user || !this.site) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const courseAvatarUrl = this.normalizeAvatarUrl(this.user.profileimageurl);
 | 
			
		||||
        const siteAvatarUrl = this.normalizeAvatarUrl(this.site.getInfo()?.userpictureurl);
 | 
			
		||||
 | 
			
		||||
        return courseAvatarUrl !== siteAvatarUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Normalize an avatar url regardless of theme.
 | 
			
		||||
     *
 | 
			
		||||
     * Given that the default image is the only one that can be changed per theme, any other url will stay the same. Note that
 | 
			
		||||
     * the values returned by this function may not be valid urls, given that they are intended for string comparison.
 | 
			
		||||
     *
 | 
			
		||||
     * @param avatarUrl Avatar url.
 | 
			
		||||
     * @return Normalized avatar string (may not be a valid url).
 | 
			
		||||
     */
 | 
			
		||||
    private normalizeAvatarUrl(avatarUrl?: string): string {
 | 
			
		||||
        if (!avatarUrl) {
 | 
			
		||||
            return 'undefined';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (avatarUrl.startsWith(`${this.site?.siteUrl}/theme/image.php`)) {
 | 
			
		||||
            return 'default';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return avatarUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,21 +18,6 @@
 | 
			
		||||
                height: 24px !important;
 | 
			
		||||
                right: calc(50% - 12px -  var(--core-avatar-size) / 2) !important;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .edit-avatar {
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                right: calc(50% - 15px -  var(--core-avatar-size) / 2);
 | 
			
		||||
                bottom: -12px;
 | 
			
		||||
 | 
			
		||||
                :host-context([dir="rtl"]) & {
 | 
			
		||||
                    left: 0;
 | 
			
		||||
                    right: unset;
 | 
			
		||||
                }
 | 
			
		||||
                &::part(native) {
 | 
			
		||||
                    border-radius: 50%;
 | 
			
		||||
                    background: var(--ion-item-background);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user