diff options
Diffstat (limited to 'client/src/app/shared/shared-main')
6 files changed, 83 insertions, 10 deletions
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 b3dc6cfe5..b71a893d1 100644 --- a/client/src/app/shared/shared-main/account/account.model.ts +++ b/client/src/app/shared/shared-main/account/account.model.ts | |||
@@ -44,6 +44,11 @@ export class Account extends Actor implements ServerAccount { | |||
44 | this.updateComputedAttributes() | 44 | this.updateComputedAttributes() |
45 | } | 45 | } |
46 | 46 | ||
47 | resetAvatar () { | ||
48 | this.avatar = null | ||
49 | this.avatarUrl = Account.GET_DEFAULT_AVATAR_URL() | ||
50 | } | ||
51 | |||
47 | private updateComputedAttributes () { | 52 | private updateComputedAttributes () { |
48 | this.avatarUrl = Account.GET_ACTOR_AVATAR_URL(this) | 53 | this.avatarUrl = Account.GET_ACTOR_AVATAR_URL(this) |
49 | } | 54 | } |
diff --git a/client/src/app/shared/shared-main/account/actor-avatar-info.component.html b/client/src/app/shared/shared-main/account/actor-avatar-info.component.html index e63d8de2d..a34d27b26 100644 --- a/client/src/app/shared/shared-main/account/actor-avatar-info.component.html +++ b/client/src/app/shared/shared-main/account/actor-avatar-info.component.html | |||
@@ -4,12 +4,18 @@ | |||
4 | <img [src]="actor.avatarUrl" alt="Avatar" /> | 4 | <img [src]="actor.avatarUrl" alt="Avatar" /> |
5 | 5 | ||
6 | <div class="actor-img-edit-container"> | 6 | <div class="actor-img-edit-container"> |
7 | <div class="actor-img-edit-button" [ngbTooltip]="avatarFormat" | 7 | |
8 | placement="right" container="body"> | 8 | <div *ngIf="!hasAvatar" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body"> |
9 | <my-global-icon iconName="upload"></my-global-icon> | ||
10 | <label class="sr-only" for="avatarfile" i18n>Upload a new avatar</label> | ||
11 | <input #avatarfileInput type="file" title=" " name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/> | ||
12 | </div> | ||
13 | |||
14 | <div *ngIf="hasAvatar" class="actor-img-edit-button" #avatarPopover="ngbPopover" [ngbPopover]="avatarEditContent" popoverClass="popover-avatar-info" autoClose="outside" placement="right"> | ||
9 | <my-global-icon iconName="edit"></my-global-icon> | 15 | <my-global-icon iconName="edit"></my-global-icon> |
10 | <label for="avatarfile" i18n>Change your avatar</label> | 16 | <label class="sr-only" for="avatarMenu" i18n>Change your avatar</label> |
11 | <input #avatarfileInput type="file" title=" " name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange()"/> | ||
12 | </div> | 17 | </div> |
18 | |||
13 | </div> | 19 | </div> |
14 | </div> | 20 | </div> |
15 | 21 | ||
@@ -22,4 +28,16 @@ | |||
22 | <div i18n class="actor-info-followers">{{ actor.followersCount }} subscribers</div> | 28 | <div i18n class="actor-info-followers">{{ actor.followersCount }} subscribers</div> |
23 | </div> | 29 | </div> |
24 | </div> | 30 | </div> |
25 | </ng-container> \ No newline at end of file | 31 | </ng-container> |
32 | |||
33 | <ng-template #avatarEditContent> | ||
34 | <div class="dropdown-item c-hand" [ngbTooltip]="avatarFormat" placement="right" container="body"> | ||
35 | <my-global-icon iconName="upload"></my-global-icon> | ||
36 | <span for="avatarfile" i18n>Upload a new avatar</span> | ||
37 | <input #avatarfileInput type="file" title=" " name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/> | ||
38 | </div> | ||
39 | <div class="dropdown-item c-hand" (click)="deleteAvatar()" (key.enter)="deleteAvatar()"> | ||
40 | <my-global-icon iconName="delete"></my-global-icon> | ||
41 | <span i18n>Remove avatar</span> | ||
42 | </div> | ||
43 | </ng-template> \ No newline at end of file | ||
diff --git a/client/src/app/shared/shared-main/account/actor-avatar-info.component.scss b/client/src/app/shared/shared-main/account/actor-avatar-info.component.scss index 7118e9471..57c298508 100644 --- a/client/src/app/shared/shared-main/account/actor-avatar-info.component.scss +++ b/client/src/app/shared/shared-main/account/actor-avatar-info.component.scss | |||
@@ -70,3 +70,17 @@ | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | } | 72 | } |
73 | |||
74 | .actor-img-edit-container ::ng-deep .popover-avatar-info .popover-body { | ||
75 | padding: 0; | ||
76 | |||
77 | .dropdown-item { | ||
78 | padding: 6px 10px; | ||
79 | border-radius: 4px; | ||
80 | |||
81 | &:first-child { | ||
82 | @include peertube-file; | ||
83 | display: block; | ||
84 | } | ||
85 | } | ||
86 | } | ||
diff --git a/client/src/app/shared/shared-main/account/actor-avatar-info.component.ts b/client/src/app/shared/shared-main/account/actor-avatar-info.component.ts index de78a390e..451bbbba3 100644 --- a/client/src/app/shared/shared-main/account/actor-avatar-info.component.ts +++ b/client/src/app/shared/shared-main/account/actor-avatar-info.component.ts | |||
@@ -1,22 +1,27 @@ | |||
1 | import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' | 1 | import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core' |
2 | import { Notifier, ServerService } from '@app/core' | 2 | import { Notifier, ServerService } from '@app/core' |
3 | import { getBytes } from '@root-helpers/bytes' | 3 | import { getBytes } from '@root-helpers/bytes' |
4 | import { ServerConfig } from '@shared/models' | 4 | import { ServerConfig } from '@shared/models' |
5 | import { VideoChannel } from '../video-channel/video-channel.model' | 5 | import { VideoChannel } from '../video-channel/video-channel.model' |
6 | import { Account } from '../account/account.model' | 6 | import { Account } from '../account/account.model' |
7 | import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' | ||
8 | import { Actor } from './actor.model' | ||
7 | 9 | ||
8 | @Component({ | 10 | @Component({ |
9 | selector: 'my-actor-avatar-info', | 11 | selector: 'my-actor-avatar-info', |
10 | templateUrl: './actor-avatar-info.component.html', | 12 | templateUrl: './actor-avatar-info.component.html', |
11 | styleUrls: [ './actor-avatar-info.component.scss' ] | 13 | styleUrls: [ './actor-avatar-info.component.scss' ] |
12 | }) | 14 | }) |
13 | export class ActorAvatarInfoComponent implements OnInit { | 15 | export class ActorAvatarInfoComponent implements OnInit, OnChanges { |
14 | @ViewChild('avatarfileInput') avatarfileInput: ElementRef<HTMLInputElement> | 16 | @ViewChild('avatarfileInput') avatarfileInput: ElementRef<HTMLInputElement> |
17 | @ViewChild('avatarPopover') avatarPopover: NgbPopover | ||
15 | 18 | ||
16 | @Input() actor: VideoChannel | Account | 19 | @Input() actor: VideoChannel | Account |
17 | 20 | ||
18 | @Output() avatarChange = new EventEmitter<FormData>() | 21 | @Output() avatarChange = new EventEmitter<FormData>() |
22 | @Output() avatarDelete = new EventEmitter<void>() | ||
19 | 23 | ||
24 | private avatarUrl: string | ||
20 | private serverConfig: ServerConfig | 25 | private serverConfig: ServerConfig |
21 | 26 | ||
22 | constructor ( | 27 | constructor ( |
@@ -30,19 +35,31 @@ export class ActorAvatarInfoComponent implements OnInit { | |||
30 | .subscribe(config => this.serverConfig = config) | 35 | .subscribe(config => this.serverConfig = config) |
31 | } | 36 | } |
32 | 37 | ||
33 | onAvatarChange () { | 38 | ngOnChanges (changes: SimpleChanges) { |
39 | if (changes['actor']) { | ||
40 | this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.actor) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | onAvatarChange (input: HTMLInputElement) { | ||
45 | this.avatarfileInput = new ElementRef(input) | ||
46 | |||
34 | const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ] | 47 | const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ] |
35 | if (avatarfile.size > this.maxAvatarSize) { | 48 | if (avatarfile.size > this.maxAvatarSize) { |
36 | this.notifier.error('Error', 'This image is too large.') | 49 | this.notifier.error('Error', $localize`This image is too large.`) |
37 | return | 50 | return |
38 | } | 51 | } |
39 | 52 | ||
40 | const formData = new FormData() | 53 | const formData = new FormData() |
41 | formData.append('avatarfile', avatarfile) | 54 | formData.append('avatarfile', avatarfile) |
42 | 55 | this.avatarPopover?.close() | |
43 | this.avatarChange.emit(formData) | 56 | this.avatarChange.emit(formData) |
44 | } | 57 | } |
45 | 58 | ||
59 | deleteAvatar () { | ||
60 | this.avatarDelete.emit() | ||
61 | } | ||
62 | |||
46 | get maxAvatarSize () { | 63 | get maxAvatarSize () { |
47 | return this.serverConfig.avatar.file.size.max | 64 | return this.serverConfig.avatar.file.size.max |
48 | } | 65 | } |
@@ -58,4 +75,8 @@ export class ActorAvatarInfoComponent implements OnInit { | |||
58 | get avatarFormat () { | 75 | get avatarFormat () { |
59 | return `${$localize`max size`}: 192*192px, ${this.maxAvatarSizeInBytes} ${$localize`extensions`}: ${this.avatarExtensions}` | 76 | return `${$localize`max size`}: 192*192px, ${this.maxAvatarSizeInBytes} ${$localize`extensions`}: ${this.avatarExtensions}` |
60 | } | 77 | } |
78 | |||
79 | get hasAvatar () { | ||
80 | return !!this.avatarUrl | ||
81 | } | ||
61 | } | 82 | } |
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 4f1f5b65d..c6a63fe6c 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 | |||
@@ -56,6 +56,11 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
56 | this.updateComputedAttributes() | 56 | this.updateComputedAttributes() |
57 | } | 57 | } |
58 | 58 | ||
59 | resetAvatar () { | ||
60 | this.avatar = null | ||
61 | this.avatarUrl = VideoChannel.GET_DEFAULT_AVATAR_URL() | ||
62 | } | ||
63 | |||
59 | private updateComputedAttributes () { | 64 | private updateComputedAttributes () { |
60 | this.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this) | 65 | this.avatarUrl = VideoChannel.GET_ACTOR_AVATAR_URL(this) |
61 | } | 66 | } |
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 64dcf638a..eff3fad4d 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 | |||
@@ -89,6 +89,16 @@ export class VideoChannelService { | |||
89 | .pipe(catchError(err => this.restExtractor.handleError(err))) | 89 | .pipe(catchError(err => this.restExtractor.handleError(err))) |
90 | } | 90 | } |
91 | 91 | ||
92 | deleteVideoChannelAvatar (videoChannelName: string) { | ||
93 | const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelName + '/avatar' | ||
94 | |||
95 | return this.authHttp.delete(url) | ||
96 | .pipe( | ||
97 | map(this.restExtractor.extractDataBool), | ||
98 | catchError(err => this.restExtractor.handleError(err)) | ||
99 | ) | ||
100 | } | ||
101 | |||
92 | removeVideoChannel (videoChannel: VideoChannel) { | 102 | removeVideoChannel (videoChannel: VideoChannel) { |
93 | return this.authHttp.delete(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost) | 103 | return this.authHttp.delete(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost) |
94 | .pipe( | 104 | .pipe( |