aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+videos
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+videos')
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.html85
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.scss99
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.ts93
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/index.ts2
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.html (renamed from client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.html)0
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.scss (renamed from client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.scss)0
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts (renamed from client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.ts)2
-rw-r--r--client/src/app/+videos/+video-watch/shared/index.ts1
-rw-r--r--client/src/app/+videos/+video-watch/shared/metadata/index.ts1
-rw-r--r--client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts5
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.html90
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.scss125
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts56
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.module.ts2
14 files changed, 312 insertions, 249 deletions
diff --git a/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.html b/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.html
new file mode 100644
index 000000000..8fb244cc4
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.html
@@ -0,0 +1,85 @@
1<div class="video-actions-rates">
2 <div class="video-actions full-width justify-content-end">
3 <my-video-rate
4 [video]="video" [isUserLoggedIn]="isUserLoggedIn"
5 (rateUpdated)="onRateUpdated($event)" (userRatingLoaded)="onRateUpdated($event)"
6 ></my-video-rate>
7
8 <button *ngIf="video.support" (click)="showSupportModal()" (keyup.enter)="showSupportModal()" class="action-button action-button-support" [attr.aria-label]="tooltipSupport"
9 [ngbTooltip]="tooltipSupport"
10 placement="bottom auto"
11 >
12 <my-global-icon iconName="support" aria-hidden="true"></my-global-icon>
13 <span class="icon-text" i18n>SUPPORT</span>
14 </button>
15
16 <button (click)="showShareModal()" (keyup.enter)="showShareModal()" class="action-button">
17 <my-global-icon iconName="share" aria-hidden="true"></my-global-icon>
18 <span class="icon-text" i18n>SHARE</span>
19 </button>
20
21 <div
22 class="action-dropdown" ngbDropdown placement="top" role="button" autoClose="outside"
23 *ngIf="isUserLoggedIn" (openChange)="addContent.openChange($event)"
24 [ngbTooltip]="tooltipSaveToPlaylist"
25 placement="bottom auto"
26 >
27 <button class="action-button action-button-save" ngbDropdownToggle>
28 <my-global-icon iconName="playlist-add" aria-hidden="true"></my-global-icon>
29 <span class="icon-text" i18n>SAVE</span>
30 </button>
31
32 <div ngbDropdownMenu>
33 <my-video-add-to-playlist #addContent [video]="video"></my-video-add-to-playlist>
34 </div>
35 </div>
36
37 <ng-container *ngIf="!isUserLoggedIn && !video.isLive">
38 <button
39 *ngIf="isVideoDownloadable()" class="action-button action-button-save"
40 (click)="showDownloadModal()" (keydown.enter)="showDownloadModal()"
41 >
42 <my-global-icon iconName="download" aria-hidden="true"></my-global-icon>
43 <span class="icon-text d-none d-sm-inline" i18n>DOWNLOAD</span>
44 </button>
45
46 <my-video-download #videoDownloadModal></my-video-download>
47 </ng-container>
48
49 <ng-container *ngIf="isUserLoggedIn">
50 <my-video-actions-dropdown
51 placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions"
52 [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()"
53 ></my-video-actions-dropdown>
54 </ng-container>
55 </div>
56
57 <div class="likes-dislikes-bar-outer-container">
58 <div
59 class="likes-dislikes-bar-inner-container"
60 *ngIf="video.likes !== 0 || video.dislikes !== 0"
61 [ngbTooltip]="likesBarTooltipText"
62 placement="bottom"
63 >
64 <div
65 class="likes-dislikes-bar"
66 >
67 <div class="likes-bar" [ngClass]="{ 'liked': userRating !== 'none' }" [ngStyle]="{ 'width.%': video.likesPercent }"></div>
68 </div>
69 </div>
70 </div>
71</div>
72
73<div
74 class="likes-dislikes-bar"
75 *ngIf="video.likes !== 0 || video.dislikes !== 0"
76 [ngbTooltip]="likesBarTooltipText"
77 placement="bottom"
78>
79 <div class="likes-bar" [ngStyle]="{ 'width.%': video.likesPercent }"></div>
80</div>
81
82<ng-container *ngIf="video">
83 <my-support-modal #supportModal [video]="video"></my-support-modal>
84 <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share>
85</ng-container>
diff --git a/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.scss b/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.scss
new file mode 100644
index 000000000..967d515e6
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.scss
@@ -0,0 +1,99 @@
1@use '_variables' as *;
2@use '_mixins' as *;
3
4.video-actions {
5 height: 40px; // Align with the title
6 display: flex;
7 align-items: center;
8
9 .action-button:not(:first-child),
10 .action-dropdown,
11 my-video-actions-dropdown {
12 @include margin-left(5px);
13 }
14
15 ::ng-deep.action-button {
16 @include peertube-button;
17 @include button-with-icon(21px, 0, -1px);
18
19 font-size: 100%;
20 font-weight: $font-semibold;
21 display: inline-block;
22 padding: 0 10px;
23 white-space: nowrap;
24 background-color: transparent !important;
25 color: pvar(--actionButtonColor);
26 text-transform: uppercase;
27
28 &::after {
29 display: none;
30 }
31
32 &:hover {
33 opacity: 0.9;
34 }
35
36 &.action-button-support {
37 color: pvar(--supportButtonColor);
38
39 my-global-icon {
40 @include apply-svg-color(pvar(--supportButtonColor));
41 }
42 }
43
44 &.action-button-support {
45 my-global-icon {
46 ::ng-deep path:first-child {
47 fill: pvar(--supportButtonHeartColor) !important;
48 }
49 }
50 }
51
52 &.action-button-save {
53 my-global-icon {
54 top: 0 !important;
55 right: -1px;
56 }
57 }
58
59 .icon-text {
60 @include margin-left(3px);
61 }
62 }
63}
64
65.likes-dislikes-bar-outer-container {
66 position: relative;
67}
68
69.likes-dislikes-bar-inner-container {
70 position: absolute;
71 height: 20px;
72}
73
74.likes-dislikes-bar {
75 $likes-bar-height: 2px;
76
77 height: $likes-bar-height;
78 margin-top: -$likes-bar-height;
79
80 width: 120px;
81 background-color: #ccc;
82 position: relative;
83 top: 10px;
84
85 .likes-bar {
86 height: 100%;
87 background-color: #909090;
88
89 &.liked {
90 background-color: pvar(--activatedActionButtonColor);
91 }
92 }
93}
94
95@media screen and (max-width: 450px) {
96 .action-button .icon-text {
97 display: none !important;
98 }
99}
diff --git a/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.ts b/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.ts
new file mode 100644
index 000000000..e59238ffe
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/action-buttons.component.ts
@@ -0,0 +1,93 @@
1import { Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core'
2import { RedirectService, ScreenService } from '@app/core'
3import { VideoDetails } from '@app/shared/shared-main'
4import { VideoShareComponent } from '@app/shared/shared-share-modal'
5import { SupportModalComponent } from '@app/shared/shared-support-modal'
6import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature'
7import { VideoPlaylist } from '@app/shared/shared-video-playlist'
8import { UserVideoRateType, VideoCaption } from '@shared/models/videos'
9
10@Component({
11 selector: 'my-action-buttons',
12 templateUrl: './action-buttons.component.html',
13 styleUrls: [ './action-buttons.component.scss' ]
14})
15export class ActionButtonsComponent implements OnInit, OnChanges {
16 @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
17 @ViewChild('supportModal') supportModal: SupportModalComponent
18 @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent
19
20 @Input() video: VideoDetails
21 @Input() videoCaptions: VideoCaption[]
22 @Input() playlist: VideoPlaylist
23
24 @Input() isUserLoggedIn: boolean
25
26 @Input() currentTime: number
27 @Input() currentPlaylistPosition: number
28
29 likesBarTooltipText = ''
30
31 tooltipSupport = ''
32 tooltipSaveToPlaylist = ''
33
34 videoActionsOptions: VideoActionsDisplayType = {
35 playlist: false,
36 download: true,
37 update: true,
38 blacklist: true,
39 delete: true,
40 report: true,
41 duplicate: true,
42 mute: true,
43 liveInfo: true
44 }
45
46 userRating: UserVideoRateType
47
48 constructor (
49 private screenService: ScreenService,
50 private redirectService: RedirectService
51 ) { }
52
53 ngOnInit () {
54 // Hide the tooltips for unlogged users in mobile view, this adds confusion with the popover
55 if (this.isUserLoggedIn || !this.screenService.isInMobileView()) {
56 this.tooltipSupport = $localize`Support options for this video`
57 this.tooltipSaveToPlaylist = $localize`Save to playlist`
58 }
59 }
60
61 ngOnChanges () {
62 this.setVideoLikesBarTooltipText()
63 }
64
65 showDownloadModal () {
66 this.videoDownloadModal.show(this.video, this.videoCaptions)
67 }
68
69 isVideoDownloadable () {
70 return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled && !this.video.isLive
71 }
72
73 showSupportModal () {
74 this.supportModal.show()
75 }
76
77 showShareModal () {
78 this.videoShareModal.show(this.currentTime, this.currentPlaylistPosition)
79 }
80
81 onRateUpdated (userRating: UserVideoRateType) {
82 this.userRating = userRating
83 this.setVideoLikesBarTooltipText()
84 }
85
86 onVideoRemoved () {
87 this.redirectService.redirectToHomepage()
88 }
89
90 private setVideoLikesBarTooltipText () {
91 this.likesBarTooltipText = `${this.video.likes} likes / ${this.video.dislikes} dislikes`
92 }
93}
diff --git a/client/src/app/+videos/+video-watch/shared/action-buttons/index.ts b/client/src/app/+videos/+video-watch/shared/action-buttons/index.ts
new file mode 100644
index 000000000..3844dd12e
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/index.ts
@@ -0,0 +1,2 @@
1export * from './action-buttons.component'
2export * from './video-rate.component'
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.html b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.html
index 7dd9b3678..7dd9b3678 100644
--- a/client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.html
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.html
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.scss b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.scss
index f4f696f33..f4f696f33 100644
--- a/client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.scss
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.scss
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.ts b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts
index 89a666a62..ecb5a9281 100644
--- a/client/src/app/+videos/+video-watch/shared/metadata/video-rate.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts
@@ -31,7 +31,7 @@ export class VideoRateComponent implements OnInit, OnChanges, OnDestroy {
31 private screenService: ScreenService 31 private screenService: ScreenService
32 ) { } 32 ) { }
33 33
34 async ngOnInit () { 34 ngOnInit () {
35 // Hide the tooltips for unlogged users in mobile view, this adds confusion with the popover 35 // Hide the tooltips for unlogged users in mobile view, this adds confusion with the popover
36 if (this.isUserLoggedIn || !this.screenService.isInMobileView()) { 36 if (this.isUserLoggedIn || !this.screenService.isInMobileView()) {
37 this.tooltipLike = $localize`Like this video` 37 this.tooltipLike = $localize`Like this video`
diff --git a/client/src/app/+videos/+video-watch/shared/index.ts b/client/src/app/+videos/+video-watch/shared/index.ts
index 6c5ff7e9b..069f862e2 100644
--- a/client/src/app/+videos/+video-watch/shared/index.ts
+++ b/client/src/app/+videos/+video-watch/shared/index.ts
@@ -1,3 +1,4 @@
1export * from './action-buttons'
1export * from './comment' 2export * from './comment'
2export * from './information' 3export * from './information'
3export * from './metadata' 4export * from './metadata'
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/index.ts b/client/src/app/+videos/+video-watch/shared/metadata/index.ts
index ba97f7011..7f7ee797b 100644
--- a/client/src/app/+videos/+video-watch/shared/metadata/index.ts
+++ b/client/src/app/+videos/+video-watch/shared/metadata/index.ts
@@ -1,3 +1,2 @@
1export * from './video-avatar-channel.component' 1export * from './video-avatar-channel.component'
2export * from './video-description.component' 2export * from './video-description.component'
3export * from './video-rate.component'
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts
index b554567d9..23d00d31a 100644
--- a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts
@@ -1,4 +1,4 @@
1import { Component, EventEmitter, Inject, Input, LOCALE_ID, OnChanges, Output } from '@angular/core' 1import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'
2import { MarkdownService, Notifier } from '@app/core' 2import { MarkdownService, Notifier } from '@app/core'
3import { VideoDetails, VideoService } from '@app/shared/shared-main' 3import { VideoDetails, VideoService } from '@app/shared/shared-main'
4 4
@@ -21,8 +21,7 @@ export class VideoDescriptionComponent implements OnChanges {
21 constructor ( 21 constructor (
22 private videoService: VideoService, 22 private videoService: VideoService,
23 private notifier: Notifier, 23 private notifier: Notifier,
24 private markdownService: MarkdownService, 24 private markdownService: MarkdownService
25 @Inject(LOCALE_ID) private localeId: string
26 ) { } 25 ) { }
27 26
28 ngOnChanges () { 27 ngOnChanges () {
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.html b/client/src/app/+videos/+video-watch/video-watch.component.html
index 2380d5a98..a84bafa2a 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.html
+++ b/client/src/app/+videos/+video-watch/video-watch.component.html
@@ -74,90 +74,13 @@
74 <my-video-views-counter [video]="video"></my-video-views-counter> 74 <my-video-views-counter [video]="video"></my-video-views-counter>
75 </div> 75 </div>
76 76
77 <div class="video-actions-rates"> 77 <my-action-buttons
78 <div class="video-actions full-width justify-content-end"> 78 [video]="video" [isUserLoggedIn]="isUserLoggedIn()" [videoCaptions]="videoCaptions" [playlist]="playlist"
79 <my-video-rate 79 [currentTime]="getCurrentTime()" [currentPlaylistPosition]="getCurrentPlaylistPosition()"
80 [video]="video" [isUserLoggedIn]="isUserLoggedIn()" 80 ></my-action-buttons>
81 (rateUpdated)="onRateUpdated($event)" (userRatingLoaded)="onRateUpdated($event)"
82 ></my-video-rate>
83
84 <button *ngIf="video.support" (click)="showSupportModal()" (keyup.enter)="showSupportModal()" class="action-button action-button-support" [attr.aria-label]="tooltipSupport"
85 [ngbTooltip]="tooltipSupport"
86 placement="bottom auto"
87 >
88 <my-global-icon iconName="support" aria-hidden="true"></my-global-icon>
89 <span class="icon-text" i18n>SUPPORT</span>
90 </button>
91
92 <button (click)="showShareModal()" (keyup.enter)="showShareModal()" class="action-button">
93 <my-global-icon iconName="share" aria-hidden="true"></my-global-icon>
94 <span class="icon-text" i18n>SHARE</span>
95 </button>
96
97 <div
98 class="action-dropdown" ngbDropdown placement="top" role="button" autoClose="outside"
99 *ngIf="isUserLoggedIn()" (openChange)="addContent.openChange($event)"
100 [ngbTooltip]="tooltipSaveToPlaylist"
101 placement="bottom auto"
102 >
103 <button class="action-button action-button-save" ngbDropdownToggle>
104 <my-global-icon iconName="playlist-add" aria-hidden="true"></my-global-icon>
105 <span class="icon-text" i18n>SAVE</span>
106 </button>
107
108 <div ngbDropdownMenu>
109 <my-video-add-to-playlist #addContent [video]="video"></my-video-add-to-playlist>
110 </div>
111 </div>
112
113 <ng-container *ngIf="!isUserLoggedIn() && !isLive()">
114 <button
115 *ngIf="isVideoDownloadable()" class="action-button action-button-save"
116 (click)="showDownloadModal()" (keydown.enter)="showDownloadModal()"
117 >
118 <my-global-icon iconName="download" aria-hidden="true"></my-global-icon>
119 <span class="icon-text d-none d-sm-inline" i18n>DOWNLOAD</span>
120 </button>
121
122 <my-video-download #videoDownloadModal></my-video-download>
123 </ng-container>
124
125 <ng-container *ngIf="isUserLoggedIn()">
126 <my-video-actions-dropdown
127 placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions"
128 [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()"
129 ></my-video-actions-dropdown>
130 </ng-container>
131 </div>
132
133 <div class="video-info-likes-dislikes-bar-outer-container">
134 <div
135 class="video-info-likes-dislikes-bar-inner-container"
136 *ngIf="video.likes !== 0 || video.dislikes !== 0"
137 [ngbTooltip]="likesBarTooltipText"
138 placement="bottom"
139 >
140 <div
141 class="video-info-likes-dislikes-bar"
142 >
143 <div class="likes-bar" [ngClass]="{ 'liked': userRating !== 'none' }" [ngStyle]="{ 'width.%': video.likesPercent }"></div>
144 </div>
145 </div>
146 </div>
147 </div>
148
149 <div
150 class="video-info-likes-dislikes-bar"
151 *ngIf="video.likes !== 0 || video.dislikes !== 0"
152 [ngbTooltip]="likesBarTooltipText"
153 placement="bottom"
154 >
155 <div class="likes-bar" [ngStyle]="{ 'width.%': video.likesPercent }"></div>
156 </div>
157 </div> 81 </div>
158 </div> 82 </div>
159 83
160
161 <div class="pt-3 border-top video-info-channel d-flex"> 84 <div class="pt-3 border-top video-info-channel d-flex">
162 <div class="video-info-channel-left d-flex"> 85 <div class="video-info-channel-left d-flex">
163 <my-video-avatar-channel [video]="video" [genericChannel]="isChannelDisplayNameGeneric()"></my-video-avatar-channel> 86 <my-video-avatar-channel [video]="video" [genericChannel]="isChannelDisplayNameGeneric()"></my-video-avatar-channel>
@@ -264,9 +187,4 @@
264 <my-privacy-concerns></my-privacy-concerns> 187 <my-privacy-concerns></my-privacy-concerns>
265</div> 188</div>
266 189
267<ng-container *ngIf="video !== null">
268 <my-support-modal #supportModal [video]="video"></my-support-modal>
269 <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share>
270</ng-container>
271
272<my-player-styles></my-player-styles> 190<my-player-styles></my-player-styles>
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.scss b/client/src/app/+videos/+video-watch/video-watch.component.scss
index e075fc57e..1d83fa139 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.scss
+++ b/client/src/app/+videos/+video-watch/video-watch.component.scss
@@ -151,6 +151,7 @@
151 @include peertube-word-wrap; 151 @include peertube-word-wrap;
152 152
153 @include margin-right(30px); 153 @include margin-right(30px);
154
154 min-height: 40px; // Align with the action buttons 155 min-height: 40px; // Align with the action buttons
155 font-size: 27px; 156 font-size: 27px;
156 font-weight: $font-semibold; 157 font-weight: $font-semibold;
@@ -211,106 +212,6 @@
211 @include margin-left(5px); 212 @include margin-left(5px);
212 } 213 }
213 } 214 }
214
215 .video-actions-rates {
216 @include margin-left(auto);
217 @include margin-right(0);
218
219 margin-top: 0;
220 margin-bottom: 10px;
221
222 align-items: start;
223 width: max-content;
224
225 .video-actions {
226 height: 40px; // Align with the title
227 display: flex;
228 align-items: center;
229
230 .action-button:not(:first-child),
231 .action-dropdown,
232 my-video-actions-dropdown {
233 @include margin-left(5px);
234 }
235
236 ::ng-deep.action-button {
237 @include peertube-button;
238 @include button-with-icon(21px, 0, -1px);
239
240 font-size: 100%;
241 font-weight: $font-semibold;
242 display: inline-block;
243 padding: 0 10px;
244 white-space: nowrap;
245 background-color: transparent !important;
246 color: pvar(--actionButtonColor);
247 text-transform: uppercase;
248
249 &::after {
250 display: none;
251 }
252
253 &:hover {
254 opacity: 0.9;
255 }
256
257 &.action-button-support {
258 color: pvar(--supportButtonColor);
259
260 my-global-icon {
261 @include apply-svg-color(pvar(--supportButtonColor));
262 }
263 }
264
265 &.action-button-support {
266 my-global-icon {
267 ::ng-deep path:first-child {
268 fill: pvar(--supportButtonHeartColor) !important;
269 }
270 }
271 }
272
273 &.action-button-save {
274 my-global-icon {
275 top: 0 !important;
276 right: -1px;
277 }
278 }
279
280 .icon-text {
281 @include margin-left(3px);
282 }
283 }
284 }
285
286 .video-info-likes-dislikes-bar-outer-container {
287 position: relative;
288 }
289
290 .video-info-likes-dislikes-bar-inner-container {
291 position: absolute;
292 height: 20px;
293 }
294
295 .video-info-likes-dislikes-bar {
296 $likes-bar-height: 2px;
297 height: $likes-bar-height;
298 margin-top: -$likes-bar-height;
299 width: 120px;
300 background-color: #ccc;
301 position: relative;
302 top: 10px;
303
304 .likes-bar {
305 height: 100%;
306 background-color: #909090;
307
308 &.liked {
309 background-color: pvar(--activatedActionButtonColor);
310 }
311 }
312 }
313 }
314 } 215 }
315 216
316 .video-attributes { 217 .video-attributes {
@@ -351,6 +252,18 @@
351 } 252 }
352} 253}
353 254
255my-action-buttons {
256 @include margin-left(auto);
257 @include margin-right(0);
258
259 display: block;
260 margin-top: 0;
261 margin-bottom: 10px;
262
263 align-items: start;
264 width: max-content;
265}
266
354my-recommended-videos { 267my-recommended-videos {
355 @include padding-left(15px); 268 @include padding-left(15px);
356 269
@@ -411,10 +324,6 @@ my-video-comments {
411 324
412@media screen and (max-width: 450px) { 325@media screen and (max-width: 450px) {
413 .video-bottom { 326 .video-bottom {
414 .action-button .icon-text {
415 display: none !important;
416 }
417
418 .video-info .video-info-first-row { 327 .video-info .video-info-first-row {
419 .video-info-name { 328 .video-info-name {
420 font-size: 18px; 329 font-size: 18px;
@@ -423,12 +332,12 @@ my-video-comments {
423 .video-info-date-views { 332 .video-info-date-views {
424 font-size: 14px; 333 font-size: 14px;
425 } 334 }
426
427 .video-actions-rates {
428 margin-top: 10px;
429 }
430 } 335 }
431 } 336 }
337
338 my-action-buttons {
339 margin-top: 10px;
340 }
432} 341}
433 342
434 343
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts
index 5a0109e64..ca20c2b85 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -18,24 +18,13 @@ import {
18 UserService 18 UserService
19} from '@app/core' 19} from '@app/core'
20import { HooksService } from '@app/core/plugins/hooks.service' 20import { HooksService } from '@app/core/plugins/hooks.service'
21import { RedirectService } from '@app/core/routing/redirect.service'
22import { isXPercentInViewport, scrollToTop } from '@app/helpers' 21import { isXPercentInViewport, scrollToTop } from '@app/helpers'
23import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main' 22import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main'
24import { VideoShareComponent } from '@app/shared/shared-share-modal'
25import { SupportModalComponent } from '@app/shared/shared-support-modal'
26import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' 23import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
27import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature' 24import { VideoActionsDisplayType } from '@app/shared/shared-video-miniature'
28import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' 25import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
29import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' 26import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
30import { 27import { HTMLServerConfig, PeerTubeProblemDocument, ServerErrorCode, VideoCaption, VideoPrivacy, VideoState } from '@shared/models'
31 HTMLServerConfig,
32 PeerTubeProblemDocument,
33 ServerErrorCode,
34 UserVideoRateType,
35 VideoCaption,
36 VideoPrivacy,
37 VideoState
38} from '@shared/models'
39import { cleanupVideoWatch, getStoredTheater, getStoredVideoWatchHistory } from '../../../assets/player/peertube-player-local-storage' 28import { cleanupVideoWatch, getStoredTheater, getStoredVideoWatchHistory } from '../../../assets/player/peertube-player-local-storage'
40import { 29import {
41 CustomizationOptions, 30 CustomizationOptions,
@@ -58,10 +47,7 @@ type URLOptions = CustomizationOptions & { playerMode: PlayerMode }
58}) 47})
59export class VideoWatchComponent implements OnInit, OnDestroy { 48export class VideoWatchComponent implements OnInit, OnDestroy {
60 @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent 49 @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent
61 @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
62 @ViewChild('supportModal') supportModal: SupportModalComponent
63 @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent 50 @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent
64 @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent
65 51
66 player: any 52 player: any
67 playerElement: HTMLVideoElement 53 playerElement: HTMLVideoElement
@@ -95,8 +81,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
95 liveInfo: true 81 liveInfo: true
96 } 82 }
97 83
98 userRating: UserVideoRateType
99
100 private nextVideoUuid = '' 84 private nextVideoUuid = ''
101 private nextVideoTitle = '' 85 private nextVideoTitle = ''
102 private currentTime: number 86 private currentTime: number
@@ -124,7 +108,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
124 private restExtractor: RestExtractor, 108 private restExtractor: RestExtractor,
125 private notifier: Notifier, 109 private notifier: Notifier,
126 private zone: NgZone, 110 private zone: NgZone,
127 private redirectService: RedirectService,
128 private videoCaptionService: VideoCaptionService, 111 private videoCaptionService: VideoCaptionService,
129 private hotkeysService: HotkeysService, 112 private hotkeysService: HotkeysService,
130 private hooks: HooksService, 113 private hooks: HooksService,
@@ -203,20 +186,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
203 this.hotkeysService.remove(this.hotkeys) 186 this.hotkeysService.remove(this.hotkeys)
204 } 187 }
205 188
206 showDownloadModal () { 189 getCurrentTime () {
207 this.videoDownloadModal.show(this.video, this.videoCaptions) 190 return this.currentTime
208 }
209
210 isVideoDownloadable () {
211 return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled && !this.video.isLive
212 } 191 }
213 192
214 showSupportModal () { 193 getCurrentPlaylistPosition () {
215 this.supportModal.show() 194 return this.videoWatchPlaylist.currentPlaylistPosition
216 }
217
218 showShareModal () {
219 this.videoShareModal.show(this.currentTime, this.videoWatchPlaylist.currentPlaylistPosition)
220 } 195 }
221 196
222 isUserLoggedIn () { 197 isUserLoggedIn () {
@@ -245,10 +220,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
245 } 220 }
246 } 221 }
247 222
248 onVideoRemoved () {
249 this.redirectService.redirectToHomepage()
250 }
251
252 isVideoToTranscode () { 223 isVideoToTranscode () {
253 return this.video && this.video.state.id === VideoState.TO_TRANSCODE 224 return this.video && this.video.state.id === VideoState.TO_TRANSCODE
254 } 225 }
@@ -261,10 +232,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
261 return this.video && this.video.scheduledUpdate !== undefined 232 return this.video && this.video.scheduledUpdate !== undefined
262 } 233 }
263 234
264 isLive () {
265 return !!(this.video?.isLive)
266 }
267
268 isWaitingForLive () { 235 isWaitingForLive () {
269 return this.video?.state.id === VideoState.WAITING_FOR_LIVE 236 return this.video?.state.id === VideoState.WAITING_FOR_LIVE
270 } 237 }
@@ -311,11 +278,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
311 this.loadVideo(videoId) 278 this.loadVideo(videoId)
312 } 279 }
313 280
314 onRateUpdated (userRating: UserVideoRateType) {
315 this.userRating = userRating
316 this.setVideoLikesBarTooltipText()
317 }
318
319 displayOtherVideosAsRow () { 281 displayOtherVideosAsRow () {
320 // Use the same value as in the SASS file 282 // Use the same value as in the SASS file
321 return this.screenService.getWindowInnerWidth() <= 1100 283 return this.screenService.getWindowInnerWidth() <= 1100
@@ -421,10 +383,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
421 }) 383 })
422 } 384 }
423 385
424 private setVideoLikesBarTooltipText () {
425 this.likesBarTooltipText = `${this.video.likes} likes / ${this.video.dislikes} dislikes`
426 }
427
428 private handleError (err: any) { 386 private handleError (err: any) {
429 const errorMessage: string = typeof err === 'string' ? err : err.message 387 const errorMessage: string = typeof err === 'string' ? err : err.message
430 if (!errorMessage) return 388 if (!errorMessage) return
@@ -467,8 +425,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
467 this.buildPlayer(urlOptions) 425 this.buildPlayer(urlOptions)
468 .catch(err => console.error('Cannot build the player', err)) 426 .catch(err => console.error('Cannot build the player', err))
469 427
470 this.setVideoLikesBarTooltipText()
471
472 this.setOpenGraphTags() 428 this.setOpenGraphTags()
473 429
474 const hookOptions = { 430 const hookOptions = {
diff --git a/client/src/app/+videos/+video-watch/video-watch.module.ts b/client/src/app/+videos/+video-watch/video-watch.module.ts
index c1f40d785..602525342 100644
--- a/client/src/app/+videos/+video-watch/video-watch.module.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.module.ts
@@ -19,6 +19,7 @@ import {
19 VideoDescriptionComponent, 19 VideoDescriptionComponent,
20 VideoRateComponent, 20 VideoRateComponent,
21 VideoWatchPlaylistComponent, 21 VideoWatchPlaylistComponent,
22 ActionButtonsComponent,
22 PrivacyConcernsComponent 23 PrivacyConcernsComponent
23} from './shared' 24} from './shared'
24import { VideoCommentAddComponent } from './shared/comment/video-comment-add.component' 25import { VideoCommentAddComponent } from './shared/comment/video-comment-add.component'
@@ -53,6 +54,7 @@ import { VideoWatchComponent } from './video-watch.component'
53 VideoRateComponent, 54 VideoRateComponent,
54 VideoDescriptionComponent, 55 VideoDescriptionComponent,
55 PrivacyConcernsComponent, 56 PrivacyConcernsComponent,
57 ActionButtonsComponent,
56 58
57 VideoCommentsComponent, 59 VideoCommentsComponent,
58 VideoCommentAddComponent, 60 VideoCommentAddComponent,