From d0800f7661f13fabe7bb6f4aa0ea50764f106405 Mon Sep 17 00:00:00 2001 From: kontrollanten <6680299+kontrollanten@users.noreply.github.com> Date: Mon, 28 Feb 2022 08:34:43 +0100 Subject: Implement avatar miniatures (#4639) * client: remove unused file * refactor(client/my-actor-avatar): size from input Read size from component input instead of scss, to make it possible to use smaller avatar images when implemented. * implement avatar miniatures close #4560 * fix(test): max file size * fix(search-index): normalize res acc to avatarMini * refactor avatars to an array * client/search: resize channel avatar to 120 * refactor(client/videos): remove unused function * client(actor-avatar): set default size * fix tests and avatars full result When findOne is used only an array containting one avatar is returned. * update migration version and version notations * server/search: harmonize normalizing * Cleanup avatar miniature PR Co-authored-by: Chocobozzz --- .../abuse-list-table.component.html | 2 +- .../actor-avatar-edit.component.ts | 2 +- .../shared-actor-image/actor-avatar.component.scss | 29 ++++----------- .../shared-actor-image/actor-avatar.component.ts | 15 ++++---- .../channel-miniature-markup.component.html | 2 +- .../channel-miniature-markup.component.scss | 2 -- .../select/select-channel.component.ts | 2 +- .../shared/shared-main/account/account.model.ts | 16 +++++---- .../app/shared/shared-main/account/actor.model.ts | 20 ++++++----- .../misc/channels-setup-message.component.ts | 2 +- .../shared-main/users/user-notification.model.ts | 8 ++--- .../video-channel/video-channel.model.ts | 42 ++++++++++++---------- .../video-channel/video-channel.service.ts | 2 +- .../app/shared/shared-main/video/video.model.ts | 12 +++++-- .../account-blocklist.component.html | 2 +- .../video-miniature.component.html | 2 ++ 16 files changed, 82 insertions(+), 78 deletions(-) (limited to 'client/src/app/shared') diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html index 07cc73461..f0a27c6e2 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html @@ -43,7 +43,7 @@
- +
{{ abuse.reporterAccount.displayName }} {{ abuse.reporterAccount.nameWithHost }} diff --git a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts index 8b7d64ed3..01bb401fb 100644 --- a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts +++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts @@ -72,7 +72,7 @@ export class ActorAvatarEditComponent implements OnInit { } hasAvatar () { - return !!this.preview || !!this.actor.avatar + return !!this.preview || this.actor.avatars.length !== 0 } isChannel () { diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.scss b/client/src/app/shared/shared-actor-image/actor-avatar.component.scss index a2424b593..68bf74553 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar.component.scss +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.scss @@ -20,38 +20,23 @@ } } -.avatar-18 { - --avatarSize: 18px; - --initialFontSize: 13px; -} +$sizes: '18', '25', '28', '32', '34', '35', '36', '40', '48', '75', '80', '100', '120'; -.avatar-25 { - --avatarSize: 25px; +@each $size in $sizes { + .avatar-#{$size} { + --avatarSize: #{$size}px; + } } -.avatar-32 { - --avatarSize: 32px; -} - -.avatar-34 { - --avatarSize: 34px; -} - -.avatar-36 { - --avatarSize: 36px; -} - -.avatar-40 { - --avatarSize: 40px; +.avatar-18 { + --initialFontSize: 13px; } .avatar-100 { - --avatarSize: 100px; --initialFontSize: 40px; } .avatar-120 { - --avatarSize: 120px; --initialFontSize: 46px; } diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts index c323dc724..bc7e8a096 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts @@ -4,11 +4,11 @@ import { Account } from '../shared-main/account/account.model' type ActorInput = { name: string - avatar?: { url?: string, path: string } + avatars: { width: number, url?: string, path: string }[] url: string } -export type ActorAvatarSize = '18' | '25' | '32' | '34' | '36' | '40' | '100' | '120' +export type ActorAvatarSize = '18' | '25' | '28' | '32' | '34' | '35' | '36' | '40' | '48' | '75' | '80' | '100' | '120' @Component({ selector: 'my-actor-avatar', @@ -23,7 +23,7 @@ export class ActorAvatarComponent { @Input() previewImage: string - @Input() size: ActorAvatarSize + @Input() size: ActorAvatarSize = '32' // Use an external link @Input() href: string @@ -50,14 +50,13 @@ export class ActorAvatarComponent { } get defaultAvatarUrl () { - if (this.channel) return VideoChannel.GET_DEFAULT_AVATAR_URL() - - return Account.GET_DEFAULT_AVATAR_URL() + if (this.account) return Account.GET_DEFAULT_AVATAR_URL(+this.size) + if (this.channel) return VideoChannel.GET_DEFAULT_AVATAR_URL(+this.size) } get avatarUrl () { - if (this.account) return Account.GET_ACTOR_AVATAR_URL(this.account) - if (this.channel) return VideoChannel.GET_ACTOR_AVATAR_URL(this.channel) + if (this.account) return Account.GET_ACTOR_AVATAR_URL(this.account, +this.size) + if (this.channel) return VideoChannel.GET_ACTOR_AVATAR_URL(this.channel, +this.size) return '' } diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html index de150aac9..52a402329 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.html @@ -1,7 +1,7 @@
- +
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss index 39e8d2091..e8ef478d9 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.scss @@ -26,8 +26,6 @@ } my-actor-avatar { - @include actor-avatar-size(75px); - grid-column: 1; grid-row: 1 / 4; } 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 40a7c53bb..5fcae0050 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 @@ -31,7 +31,7 @@ export class SelectChannelComponent implements ControlValueAccessor, OnChanges { this.channels = this.items.map(c => { const avatarPath = c.avatarPath ? c.avatarPath - : VideoChannel.GET_DEFAULT_AVATAR_URL() + : VideoChannel.GET_DEFAULT_AVATAR_URL(20) return Object.assign({}, c, { avatarPath }) }) 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 8b78d01a6..a26a9c11c 100644 --- a/client/src/app/shared/shared-main/account/account.model.ts +++ b/client/src/app/shared/shared-main/account/account.model.ts @@ -17,11 +17,15 @@ export class Account extends Actor implements ServerAccount { userId?: number - static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) { - return Actor.GET_ACTOR_AVATAR_URL(actor) + static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { + return Actor.GET_ACTOR_AVATAR_URL(actor, size) } - static GET_DEFAULT_AVATAR_URL () { + static GET_DEFAULT_AVATAR_URL (size: number) { + if (size <= 48) { + return `${window.location.origin}/client/assets/images/default-avatar-account-48x48.png` + } + return `${window.location.origin}/client/assets/images/default-avatar-account.png` } @@ -42,12 +46,12 @@ export class Account extends Actor implements ServerAccount { this.mutedServerByInstance = false } - updateAvatar (newAvatar: ActorImage) { - this.avatar = newAvatar + updateAvatar (newAvatars: ActorImage[]) { + this.avatars = newAvatars } resetAvatar () { - this.avatar = null + this.avatars = [] } updateBlockStatus (blockStatus: BlockStatus) { 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 082f44fb9..a54f51aa4 100644 --- a/client/src/app/shared/shared-main/account/actor.model.ts +++ b/client/src/app/shared/shared-main/account/actor.model.ts @@ -13,20 +13,22 @@ export abstract class Actor implements ServerActor { createdAt: Date | string - avatar: ActorImage + // TODO: remove, deprecated in 4.2 + avatar: never + + avatars: ActorImage[] isLocal: boolean - static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) { - if (actor?.avatar?.url) return actor.avatar.url + static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { + const avatar = actor.avatars.sort((a, b) => a.width - b.width).find(a => a.width >= size) - if (actor?.avatar) { - const absoluteAPIUrl = getAbsoluteAPIUrl() + if (!avatar) return '' + if (avatar.url) return avatar.url - return absoluteAPIUrl + actor.avatar.path - } + const absoluteAPIUrl = getAbsoluteAPIUrl() - return '' + return absoluteAPIUrl + avatar.path } static CREATE_BY_STRING (accountName: string, host: string, forceHostname = false) { @@ -55,7 +57,7 @@ export abstract class Actor implements ServerActor { if (hash.createdAt) this.createdAt = new Date(hash.createdAt.toString()) - this.avatar = hash.avatar + this.avatars = hash.avatars this.isLocal = Actor.IS_LOCAL(this.host) } } diff --git a/client/src/app/shared/shared-main/misc/channels-setup-message.component.ts b/client/src/app/shared/shared-main/misc/channels-setup-message.component.ts index 702475029..4f9cbc525 100644 --- a/client/src/app/shared/shared-main/misc/channels-setup-message.component.ts +++ b/client/src/app/shared/shared-main/misc/channels-setup-message.component.ts @@ -19,7 +19,7 @@ export class ChannelsSetupMessageComponent implements OnInit { hasChannelNotConfigured () { if (!this.user.videoChannels) return false - return this.user.videoChannels.filter((channel: VideoChannel) => (!channel.avatar || !channel.description)).length > 0 + return this.user.videoChannels.filter((channel: VideoChannel) => (channel.avatars.length === 0 || !channel.description)).length > 0 } ngOnInit () { 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 439547102..1eb69d5a2 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 @@ -254,11 +254,11 @@ export class UserNotification implements UserNotificationServer { return [ this.buildVideoUrl(comment.video), { threadId: comment.threadId } ] } - private setAccountAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { - actor.avatarUrl = Account.GET_ACTOR_AVATAR_URL(actor) || Account.GET_DEFAULT_AVATAR_URL() + private setAccountAvatarUrl (actor: { avatarUrl?: string, avatars: { width: number, url?: string, path: string }[] }) { + actor.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(actor, 48) || Account.GET_DEFAULT_AVATAR_URL(48) } - private setVideoChannelAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) { - actor.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(actor) || VideoChannel.GET_DEFAULT_AVATAR_URL() + private setVideoChannelAvatarUrl (actor: { avatarUrl?: string, avatars: { width: number, url?: string, path: string }[] }) { + actor.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(actor, 48) || VideoChannel.GET_DEFAULT_AVATAR_URL(48) } } 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 ac2679b42..e22b0cfd0 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 @@ -12,7 +12,11 @@ export class VideoChannel extends Actor implements ServerVideoChannel { nameWithHost: string nameWithHostForced: string - banner: ActorImage + // TODO: remove, deprecated in 4.2 + banner: never + + banners: ActorImage[] + bannerUrl: string updatedAt: Date | string @@ -24,23 +28,25 @@ export class VideoChannel extends Actor implements ServerVideoChannel { viewsPerDay?: ViewsPerDate[] - static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) { - return Actor.GET_ACTOR_AVATAR_URL(actor) + static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { + return Actor.GET_ACTOR_AVATAR_URL(actor, size) } static GET_ACTOR_BANNER_URL (channel: ServerVideoChannel) { - if (channel?.banner?.url) return channel.banner.url - - if (channel?.banner) { - const absoluteAPIUrl = getAbsoluteAPIUrl() + if (!channel) return '' - return absoluteAPIUrl + channel.banner.path - } + const banner = channel.banners[0] + if (!banner) return '' - return '' + if (banner.url) return banner.url + return getAbsoluteAPIUrl() + banner.path } - static GET_DEFAULT_AVATAR_URL () { + static GET_DEFAULT_AVATAR_URL (size: number) { + if (size <= 48) { + return `${window.location.origin}/client/assets/images/default-avatar-video-channel-48x48.png` + } + return `${window.location.origin}/client/assets/images/default-avatar-video-channel.png` } @@ -51,7 +57,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel { this.description = hash.description this.support = hash.support - this.banner = hash.banner + this.banners = hash.banners this.isLocal = hash.isLocal @@ -74,24 +80,24 @@ export class VideoChannel extends Actor implements ServerVideoChannel { this.updateComputedAttributes() } - updateAvatar (newAvatar: ActorImage) { - this.avatar = newAvatar + updateAvatar (newAvatars: ActorImage[]) { + this.avatars = newAvatars this.updateComputedAttributes() } resetAvatar () { - this.updateAvatar(null) + this.updateAvatar([]) } - updateBanner (newBanner: ActorImage) { - this.banner = newBanner + updateBanner (newBanners: ActorImage[]) { + this.banners = newBanners this.updateComputedAttributes() } resetBanner () { - this.updateBanner(null) + this.updateBanner([]) } updateComputedAttributes () { diff --git a/client/src/app/shared/shared-main/video-channel/video-channel.service.ts b/client/src/app/shared/shared-main/video-channel/video-channel.service.ts index f37f13c51..480d250fb 100644 --- a/client/src/app/shared/shared-main/video-channel/video-channel.service.ts +++ b/client/src/app/shared/shared-main/video-channel/video-channel.service.ts @@ -80,7 +80,7 @@ export class VideoChannelService { changeVideoChannelImage (videoChannelName: string, avatarForm: FormData, type: 'avatar' | 'banner') { const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelName + '/' + type + '/pick' - return this.authHttp.post<{ avatar?: ActorImage, banner?: ActorImage }>(url, avatarForm) + return this.authHttp.post<{ avatars?: ActorImage[], banners?: ActorImage[] }>(url, avatarForm) .pipe(catchError(err => this.restExtractor.handleError(err))) } 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 fe5643688..8e275181c 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts @@ -84,7 +84,11 @@ export class Video implements VideoServerModel { displayName: string url: string host: string - avatar?: ActorImage + + // TODO: remove, deprecated in 4.2 + avatar: ActorImage + + avatars: ActorImage[] } channel: { @@ -93,7 +97,11 @@ export class Video implements VideoServerModel { displayName: string url: string host: string - avatar?: ActorImage + + // TODO: remove, deprecated in 4.2 + avatar: ActorImage + + avatars: ActorImage[] } userHistory?: { diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.html b/client/src/app/shared/shared-moderation/account-blocklist.component.html index 637abcb51..0143194e9 100644 --- a/client/src/app/shared/shared-moderation/account-blocklist.component.html +++ b/client/src/app/shared/shared-moderation/account-blocklist.component.html @@ -33,7 +33,7 @@
- +
{{ accountBlock.blockedAccount.displayName }} {{ accountBlock.blockedAccount.nameWithHost }} diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.html b/client/src/app/shared/shared-video-miniature/video-miniature.component.html index 30483831a..3cf128de0 100644 --- a/client/src/app/shared/shared-video-miniature/video-miniature.component.html +++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.html @@ -13,11 +13,13 @@
-- cgit v1.2.3