diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 9f92358a0..7875b74ad 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts @@ -2,7 +2,7 @@ import { SortMeta } from 'primeng/api' import { Component, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute, Params, Router } from '@angular/router' import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService, UserService } from '@app/core' -import { Actor, DropdownAction } from '@app/shared/shared-main' +import { Account, DropdownAction } from '@app/shared/shared-main' import { UserBanModalComponent } from '@app/shared/shared-moderation' import { ServerConfig, User, UserRole } from '@shared/models' @@ -164,7 +164,7 @@ export class UserListComponent extends RestTable implements OnInit { } switchToDefaultAvatar ($event: Event) { - ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() + ($event.target as HTMLImageElement).src = Account.GET_DEFAULT_AVATAR_URL() } async unbanUsers (users: User[]) { diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.ts b/client/src/app/+my-library/my-ownership/my-ownership.component.ts index e1aca65f6..78c3d9192 100644 --- a/client/src/app/+my-library/my-ownership/my-ownership.component.ts +++ b/client/src/app/+my-library/my-ownership/my-ownership.component.ts @@ -1,7 +1,7 @@ import { SortMeta } from 'primeng/api' import { Component, OnInit, ViewChild } from '@angular/core' import { Notifier, RestPagination, RestTable } from '@app/core' -import { Account, Actor, VideoOwnershipService } from '@app/shared/shared-main' +import { Account, VideoOwnershipService } from '@app/shared/shared-main' import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '@shared/models' import { MyAcceptOwnershipComponent } from './my-accept-ownership/my-accept-ownership.component' @@ -44,7 +44,7 @@ export class MyOwnershipComponent extends RestTable implements OnInit { } switchToDefaultAvatar ($event: Event) { - ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() + ($event.target as HTMLImageElement).src = Account.GET_DEFAULT_AVATAR_URL() } openAcceptModal (videoChangeOwnership: VideoChangeOwnership) { diff --git a/client/src/app/+videos/+video-watch/comment/video-comment-add.component.ts b/client/src/app/+videos/+video-watch/comment/video-comment-add.component.ts index 4bde5c53d..f1f0dfeba 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment-add.component.ts +++ b/client/src/app/+videos/+video-watch/comment/video-comment-add.component.ts @@ -4,7 +4,7 @@ import { Router } from '@angular/router' import { Notifier, User } from '@app/core' import { VIDEO_COMMENT_TEXT_VALIDATOR } from '@app/shared/form-validators/video-comment-validators' import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' -import { Video } from '@app/shared/shared-main' +import { Video, Account } from '@app/shared/shared-main' import { VideoComment, VideoCommentService } from '@app/shared/shared-video-comment' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { VideoCommentCreate } from '@shared/models' @@ -145,7 +145,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnChanges, getAvatarUrl () { if (this.user) return this.user.accountAvatarUrl - return window.location.origin + '/client/assets/images/default-avatar.png' + return Account.GET_DEFAULT_AVATAR_URL() } gotoLogin () { diff --git a/client/src/app/+videos/+video-watch/comment/video-comment.component.ts b/client/src/app/+videos/+video-watch/comment/video-comment.component.ts index 3b3a5cc81..0958b25c0 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment.component.ts +++ b/client/src/app/+videos/+video-watch/comment/video-comment.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core' import { MarkdownService, Notifier, UserService } from '@app/core' import { AuthService } from '@app/core/auth' -import { Account, Actor, DropdownAction, Video } from '@app/shared/shared-main' +import { Account, DropdownAction, Video } from '@app/shared/shared-main' import { CommentReportComponent } from '@app/shared/shared-moderation/report-modals/comment-report.component' import { VideoComment, VideoCommentThreadTree } from '@app/shared/shared-video-comment' import { User, UserRight } from '@shared/models' @@ -130,7 +130,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { } switchToDefaultAvatar ($event: Event) { - ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() + ($event.target as HTMLImageElement).src = Account.GET_DEFAULT_AVATAR_URL() } isNotDeletedOrDeletedWithReplies () { diff --git a/client/src/app/shared/shared-abuse-list/abuse-details.component.ts b/client/src/app/shared/shared-abuse-list/abuse-details.component.ts index 282a6fe19..31cf3389d 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-details.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-details.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core' import { durationToString } from '@app/helpers' -import { Actor } from '@app/shared/shared-main' +import { Account } from '@app/shared/shared-main' import { AbusePredefinedReasonsString } from '@shared/models' import { ProcessedAbuse } from './processed-abuse.model' @@ -47,6 +47,6 @@ export class AbuseDetailsComponent { } switchToDefaultAvatar ($event: Event) { - ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() + ($event.target as HTMLImageElement).src = Account.GET_DEFAULT_AVATAR_URL() } } diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts index 807665b9c..904f62b57 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts @@ -122,7 +122,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV } switchToDefaultAvatar ($event: Event) { - ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() + ($event.target as HTMLImageElement).src = Account.GET_DEFAULT_AVATAR_URL() } async removeAbuse (abuse: AdminAbuse) { diff --git a/client/src/app/shared/shared-forms/select/select-channel.component.ts b/client/src/app/shared/shared-forms/select/select-channel.component.ts index 1b0db9b6f..1d91d59bc 100644 --- a/client/src/app/shared/shared-forms/select/select-channel.component.ts +++ b/client/src/app/shared/shared-forms/select/select-channel.component.ts @@ -1,6 +1,6 @@ import { Component, forwardRef, Input } from '@angular/core' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' -import { Actor } from '@app/shared/shared-main/account/actor.model' +import { VideoChannel } from '@app/shared/shared-main' export type SelectChannelItem = { id: number @@ -34,7 +34,7 @@ export class SelectChannelComponent implements ControlValueAccessor { get channels () { return this.items.map(c => Object.assign(c, { - avatarPath: c.avatarPath ? c.avatarPath : Actor.GET_DEFAULT_AVATAR_URL() + avatarPath: c.avatarPath ? c.avatarPath : VideoChannel.GET_DEFAULT_AVATAR_URL() })) } diff --git a/client/src/app/shared/shared-main/account/account.model.ts b/client/src/app/shared/shared-main/account/account.model.ts index 6df2e9d10..b3dc6cfe5 100644 --- a/client/src/app/shared/shared-main/account/account.model.ts +++ b/client/src/app/shared/shared-main/account/account.model.ts @@ -1,4 +1,4 @@ -import { Account as ServerAccount } from '@shared/models/actors/account.model' +import { Account as ServerAccount, Avatar } from '@shared/models' import { Actor } from './actor.model' export class Account extends Actor implements ServerAccount { @@ -13,9 +13,19 @@ export class Account extends Actor implements ServerAccount { userId?: number + static GET_ACTOR_AVATAR_URL (actor: object) { + return Actor.GET_ACTOR_AVATAR_URL(actor) || this.GET_DEFAULT_AVATAR_URL() + } + + static GET_DEFAULT_AVATAR_URL () { + return `${window.location.origin}/client/assets/images/default-avatar-account.png` + } + constructor (hash: ServerAccount) { super(hash) + this.updateComputedAttributes() + this.displayName = hash.displayName this.description = hash.description this.userId = hash.userId @@ -27,4 +37,14 @@ export class Account extends Actor implements ServerAccount { this.mutedServerByUser = false this.mutedServerByInstance = false } + + updateAvatar (newAvatar: Avatar) { + this.avatar = newAvatar + + this.updateComputedAttributes() + } + + private updateComputedAttributes () { + this.avatarUrl = Account.GET_ACTOR_AVATAR_URL(this) + } } diff --git a/client/src/app/shared/shared-main/account/actor.model.ts b/client/src/app/shared/shared-main/account/actor.model.ts index 950e256ff..8222c9769 100644 --- a/client/src/app/shared/shared-main/account/actor.model.ts +++ b/client/src/app/shared/shared-main/account/actor.model.ts @@ -24,12 +24,6 @@ export abstract class Actor implements ActorServer { return absoluteAPIUrl + actor.avatar.path } - - return this.GET_DEFAULT_AVATAR_URL() - } - - static GET_DEFAULT_AVATAR_URL () { - return window.location.origin + '/client/assets/images/default-avatar.png' } static CREATE_BY_STRING (accountName: string, host: string, forceHostname = false) { @@ -61,17 +55,5 @@ export abstract class Actor implements ActorServer { this.avatar = hash.avatar this.isLocal = Actor.IS_LOCAL(this.host) - - this.updateComputedAttributes() - } - - updateAvatar (newAvatar: Avatar) { - this.avatar = newAvatar - - this.updateComputedAttributes() - } - - private updateComputedAttributes () { - this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this) } } diff --git a/client/src/app/shared/shared-main/users/user-notification.model.ts b/client/src/app/shared/shared-main/users/user-notification.model.ts index 648bb7fe0..b1df4a584 100644 --- a/client/src/app/shared/shared-main/users/user-notification.model.ts +++ b/client/src/app/shared/shared-main/users/user-notification.model.ts @@ -7,7 +7,7 @@ import { VideoInfo, UserRight } from '@shared/models' -import { Actor } from '../account/actor.model' +import { Account, Actor, VideoChannel } from '@app/shared/shared-main' import { AuthUser } from '@app/core' export class UserNotification implements UserNotificationServer { @@ -95,22 +95,22 @@ export class UserNotification implements UserNotificationServer { // To prevent a notification popup crash in case of bug, wrap it inside a try/catch try { this.video = hash.video - if (this.video) this.setAvatarUrl(this.video.channel) + if (this.video) this.setVideoChannelAvatarUrl(this.video.channel) this.videoImport = hash.videoImport this.comment = hash.comment - if (this.comment) this.setAvatarUrl(this.comment.account) + if (this.comment) this.setAccountAvatarUrl(this.comment.account) this.abuse = hash.abuse this.videoBlacklist = hash.videoBlacklist this.account = hash.account - if (this.account) this.setAvatarUrl(this.account) + if (this.account) this.setAccountAvatarUrl(this.account) this.actorFollow = hash.actorFollow - if (this.actorFollow) this.setAvatarUrl(this.actorFollow.follower) + if (this.actorFollow) this.setAccountAvatarUrl(this.actorFollow.follower) this.createdAt = hash.createdAt this.updatedAt = hash.updatedAt @@ -222,7 +222,11 @@ export class UserNotification implements UserNotificationServer { return [ this.buildVideoUrl(comment.video), { threadId: comment.threadId } ] } - private setAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { - actor.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(actor) + private setAccountAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { + actor.avatarUrl = Account.GET_ACTOR_AVATAR_URL(actor) + } + + private setVideoChannelAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { + actor.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(actor) } } diff --git a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts index 123389afb..4f1f5b65d 100644 --- a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts +++ b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts @@ -1,4 +1,4 @@ -import { VideoChannel as ServerVideoChannel, ViewsPerDate, Account } from '@shared/models' +import { VideoChannel as ServerVideoChannel, ViewsPerDate, Account, Avatar } from '@shared/models' import { Actor } from '../account/actor.model' export class VideoChannel extends Actor implements ServerVideoChannel { @@ -17,9 +17,19 @@ export class VideoChannel extends Actor implements ServerVideoChannel { viewsPerDay?: ViewsPerDate[] + static GET_ACTOR_AVATAR_URL (actor: object) { + return Actor.GET_ACTOR_AVATAR_URL(actor) || this.GET_DEFAULT_AVATAR_URL() + } + + static GET_DEFAULT_AVATAR_URL () { + return `${window.location.origin}/client/assets/images/default-avatar-videochannel.png` + } + constructor (hash: ServerVideoChannel) { super(hash) + this.updateComputedAttributes() + this.displayName = hash.displayName this.description = hash.description this.support = hash.support @@ -39,4 +49,14 @@ export class VideoChannel extends Actor implements ServerVideoChannel { this.ownerAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.ownerAccount) } } + + updateAvatar (newAvatar: Avatar) { + this.avatar = newAvatar + + this.updateComputedAttributes() + } + + private updateComputedAttributes () { + this.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this) + } } diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts index 92f5bc0c0..8e0e68020 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts @@ -12,7 +12,7 @@ import { VideoScheduleUpdate, VideoState } from '@shared/models' -import { Actor } from '../account/actor.model' +import { Account, Actor, VideoChannel } from '@app/shared/shared-main' export class Video implements VideoServerModel { byVideoChannel: string @@ -142,8 +142,8 @@ export class Video implements VideoServerModel { this.byAccount = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host) this.byVideoChannel = Actor.CREATE_BY_STRING(hash.channel.name, hash.channel.host) - this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) - this.videoChannelAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.channel) + this.accountAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.account) + this.videoChannelAvatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this.channel) this.category.label = peertubeTranslate(this.category.label, translations) this.licence.label = peertubeTranslate(this.licence.label, translations) diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.ts b/client/src/app/shared/shared-moderation/account-blocklist.component.ts index 68928a2c2..3de9587b8 100644 --- a/client/src/app/shared/shared-moderation/account-blocklist.component.ts +++ b/client/src/app/shared/shared-moderation/account-blocklist.component.ts @@ -1,7 +1,7 @@ import { SortMeta } from 'primeng/api' import { Directive, OnInit } from '@angular/core' import { Notifier, RestPagination, RestTable } from '@app/core' -import { Actor } from '@app/shared/shared-main' +import { Account } from '@app/shared/shared-main' import { AccountBlock } from './account-block.model' import { BlocklistComponentType, BlocklistService } from './blocklist.service' @@ -31,7 +31,7 @@ export class GenericAccountBlocklistComponent extends RestTable implements OnIni } switchToDefaultAvatar ($event: Event) { - ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() + ($event.target as HTMLImageElement).src = Account.GET_DEFAULT_AVATAR_URL() } unblockAccount (accountBlock: AccountBlock) { diff --git a/client/src/app/shared/shared-video-comment/video-comment.model.ts b/client/src/app/shared/shared-video-comment/video-comment.model.ts index eeee397af..bf718ae08 100644 --- a/client/src/app/shared/shared-video-comment/video-comment.model.ts +++ b/client/src/app/shared/shared-video-comment/video-comment.model.ts @@ -1,5 +1,5 @@ import { getAbsoluteAPIUrl } from '@app/helpers' -import { Actor } from '@app/shared/shared-main' +import { Account, Actor } from '@app/shared/shared-main' import { Account as AccountInterface, VideoComment as VideoCommentServerModel, VideoCommentAdmin as VideoCommentAdminServerModel } from '@shared/models' export class VideoComment implements VideoCommentServerModel { @@ -38,7 +38,7 @@ export class VideoComment implements VideoCommentServerModel { if (this.account) { this.by = Actor.CREATE_BY_STRING(this.account.name, this.account.host) - this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) + this.accountAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.account) const absoluteAPIUrl = getAbsoluteAPIUrl() const thisHost = new URL(absoluteAPIUrl).host @@ -97,7 +97,7 @@ export class VideoCommentAdmin implements VideoCommentAdminServerModel { if (this.account) { this.by = Actor.CREATE_BY_STRING(this.account.name, this.account.host) - this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) + this.accountAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.account) this.account.localUrl = '/accounts/' + this.by } diff --git a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts index 3db3b7a2e..9bec16d77 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts +++ b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts @@ -1,5 +1,5 @@ import { getAbsoluteAPIUrl, getAbsoluteEmbedUrl } from '@app/helpers' -import { Actor } from '@app/shared/shared-main' +import { Account, Actor, VideoChannel } from '@app/shared/shared-main' import { peertubeTranslate } from '@shared/core-utils/i18n' import { AccountSummary, @@ -78,12 +78,12 @@ export class VideoPlaylist implements ServerVideoPlaylist { this.ownerAccount = hash.ownerAccount this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) - this.ownerAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.ownerAccount) + this.ownerAvatarUrl = Account.GET_ACTOR_AVATAR_URL(this.ownerAccount) if (hash.videoChannel) { this.videoChannel = hash.videoChannel this.videoChannelBy = Actor.CREATE_BY_STRING(hash.videoChannel.name, hash.videoChannel.host) - this.videoChannelAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.videoChannel) + this.videoChannelAvatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this.videoChannel) } this.privacy.label = peertubeTranslate(this.privacy.label, translations) diff --git a/client/src/assets/images/default-avatar-account.png b/client/src/assets/images/default-avatar-account.png new file mode 100644 index 000000000..0bedaa0c8 Binary files /dev/null and b/client/src/assets/images/default-avatar-account.png differ diff --git a/client/src/assets/images/default-avatar-videochannel.png b/client/src/assets/images/default-avatar-videochannel.png new file mode 100644 index 000000000..e24741815 Binary files /dev/null and b/client/src/assets/images/default-avatar-videochannel.png differ diff --git a/client/src/assets/images/default-avatar.png b/client/src/assets/images/default-avatar.png deleted file mode 100644 index df66422c3..000000000 Binary files a/client/src/assets/images/default-avatar.png and /dev/null differ