diff options
Diffstat (limited to 'client/src/app/+videos')
24 files changed, 305 insertions, 184 deletions
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts index 8780ca567..8e035b6bb 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | 1 | ||
2 | import { forkJoin } from 'rxjs' | 2 | import { forkJoin } from 'rxjs' |
3 | import { Component, EventEmitter, OnInit, Output } from '@angular/core' | 3 | import { AfterViewChecked, AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core' |
4 | import { Router } from '@angular/router' | 4 | import { Router } from '@angular/router' |
5 | import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' | 5 | import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core' |
6 | import { scrollToTop } from '@app/helpers' | 6 | import { scrollToTop } from '@app/helpers' |
7 | import { FormValidatorService } from '@app/shared/shared-forms' | 7 | import { FormValidatorService } from '@app/shared/shared-forms' |
8 | import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' | 8 | import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' |
@@ -19,7 +19,7 @@ import { VideoSend } from './video-send' | |||
19 | './video-send.scss' | 19 | './video-send.scss' |
20 | ] | 20 | ] |
21 | }) | 21 | }) |
22 | export class VideoGoLiveComponent extends VideoSend implements OnInit, CanComponentDeactivate { | 22 | export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate { |
23 | @Output() firstStepDone = new EventEmitter<string>() | 23 | @Output() firstStepDone = new EventEmitter<string>() |
24 | @Output() firstStepError = new EventEmitter<void>() | 24 | @Output() firstStepError = new EventEmitter<void>() |
25 | 25 | ||
@@ -41,7 +41,8 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, CanCompon | |||
41 | protected videoService: VideoService, | 41 | protected videoService: VideoService, |
42 | protected videoCaptionService: VideoCaptionService, | 42 | protected videoCaptionService: VideoCaptionService, |
43 | private liveVideoService: LiveVideoService, | 43 | private liveVideoService: LiveVideoService, |
44 | private router: Router | 44 | private router: Router, |
45 | private hooks: HooksService | ||
45 | ) { | 46 | ) { |
46 | super() | 47 | super() |
47 | } | 48 | } |
@@ -50,6 +51,10 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, CanCompon | |||
50 | super.ngOnInit() | 51 | super.ngOnInit() |
51 | } | 52 | } |
52 | 53 | ||
54 | ngAfterViewInit () { | ||
55 | this.hooks.runAction('action:go-live.init', 'video-edit') | ||
56 | } | ||
57 | |||
53 | canDeactivate () { | 58 | canDeactivate () { |
54 | return { canDeactivate: true } | 59 | return { canDeactivate: true } |
55 | } | 60 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss index 1fef74994..dd87641fc 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss +++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss | |||
@@ -3,8 +3,8 @@ | |||
3 | 3 | ||
4 | .first-step-block { | 4 | .first-step-block { |
5 | .torrent-or-magnet { | 5 | .torrent-or-magnet { |
6 | @include divider($color: pvar(--inputPlaceholderColor), $background: pvar(--submenuColor)); | 6 | @include divider($color: pvar(--inputPlaceholderColor), $background: pvar(--submenuBackgroundColor)); |
7 | 7 | ||
8 | &[data-content] { | 8 | &[data-content] { |
9 | margin: 1.5rem 0; | 9 | margin: 1.5rem 0; |
10 | } | 10 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts index 01087e525..3aae24732 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' | 1 | import { AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' |
2 | import { Router } from '@angular/router' | 2 | import { Router } from '@angular/router' |
3 | import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' | 3 | import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core' |
4 | import { scrollToTop } from '@app/helpers' | 4 | import { scrollToTop } from '@app/helpers' |
5 | import { FormValidatorService } from '@app/shared/shared-forms' | 5 | import { FormValidatorService } from '@app/shared/shared-forms' |
6 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' | 6 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' |
@@ -18,7 +18,7 @@ import { VideoSend } from './video-send' | |||
18 | './video-send.scss' | 18 | './video-send.scss' |
19 | ] | 19 | ] |
20 | }) | 20 | }) |
21 | export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate { | 21 | export class VideoImportTorrentComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate { |
22 | @Output() firstStepDone = new EventEmitter<string>() | 22 | @Output() firstStepDone = new EventEmitter<string>() |
23 | @Output() firstStepError = new EventEmitter<void>() | 23 | @Output() firstStepError = new EventEmitter<void>() |
24 | @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement> | 24 | @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement> |
@@ -43,7 +43,8 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca | |||
43 | protected videoService: VideoService, | 43 | protected videoService: VideoService, |
44 | protected videoCaptionService: VideoCaptionService, | 44 | protected videoCaptionService: VideoCaptionService, |
45 | private router: Router, | 45 | private router: Router, |
46 | private videoImportService: VideoImportService | 46 | private videoImportService: VideoImportService, |
47 | private hooks: HooksService | ||
47 | ) { | 48 | ) { |
48 | super() | 49 | super() |
49 | } | 50 | } |
@@ -52,6 +53,10 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca | |||
52 | super.ngOnInit() | 53 | super.ngOnInit() |
53 | } | 54 | } |
54 | 55 | ||
56 | ngAfterViewInit () { | ||
57 | this.hooks.runAction('action:video-torrent-import.init', 'video-edit') | ||
58 | } | ||
59 | |||
55 | canDeactivate () { | 60 | canDeactivate () { |
56 | return { canDeactivate: true } | 61 | return { canDeactivate: true } |
57 | } | 62 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts index c447c179d..7a9fe369f 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { map, switchMap } from 'rxjs/operators' | 1 | import { map, switchMap } from 'rxjs/operators' |
2 | import { Component, EventEmitter, OnInit, Output } from '@angular/core' | 2 | import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core' |
3 | import { Router } from '@angular/router' | 3 | import { Router } from '@angular/router' |
4 | import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' | 4 | import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core' |
5 | import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers' | 5 | import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers' |
6 | import { FormValidatorService } from '@app/shared/shared-forms' | 6 | import { FormValidatorService } from '@app/shared/shared-forms' |
7 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' | 7 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' |
@@ -18,7 +18,7 @@ import { VideoSend } from './video-send' | |||
18 | './video-send.scss' | 18 | './video-send.scss' |
19 | ] | 19 | ] |
20 | }) | 20 | }) |
21 | export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate { | 21 | export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate { |
22 | @Output() firstStepDone = new EventEmitter<string>() | 22 | @Output() firstStepDone = new EventEmitter<string>() |
23 | @Output() firstStepError = new EventEmitter<void>() | 23 | @Output() firstStepError = new EventEmitter<void>() |
24 | 24 | ||
@@ -42,8 +42,9 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom | |||
42 | protected videoService: VideoService, | 42 | protected videoService: VideoService, |
43 | protected videoCaptionService: VideoCaptionService, | 43 | protected videoCaptionService: VideoCaptionService, |
44 | private router: Router, | 44 | private router: Router, |
45 | private videoImportService: VideoImportService | 45 | private videoImportService: VideoImportService, |
46 | ) { | 46 | private hooks: HooksService |
47 | ) { | ||
47 | super() | 48 | super() |
48 | } | 49 | } |
49 | 50 | ||
@@ -51,6 +52,10 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom | |||
51 | super.ngOnInit() | 52 | super.ngOnInit() |
52 | } | 53 | } |
53 | 54 | ||
55 | ngAfterViewInit () { | ||
56 | this.hooks.runAction('action:video-url-import.init', 'video-edit') | ||
57 | } | ||
58 | |||
54 | canDeactivate () { | 59 | canDeactivate () { |
55 | return { canDeactivate: true } | 60 | return { canDeactivate: true } |
56 | } | 61 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts index ca21b61cd..effb37077 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import { Subscription } from 'rxjs' | 1 | import { Subscription } from 'rxjs' |
2 | import { HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http' | 2 | import { HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http' |
3 | import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' | 3 | import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' |
4 | import { Router } from '@angular/router' | 4 | import { Router } from '@angular/router' |
5 | import { AuthService, CanComponentDeactivate, Notifier, ServerService, UserService } from '@app/core' | 5 | import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService, UserService } from '@app/core' |
6 | import { scrollToTop, uploadErrorHandler } from '@app/helpers' | 6 | import { scrollToTop, uploadErrorHandler } from '@app/helpers' |
7 | import { FormValidatorService } from '@app/shared/shared-forms' | 7 | import { FormValidatorService } from '@app/shared/shared-forms' |
8 | import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' | 8 | import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' |
9 | import { LoadingBarService } from '@ngx-loading-bar/core' | 9 | import { LoadingBarService } from '@ngx-loading-bar/core' |
10 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | ||
10 | import { VideoPrivacy } from '@shared/models' | 11 | import { VideoPrivacy } from '@shared/models' |
11 | import { VideoSend } from './video-send' | 12 | import { VideoSend } from './video-send' |
12 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | ||
13 | 13 | ||
14 | @Component({ | 14 | @Component({ |
15 | selector: 'my-video-upload', | 15 | selector: 'my-video-upload', |
@@ -20,7 +20,7 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | |||
20 | './video-send.scss' | 20 | './video-send.scss' |
21 | ] | 21 | ] |
22 | }) | 22 | }) |
23 | export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { | 23 | export class VideoUploadComponent extends VideoSend implements OnInit, AfterViewInit, OnDestroy, CanComponentDeactivate { |
24 | @Output() firstStepDone = new EventEmitter<string>() | 24 | @Output() firstStepDone = new EventEmitter<string>() |
25 | @Output() firstStepError = new EventEmitter<void>() | 25 | @Output() firstStepError = new EventEmitter<void>() |
26 | @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement> | 26 | @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement> |
@@ -60,7 +60,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy | |||
60 | protected videoService: VideoService, | 60 | protected videoService: VideoService, |
61 | protected videoCaptionService: VideoCaptionService, | 61 | protected videoCaptionService: VideoCaptionService, |
62 | private userService: UserService, | 62 | private userService: UserService, |
63 | private router: Router | 63 | private router: Router, |
64 | private hooks: HooksService | ||
64 | ) { | 65 | ) { |
65 | super() | 66 | super() |
66 | } | 67 | } |
@@ -79,6 +80,10 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy | |||
79 | }) | 80 | }) |
80 | } | 81 | } |
81 | 82 | ||
83 | ngAfterViewInit () { | ||
84 | this.hooks.runAction('action:video-upload.init', 'video-edit') | ||
85 | } | ||
86 | |||
82 | ngOnDestroy () { | 87 | ngOnDestroy () { |
83 | if (this.videoUploadObservable) this.videoUploadObservable.unsubscribe() | 88 | if (this.videoUploadObservable) this.videoUploadObservable.unsubscribe() |
84 | } | 89 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add.component.scss b/client/src/app/+videos/+video-edit/video-add.component.scss index 5db9e823d..1ebee946b 100644 --- a/client/src/app/+videos/+video-edit/video-add.component.scss +++ b/client/src/app/+videos/+video-edit/video-add.component.scss | |||
@@ -67,7 +67,7 @@ $nav-link-height: 40px; | |||
67 | &.active { | 67 | &.active { |
68 | border-color: $border-color; | 68 | border-color: $border-color; |
69 | border-bottom-color: transparent; | 69 | border-bottom-color: transparent; |
70 | background-color: pvar(--submenuColor) !important; | 70 | background-color: pvar(--submenuBackgroundColor) !important; |
71 | 71 | ||
72 | span { | 72 | span { |
73 | border-bottom-color: pvar(--mainColor); | 73 | border-bottom-color: pvar(--mainColor); |
@@ -84,7 +84,7 @@ $nav-link-height: 40px; | |||
84 | border: $border-width $border-type $border-color; | 84 | border: $border-width $border-type $border-color; |
85 | border-top: transparent; | 85 | border-top: transparent; |
86 | 86 | ||
87 | background-color: pvar(--submenuColor); | 87 | background-color: pvar(--submenuBackgroundColor); |
88 | border-bottom-left-radius: 3px; | 88 | border-bottom-left-radius: 3px; |
89 | border-bottom-right-radius: 3px; | 89 | border-bottom-right-radius: 3px; |
90 | width: 100%; | 90 | width: 100%; |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comments.component.html b/client/src/app/+videos/+video-watch/comment/video-comments.component.html index 4a6426d30..9e6fde2e0 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comments.component.html +++ b/client/src/app/+videos/+video-watch/comment/video-comments.component.html | |||
@@ -1,12 +1,7 @@ | |||
1 | <div> | 1 | <div> |
2 | <div class="title-block"> | 2 | <div class="title-block"> |
3 | <h2 class="title-page title-page-single"> | 3 | <h2 class="title-page title-page-single"> |
4 | <ng-container *ngIf="totalNotDeletedComments > 0; then hasComments; else noComments"></ng-container> | 4 | {totalNotDeletedComments, plural, =0 {Comments} =1 {1 Comment} other {{{totalNotDeletedComments}} Comments}} |
5 | <ng-template #hasComments> | ||
6 | <ng-container i18n *ngIf="totalNotDeletedComments === 1; else manyComments">1 Comment</ng-container> | ||
7 | <ng-template i18n #manyComments>{{ totalNotDeletedComments }} Comments</ng-template> | ||
8 | </ng-template> | ||
9 | <ng-template i18n #noComments>Comments</ng-template> | ||
10 | </h2> | 5 | </h2> |
11 | 6 | ||
12 | <my-feed [syndicationItems]="syndicationItems"></my-feed> | 7 | <my-feed [syndicationItems]="syndicationItems"></my-feed> |
@@ -79,15 +74,17 @@ | |||
79 | <span class="glyphicon glyphicon-menu-down"></span> | 74 | <span class="glyphicon glyphicon-menu-down"></span> |
80 | 75 | ||
81 | <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container> | 76 | <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container> |
77 | |||
82 | <ng-template #hasAuthorComments> | 78 | <ng-template #hasAuthorComments> |
83 | <ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n> | 79 | <ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n> |
84 | View {{ comment.totalReplies }} replies from {{ video?.account?.displayName || 'the author' }} and others | 80 | View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}} from {{ video?.account?.displayName || 'the author' }} and others |
85 | </ng-container> | 81 | </ng-container> |
86 | <ng-template i18n #onlyAuthorComments> | 82 | <ng-template i18n #onlyAuthorComments> |
87 | View {{ comment.totalReplies }} replies from {{ video?.account?.displayName || 'the author' }} | 83 | View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}} from {{ video?.account?.displayName || 'the author' }} |
88 | </ng-template> | 84 | </ng-template> |
89 | </ng-template> | 85 | </ng-template> |
90 | <ng-template i18n #noAuthorComments>View {{ comment.totalReplies }} replies</ng-template> | 86 | |
87 | <ng-template i18n #noAuthorComments>View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}}</ng-template> | ||
91 | 88 | ||
92 | <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader> | 89 | <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader> |
93 | </div> | 90 | </div> |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comments.component.ts b/client/src/app/+videos/+video-watch/comment/video-comments.component.ts index d36dd9e34..210236b61 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comments.component.ts +++ b/client/src/app/+videos/+video-watch/comment/video-comments.component.ts | |||
@@ -5,7 +5,6 @@ import { AuthService, ComponentPagination, ConfirmService, hasMoreItems, Notifie | |||
5 | import { HooksService } from '@app/core/plugins/hooks.service' | 5 | import { HooksService } from '@app/core/plugins/hooks.service' |
6 | import { Syndication, VideoDetails } from '@app/shared/shared-main' | 6 | import { Syndication, VideoDetails } from '@app/shared/shared-main' |
7 | import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment' | 7 | import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment' |
8 | import { ThisReceiver } from '@angular/compiler' | ||
9 | 8 | ||
10 | @Component({ | 9 | @Component({ |
11 | selector: 'my-video-comments', | 10 | selector: 'my-video-comments', |
diff --git a/client/src/app/+videos/+video-watch/modal/video-support.component.html b/client/src/app/+videos/+video-watch/modal/video-support.component.html deleted file mode 100644 index 935656d23..000000000 --- a/client/src/app/+videos/+video-watch/modal/video-support.component.html +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | <ng-template #modal let-hide="close"> | ||
2 | <div class="modal-header"> | ||
3 | <h4 i18n class="modal-title">Support {{ video.account.displayName }}</h4> | ||
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | ||
5 | </div> | ||
6 | |||
7 | <div class="modal-body" [innerHTML]="videoHTMLSupport"></div> | ||
8 | |||
9 | <div class="modal-footer inputs"> | ||
10 | <input | ||
11 | type="button" role="button" i18n-value value="Maybe later" class="action-button action-button-cancel" | ||
12 | (click)="hide()" (key.enter)="hide()" | ||
13 | > | ||
14 | </div> | ||
15 | </ng-template> | ||
diff --git a/client/src/app/+videos/+video-watch/modal/video-support.component.scss b/client/src/app/+videos/+video-watch/modal/video-support.component.scss deleted file mode 100644 index 184e09027..000000000 --- a/client/src/app/+videos/+video-watch/modal/video-support.component.scss +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | .action-button-cancel { | ||
2 | margin-right: 0 !important; | ||
3 | } | ||
diff --git a/client/src/app/+videos/+video-watch/modal/video-support.component.ts b/client/src/app/+videos/+video-watch/modal/video-support.component.ts deleted file mode 100644 index bd5290a72..000000000 --- a/client/src/app/+videos/+video-watch/modal/video-support.component.ts +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | import { Component, Input, ViewChild } from '@angular/core' | ||
2 | import { MarkdownService } from '@app/core' | ||
3 | import { VideoDetails } from '@app/shared/shared-main' | ||
4 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-video-support', | ||
8 | templateUrl: './video-support.component.html', | ||
9 | styleUrls: [ './video-support.component.scss' ] | ||
10 | }) | ||
11 | export class VideoSupportComponent { | ||
12 | @Input() video: VideoDetails = null | ||
13 | |||
14 | @ViewChild('modal', { static: true }) modal: NgbModal | ||
15 | |||
16 | videoHTMLSupport = '' | ||
17 | |||
18 | constructor ( | ||
19 | private markdownService: MarkdownService, | ||
20 | private modalService: NgbModal | ||
21 | ) { } | ||
22 | |||
23 | show () { | ||
24 | const modalRef = this.modalService.open(this.modal, { centered: true }) | ||
25 | |||
26 | this.markdownService.enhancedMarkdownToHTML(this.video.support) | ||
27 | .then(r => this.videoHTMLSupport = r) | ||
28 | |||
29 | return modalRef | ||
30 | } | ||
31 | } | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html index 3c7c679b8..e0e9f92e7 100644 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html +++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="other-videos"> | 1 | <div class="other-videos" [ngClass]="{ 'display-as-row': displayAsRow }"> |
2 | <ng-container *ngIf="hasVideos$ | async"> | 2 | <ng-container *ngIf="hasVideos$ | async"> |
3 | <div class="title-page-container"> | 3 | <div class="title-page-container"> |
4 | <h2 i18n class="title-page title-page-single"> | 4 | <h2 i18n class="title-page title-page-single"> |
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count"> | 15 | <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count"> |
16 | <my-video-miniature | 16 | <my-video-miniature |
17 | [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" | 17 | [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" [displayAsRow]="displayAsRow" |
18 | (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()"> | 18 | (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()"> |
19 | </my-video-miniature> | 19 | </my-video-miniature> |
20 | 20 | ||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss index b278c9654..c9fae6f27 100644 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss +++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss | |||
@@ -1,3 +1,6 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
1 | .title-page-container { | 4 | .title-page-container { |
2 | display: flex; | 5 | display: flex; |
3 | justify-content: space-between; | 6 | justify-content: space-between; |
@@ -11,6 +14,10 @@ | |||
11 | } | 14 | } |
12 | } | 15 | } |
13 | 16 | ||
17 | .title-page { | ||
18 | margin-top: 0; | ||
19 | } | ||
20 | |||
14 | .title-page-autoplay { | 21 | .title-page-autoplay { |
15 | display: flex; | 22 | display: flex; |
16 | width: max-content; | 23 | width: max-content; |
@@ -29,3 +36,29 @@ | |||
29 | hr { | 36 | hr { |
30 | margin-top: 0; | 37 | margin-top: 0; |
31 | } | 38 | } |
39 | |||
40 | my-video-miniature { | ||
41 | display: block; | ||
42 | } | ||
43 | |||
44 | .other-videos:not(.display-as-row) my-video-miniature { | ||
45 | min-width: $video-thumbnail-medium-width; | ||
46 | max-width: $video-thumbnail-medium-width; | ||
47 | } | ||
48 | |||
49 | .display-as-row { | ||
50 | my-video-miniature { | ||
51 | margin-bottom: 20px; | ||
52 | } | ||
53 | |||
54 | hr { | ||
55 | display: none; | ||
56 | } | ||
57 | |||
58 | @media screen and (max-width: $mobile-view) { | ||
59 | my-video-miniature { | ||
60 | margin-bottom: 10px; | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | |||
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts index a1c8e0661..89b9c01b6 100644 --- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts +++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts | |||
@@ -16,6 +16,8 @@ import { RecommendedVideosStore } from './recommended-videos.store' | |||
16 | export class RecommendedVideosComponent implements OnInit, OnChanges { | 16 | export class RecommendedVideosComponent implements OnInit, OnChanges { |
17 | @Input() inputRecommendation: RecommendationInfo | 17 | @Input() inputRecommendation: RecommendationInfo |
18 | @Input() playlist: VideoPlaylist | 18 | @Input() playlist: VideoPlaylist |
19 | @Input() displayAsRow: boolean | ||
20 | |||
19 | @Output() gotRecommendations = new EventEmitter<Video[]>() | 21 | @Output() gotRecommendations = new EventEmitter<Video[]>() |
20 | 22 | ||
21 | autoPlayNextVideo: boolean | 23 | autoPlayNextVideo: boolean |
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.html b/client/src/app/+videos/+video-watch/video-avatar-channel.component.html new file mode 100644 index 000000000..5058f05dd --- /dev/null +++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.html | |||
@@ -0,0 +1,27 @@ | |||
1 | <div class="wrapper" [ngClass]="'avatar-' + size"> | ||
2 | <ng-container *ngIf="!isChannelAvatarNull() && !genericChannel"> | ||
3 | <a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle"> | ||
4 | <img [src]="video.videoChannelAvatarUrl" i18n-alt alt="Channel avatar" class="channel-avatar" /> | ||
5 | </a> | ||
6 | |||
7 | <a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle"> | ||
8 | <img [src]="video.accountAvatarUrl" i18n-alt alt="Account avatar" /> | ||
9 | </a> | ||
10 | </ng-container> | ||
11 | |||
12 | <ng-container *ngIf="!isChannelAvatarNull() && genericChannel"> | ||
13 | <a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle"> | ||
14 | <img [src]="video.accountAvatarUrl" i18n-alt alt="Account avatar" /> | ||
15 | </a> | ||
16 | |||
17 | <a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle"> | ||
18 | <img [src]="video.videoChannelAvatarUrl" i18n-alt alt="Channel avatar" class="channel-avatar" /> | ||
19 | </a> | ||
20 | </ng-container> | ||
21 | |||
22 | <ng-container *ngIf="isChannelAvatarNull()"> | ||
23 | <a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle"> | ||
24 | <img [src]="video.accountAvatarUrl" i18n-alt alt="Account avatar" /> | ||
25 | </a> | ||
26 | </ng-container> | ||
27 | </div> | ||
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss b/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss new file mode 100644 index 000000000..4998e85fa --- /dev/null +++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss | |||
@@ -0,0 +1,44 @@ | |||
1 | @import '_mixins'; | ||
2 | |||
3 | .wrapper { | ||
4 | $avatar-size: 35px; | ||
5 | |||
6 | width: $avatar-size; | ||
7 | height: $avatar-size; | ||
8 | position: relative; | ||
9 | margin-right: 5px; | ||
10 | margin-bottom: 5px; | ||
11 | |||
12 | &.avatar-sm { | ||
13 | width: 28px; | ||
14 | height: 28px; | ||
15 | margin-bottom: 3px; | ||
16 | } | ||
17 | |||
18 | a { | ||
19 | @include disable-outline; | ||
20 | } | ||
21 | |||
22 | a img { | ||
23 | height: 100%; | ||
24 | object-fit: cover; | ||
25 | position: absolute; | ||
26 | top:50%; | ||
27 | left:50%; | ||
28 | transform: translate(-50%,-50%); | ||
29 | border-radius: 5px; | ||
30 | |||
31 | &:not(.channel-avatar) { | ||
32 | border-radius: 50%; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | a:nth-of-type(2) img { | ||
37 | height: 60%; | ||
38 | width: 60%; | ||
39 | border: 2px solid pvar(--mainBackgroundColor); | ||
40 | transform: translateX(15%); | ||
41 | position: relative; | ||
42 | background-color: pvar(--mainBackgroundColor); | ||
43 | } | ||
44 | } | ||
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts b/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts new file mode 100644 index 000000000..0b6e796df --- /dev/null +++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import { Component, Input, OnInit } from '@angular/core' | ||
2 | import { Video } from '@app/shared/shared-main/video' | ||
3 | |||
4 | @Component({ | ||
5 | selector: 'my-video-avatar-channel', | ||
6 | templateUrl: './video-avatar-channel.component.html', | ||
7 | styleUrls: [ './video-avatar-channel.component.scss' ] | ||
8 | }) | ||
9 | export class VideoAvatarChannelComponent implements OnInit { | ||
10 | @Input() video: Video | ||
11 | @Input() byAccount: string | ||
12 | |||
13 | @Input() size: 'md' | 'sm' = 'md' | ||
14 | @Input() genericChannel: boolean | ||
15 | |||
16 | channelLinkTitle = '' | ||
17 | accountLinkTitle = '' | ||
18 | |||
19 | ngOnInit () { | ||
20 | this.channelLinkTitle = $localize`${this.video.account.name} (channel page)` | ||
21 | this.accountLinkTitle = $localize`${this.video.byAccount} (account page)` | ||
22 | } | ||
23 | |||
24 | isChannelAvatarNull () { | ||
25 | return this.video.channel.avatar === null | ||
26 | } | ||
27 | } | ||
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 b17f898ce..99103c2c3 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.html +++ b/client/src/app/+videos/+video-watch/video-watch.component.html | |||
@@ -142,7 +142,7 @@ | |||
142 | <ng-container *ngIf="isUserLoggedIn()"> | 142 | <ng-container *ngIf="isUserLoggedIn()"> |
143 | <my-video-actions-dropdown | 143 | <my-video-actions-dropdown |
144 | placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions" | 144 | placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions" |
145 | [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()" (modalOpened)="onModalOpened()" | 145 | [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()" |
146 | ></my-video-actions-dropdown> | 146 | ></my-video-actions-dropdown> |
147 | </ng-container> | 147 | </ng-container> |
148 | </div> | 148 | </div> |
@@ -289,6 +289,7 @@ | |||
289 | </div> | 289 | </div> |
290 | 290 | ||
291 | <my-recommended-videos | 291 | <my-recommended-videos |
292 | [displayAsRow]="displayOtherVideosAsRow()" | ||
292 | [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }" | 293 | [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }" |
293 | [playlist]="playlist" | 294 | [playlist]="playlist" |
294 | (gotRecommendations)="onRecommendations($event)" | 295 | (gotRecommendations)="onRecommendations($event)" |
@@ -313,6 +314,6 @@ | |||
313 | </div> | 314 | </div> |
314 | 315 | ||
315 | <ng-container *ngIf="video !== null"> | 316 | <ng-container *ngIf="video !== null"> |
316 | <my-video-support #videoSupportModal [video]="video"></my-video-support> | 317 | <my-support-modal #supportModal [video]="video"></my-support-modal> |
317 | <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share> | 318 | <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share> |
318 | </ng-container> | 319 | </ng-container> |
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 555126cbc..2e566e3fb 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.scss +++ b/client/src/app/+videos/+video-watch/video-watch.component.scss | |||
@@ -3,7 +3,7 @@ | |||
3 | @import '_bootstrap-variables'; | 3 | @import '_bootstrap-variables'; |
4 | @import '_miniature'; | 4 | @import '_miniature'; |
5 | 5 | ||
6 | $player-factor: 1.7; // 16/9 | 6 | $player-factor: #{16/9}; |
7 | $video-info-margin-left: 44px; | 7 | $video-info-margin-left: 44px; |
8 | 8 | ||
9 | @function getPlayerHeight($width){ | 9 | @function getPlayerHeight($width){ |
@@ -179,12 +179,6 @@ $video-info-margin-left: 44px; | |||
179 | &:hover { | 179 | &:hover { |
180 | opacity: 0.8; | 180 | opacity: 0.8; |
181 | } | 181 | } |
182 | |||
183 | img { | ||
184 | @include avatar(18px); | ||
185 | |||
186 | margin: -2px 5px 0 0; | ||
187 | } | ||
188 | } | 182 | } |
189 | 183 | ||
190 | .video-info-channel-left { | 184 | .video-info-channel-left { |
@@ -413,37 +407,12 @@ $video-info-margin-left: 44px; | |||
413 | } | 407 | } |
414 | } | 408 | } |
415 | } | 409 | } |
410 | } | ||
416 | 411 | ||
417 | ::ng-deep .other-videos { | 412 | my-recommended-videos { |
418 | padding-left: 15px; | 413 | display: block; |
419 | min-width: $video-miniature-width; | 414 | padding-left: 15px; |
420 | 415 | min-width: 250px; | |
421 | @media screen and (min-width: 1800px - (3* $video-miniature-width)) { | ||
422 | width: min-content; | ||
423 | } | ||
424 | |||
425 | .title-page { | ||
426 | margin: 0 !important; | ||
427 | } | ||
428 | |||
429 | .video-miniature { | ||
430 | display: flex; | ||
431 | width: max-content; | ||
432 | height: 100%; | ||
433 | padding-bottom: 20px; | ||
434 | flex-wrap: wrap; | ||
435 | } | ||
436 | |||
437 | .video-bottom { | ||
438 | @media screen and (max-width: 1800px - (3* $video-miniature-width)) { | ||
439 | margin-left: 1rem; | ||
440 | } | ||
441 | @media screen and (max-width: 500px) { | ||
442 | margin-left: 0; | ||
443 | margin-top: .5rem; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | } | 416 | } |
448 | 417 | ||
449 | my-video-comments { | 418 | my-video-comments { |
@@ -537,6 +506,7 @@ my-video-comments { | |||
537 | } | 506 | } |
538 | } | 507 | } |
539 | 508 | ||
509 | // Use the same breakpoint than in the typescript component to display the other video miniatures as row | ||
540 | @media screen and (max-width: 1100px) { | 510 | @media screen and (max-width: 1100px) { |
541 | #video-wrapper { | 511 | #video-wrapper { |
542 | flex-direction: column; | 512 | flex-direction: column; |
@@ -549,15 +519,10 @@ my-video-comments { | |||
549 | 519 | ||
550 | .video-bottom { | 520 | .video-bottom { |
551 | flex-direction: column; | 521 | flex-direction: column; |
522 | } | ||
552 | 523 | ||
553 | ::ng-deep .other-videos { | 524 | my-recommended-videos { |
554 | padding-left: 0 !important; | 525 | padding-left: 0; |
555 | |||
556 | ::ng-deep .video-miniature { | ||
557 | flex-direction: row; | ||
558 | width: auto; | ||
559 | } | ||
560 | } | ||
561 | } | 526 | } |
562 | } | 527 | } |
563 | 528 | ||
@@ -579,10 +544,6 @@ my-video-comments { | |||
579 | } | 544 | } |
580 | } | 545 | } |
581 | 546 | ||
582 | ::ng-deep .other-videos .video-miniature { | ||
583 | flex-direction: column; | ||
584 | } | ||
585 | |||
586 | .privacy-concerns { | 547 | .privacy-concerns { |
587 | width: 100%; | 548 | width: 100%; |
588 | } | 549 | } |
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 7a98cab3b..de5fb4ed0 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts | |||
@@ -21,6 +21,7 @@ import { RedirectService } from '@app/core/routing/redirect.service' | |||
21 | import { isXPercentInViewport, scrollToTop } from '@app/helpers' | 21 | import { isXPercentInViewport, scrollToTop } from '@app/helpers' |
22 | import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main' | 22 | import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main' |
23 | import { VideoShareComponent } from '@app/shared/shared-share-modal' | 23 | import { VideoShareComponent } from '@app/shared/shared-share-modal' |
24 | import { SupportModalComponent } from '@app/shared/shared-support-modal' | ||
24 | import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' | 25 | import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' |
25 | import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature' | 26 | import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature' |
26 | import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' | 27 | import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' |
@@ -28,7 +29,12 @@ import { MetaService } from '@ngx-meta/core' | |||
28 | import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' | 29 | import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' |
29 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | 30 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
30 | import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' | 31 | import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' |
31 | import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage' | 32 | import { |
33 | cleanupVideoWatch, | ||
34 | getStoredP2PEnabled, | ||
35 | getStoredTheater, | ||
36 | getStoredVideoWatchHistory | ||
37 | } from '../../../assets/player/peertube-player-local-storage' | ||
32 | import { | 38 | import { |
33 | CustomizationOptions, | 39 | CustomizationOptions, |
34 | P2PMediaLoaderOptions, | 40 | P2PMediaLoaderOptions, |
@@ -39,7 +45,6 @@ import { | |||
39 | } from '../../../assets/player/peertube-player-manager' | 45 | } from '../../../assets/player/peertube-player-manager' |
40 | import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils' | 46 | import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils' |
41 | import { environment } from '../../../environments/environment' | 47 | import { environment } from '../../../environments/environment' |
42 | import { VideoSupportComponent } from './modal/video-support.component' | ||
43 | import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' | 48 | import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' |
44 | 49 | ||
45 | type URLOptions = CustomizationOptions & { playerMode: PlayerMode } | 50 | type URLOptions = CustomizationOptions & { playerMode: PlayerMode } |
@@ -54,7 +59,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
54 | 59 | ||
55 | @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent | 60 | @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent |
56 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent | 61 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent |
57 | @ViewChild('videoSupportModal') videoSupportModal: VideoSupportComponent | 62 | @ViewChild('supportModal') supportModal: SupportModalComponent |
58 | @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent | 63 | @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent |
59 | @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent | 64 | @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent |
60 | 65 | ||
@@ -195,6 +200,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
195 | this.theaterEnabled = getStoredTheater() | 200 | this.theaterEnabled = getStoredTheater() |
196 | 201 | ||
197 | this.hooks.runAction('action:video-watch.init', 'video-watch') | 202 | this.hooks.runAction('action:video-watch.init', 'video-watch') |
203 | |||
204 | setTimeout(cleanupVideoWatch, 1500) // Run in timeout to ensure we're not blocking the UI | ||
198 | } | 205 | } |
199 | 206 | ||
200 | ngOnDestroy () { | 207 | ngOnDestroy () { |
@@ -277,23 +284,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
277 | } | 284 | } |
278 | 285 | ||
279 | showSupportModal () { | 286 | showSupportModal () { |
280 | // Check video was playing before opening support modal | 287 | this.supportModal.show() |
281 | const isVideoPlaying = this.isPlaying() | ||
282 | |||
283 | this.pausePlayer() | ||
284 | |||
285 | const modalRef = this.videoSupportModal.show() | ||
286 | |||
287 | modalRef.result.then(() => { | ||
288 | if (isVideoPlaying) { | ||
289 | this.resumePlayer() | ||
290 | } | ||
291 | }) | ||
292 | } | 288 | } |
293 | 289 | ||
294 | showShareModal () { | 290 | showShareModal () { |
295 | this.pausePlayer() | ||
296 | |||
297 | this.videoShareModal.show(this.currentTime, this.videoWatchPlaylist.currentPlaylistPosition) | 291 | this.videoShareModal.show(this.currentTime, this.videoWatchPlaylist.currentPlaylistPosition) |
298 | } | 292 | } |
299 | 293 | ||
@@ -316,10 +310,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
316 | } | 310 | } |
317 | } | 311 | } |
318 | 312 | ||
319 | onModalOpened () { | ||
320 | this.pausePlayer() | ||
321 | } | ||
322 | |||
323 | onVideoRemoved () { | 313 | onVideoRemoved () { |
324 | this.redirectService.redirectToHomepage() | 314 | this.redirectService.redirectToHomepage() |
325 | } | 315 | } |
@@ -396,6 +386,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
396 | this.loadVideo(videoId) | 386 | this.loadVideo(videoId) |
397 | } | 387 | } |
398 | 388 | ||
389 | displayOtherVideosAsRow () { | ||
390 | // Use the same value as in the SASS file | ||
391 | return this.screenService.getWindowInnerWidth() <= 1100 | ||
392 | } | ||
393 | |||
399 | private loadVideo (videoId: string) { | 394 | private loadVideo (videoId: string) { |
400 | // Video did not change | 395 | // Video did not change |
401 | if (this.video && this.video.uuid === videoId) return | 396 | if (this.video && this.video.uuid === videoId) return |
@@ -768,9 +763,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
768 | const getStartTime = () => { | 763 | const getStartTime = () => { |
769 | const byUrl = urlOptions.startTime !== undefined | 764 | const byUrl = urlOptions.startTime !== undefined |
770 | const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined) | 765 | const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined) |
766 | const byLocalStorage = getStoredVideoWatchHistory(video.uuid) | ||
771 | 767 | ||
772 | if (byUrl) return timeToInt(urlOptions.startTime) | 768 | if (byUrl) return timeToInt(urlOptions.startTime) |
773 | if (byHistory) return video.userHistory.currentTime | 769 | if (byHistory) return video.userHistory.currentTime |
770 | if (byLocalStorage) return byLocalStorage.duration | ||
774 | 771 | ||
775 | return 0 | 772 | return 0 |
776 | } | 773 | } |
@@ -815,6 +812,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
815 | ? this.videoService.getVideoViewUrl(video.uuid) | 812 | ? this.videoService.getVideoViewUrl(video.uuid) |
816 | : null, | 813 | : null, |
817 | embedUrl: video.embedUrl, | 814 | embedUrl: video.embedUrl, |
815 | embedTitle: video.name, | ||
818 | 816 | ||
819 | isLive: video.isLive, | 817 | isLive: video.isLive, |
820 | 818 | ||
@@ -827,7 +825,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
827 | 825 | ||
828 | serverUrl: environment.apiUrl, | 826 | serverUrl: environment.apiUrl, |
829 | 827 | ||
830 | videoCaptions: playerCaptions | 828 | videoCaptions: playerCaptions, |
829 | |||
830 | videoUUID: video.uuid | ||
831 | }, | 831 | }, |
832 | 832 | ||
833 | webtorrent: { | 833 | webtorrent: { |
@@ -867,24 +867,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
867 | return { playerMode: mode, playerOptions: options } | 867 | return { playerMode: mode, playerOptions: options } |
868 | } | 868 | } |
869 | 869 | ||
870 | private pausePlayer () { | ||
871 | if (!this.player) return | ||
872 | |||
873 | this.player.pause() | ||
874 | } | ||
875 | |||
876 | private resumePlayer () { | ||
877 | if (!this.player) return | ||
878 | |||
879 | this.player.play() | ||
880 | } | ||
881 | |||
882 | private isPlaying () { | ||
883 | if (!this.player) return | ||
884 | |||
885 | return !this.player.paused() | ||
886 | } | ||
887 | |||
888 | private async subscribeToLiveEventsIfNeeded (oldVideo: VideoDetails, newVideo: VideoDetails) { | 870 | private async subscribeToLiveEventsIfNeeded (oldVideo: VideoDetails, newVideo: VideoDetails) { |
889 | if (!this.liveVideosSub) { | 871 | if (!this.liveVideosSub) { |
890 | this.liveVideosSub = this.buildLiveEventsSubscription() | 872 | this.liveVideosSub = this.buildLiveEventsSubscription() |
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 fbda9b9c4..3e9f3822e 100644 --- a/client/src/app/+videos/+video-watch/video-watch.module.ts +++ b/client/src/app/+videos/+video-watch/video-watch.module.ts | |||
@@ -4,6 +4,7 @@ import { SharedGlobalIconModule } from '@app/shared/shared-icons' | |||
4 | import { SharedMainModule } from '@app/shared/shared-main' | 4 | import { SharedMainModule } from '@app/shared/shared-main' |
5 | import { SharedModerationModule } from '@app/shared/shared-moderation' | 5 | import { SharedModerationModule } from '@app/shared/shared-moderation' |
6 | import { SharedShareModal } from '@app/shared/shared-share-modal' | 6 | import { SharedShareModal } from '@app/shared/shared-share-modal' |
7 | import { SharedSupportModal } from '@app/shared/shared-support-modal' | ||
7 | import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' | 8 | import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' |
8 | import { SharedVideoModule } from '@app/shared/shared-video' | 9 | import { SharedVideoModule } from '@app/shared/shared-video' |
9 | import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' | 10 | import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' |
@@ -13,9 +14,9 @@ import { VideoCommentService } from '../../shared/shared-video-comment/video-com | |||
13 | import { VideoCommentAddComponent } from './comment/video-comment-add.component' | 14 | import { VideoCommentAddComponent } from './comment/video-comment-add.component' |
14 | import { VideoCommentComponent } from './comment/video-comment.component' | 15 | import { VideoCommentComponent } from './comment/video-comment.component' |
15 | import { VideoCommentsComponent } from './comment/video-comments.component' | 16 | import { VideoCommentsComponent } from './comment/video-comments.component' |
16 | import { VideoSupportComponent } from './modal/video-support.component' | ||
17 | import { RecommendationsModule } from './recommendations/recommendations.module' | 17 | import { RecommendationsModule } from './recommendations/recommendations.module' |
18 | import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive' | 18 | import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive' |
19 | import { VideoAvatarChannelComponent } from './video-avatar-channel.component' | ||
19 | import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' | 20 | import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' |
20 | import { VideoWatchRoutingModule } from './video-watch-routing.module' | 21 | import { VideoWatchRoutingModule } from './video-watch-routing.module' |
21 | import { VideoWatchComponent } from './video-watch.component' | 22 | import { VideoWatchComponent } from './video-watch.component' |
@@ -34,18 +35,20 @@ import { VideoWatchComponent } from './video-watch.component' | |||
34 | SharedGlobalIconModule, | 35 | SharedGlobalIconModule, |
35 | SharedVideoCommentModule, | 36 | SharedVideoCommentModule, |
36 | SharedShareModal, | 37 | SharedShareModal, |
37 | SharedVideoModule | 38 | SharedVideoModule, |
39 | SharedSupportModal | ||
38 | ], | 40 | ], |
39 | 41 | ||
40 | declarations: [ | 42 | declarations: [ |
41 | VideoWatchComponent, | 43 | VideoWatchComponent, |
42 | VideoWatchPlaylistComponent, | 44 | VideoWatchPlaylistComponent, |
43 | 45 | ||
44 | VideoSupportComponent, | ||
45 | VideoCommentsComponent, | 46 | VideoCommentsComponent, |
46 | VideoCommentAddComponent, | 47 | VideoCommentAddComponent, |
47 | VideoCommentComponent, | 48 | VideoCommentComponent, |
48 | 49 | ||
50 | VideoAvatarChannelComponent, | ||
51 | |||
49 | TimestampRouteTransformerDirective, | 52 | TimestampRouteTransformerDirective, |
50 | TimestampRouteTransformerDirective | 53 | TimestampRouteTransformerDirective |
51 | ], | 54 | ], |
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.html b/client/src/app/+videos/video-list/overview/video-overview.component.html index ca986c634..639a96c43 100644 --- a/client/src/app/+videos/video-list/overview/video-overview.component.html +++ b/client/src/app/+videos/video-list/overview/video-overview.component.html | |||
@@ -14,7 +14,7 @@ | |||
14 | </h1> | 14 | </h1> |
15 | 15 | ||
16 | <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> | 16 | <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> |
17 | <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="true"> | 17 | <my-video-miniature [video]="video" [user]="userMiniature" [displayVideoActions]="true"> |
18 | </my-video-miniature> | 18 | </my-video-miniature> |
19 | </div> | 19 | </div> |
20 | </div> | 20 | </div> |
@@ -25,7 +25,7 @@ | |||
25 | </h2> | 25 | </h2> |
26 | 26 | ||
27 | <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> | 27 | <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> |
28 | <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="true"> | 28 | <my-video-miniature [video]="video" [user]="userMiniature" [displayVideoActions]="true"> |
29 | </my-video-miniature> | 29 | </my-video-miniature> |
30 | </div> | 30 | </div> |
31 | </div> | 31 | </div> |
@@ -40,7 +40,7 @@ | |||
40 | </div> | 40 | </div> |
41 | 41 | ||
42 | <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> | 42 | <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> |
43 | <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="true"> | 43 | <my-video-miniature [video]="video" [user]="userMiniature" [displayVideoActions]="true"> |
44 | </my-video-miniature> | 44 | </my-video-miniature> |
45 | </div> | 45 | </div> |
46 | </div> | 46 | </div> |
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.scss b/client/src/app/+videos/video-list/overview/video-overview.component.scss index c1d10188a..ec73c628c 100644 --- a/client/src/app/+videos/video-list/overview/video-overview.component.scss +++ b/client/src/app/+videos/video-list/overview/video-overview.component.scss | |||
@@ -8,9 +8,84 @@ | |||
8 | } | 8 | } |
9 | 9 | ||
10 | .margin-content { | 10 | .margin-content { |
11 | @include fluid-videos-miniature-layout; | 11 | @include grid-videos-miniature-layout; |
12 | } | 12 | } |
13 | 13 | ||
14 | .section { | 14 | .section { |
15 | @include miniature-rows; | 15 | &:first-child { |
16 | padding-top: 30px; | ||
17 | |||
18 | .section-title { | ||
19 | border-top: none !important; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | .section-title { | ||
24 | font-size: 24px; | ||
25 | font-weight: $font-semibold; | ||
26 | padding-top: 15px; | ||
27 | margin-bottom: 15px; | ||
28 | display: flex; | ||
29 | justify-content: space-between; | ||
30 | |||
31 | &:not(h2) { | ||
32 | border-top: 1px solid $separator-border-color; | ||
33 | } | ||
34 | |||
35 | a { | ||
36 | &:hover, &:focus:not(.focus-visible), &:active { | ||
37 | text-decoration: none; | ||
38 | outline: none; | ||
39 | } | ||
40 | |||
41 | color: pvar(--mainForegroundColor); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | &.channel { | ||
46 | .section-title { | ||
47 | a { | ||
48 | display: flex; | ||
49 | width: fit-content; | ||
50 | align-items: center; | ||
51 | |||
52 | img { | ||
53 | @include channel-avatar(28px); | ||
54 | |||
55 | margin-right: 8px; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | .followers { | ||
60 | color: pvar(--greyForegroundColor); | ||
61 | font-weight: normal; | ||
62 | font-size: 14px; | ||
63 | margin-left: 10px; | ||
64 | position: relative; | ||
65 | top: 2px; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | .show-more { | ||
71 | position: relative; | ||
72 | top: -5px; | ||
73 | display: inline-block; | ||
74 | font-size: 16px; | ||
75 | text-transform: uppercase; | ||
76 | color: pvar(--greyForegroundColor); | ||
77 | margin-bottom: 10px; | ||
78 | font-weight: $font-semibold; | ||
79 | text-decoration: none; | ||
80 | } | ||
81 | |||
82 | @media screen and (max-width: $mobile-view) { | ||
83 | max-height: initial; | ||
84 | overflow: initial; | ||
85 | |||
86 | .section-title { | ||
87 | font-size: 17px; | ||
88 | margin-left: 10px; | ||
89 | } | ||
90 | } | ||
16 | } | 91 | } |
diff --git a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts index e352a2b2c..6aabb93a5 100644 --- a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts +++ b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts | |||
@@ -7,7 +7,7 @@ import { HooksService } from '@app/core/plugins/hooks.service' | |||
7 | import { immutableAssign } from '@app/helpers' | 7 | import { immutableAssign } from '@app/helpers' |
8 | import { VideoService } from '@app/shared/shared-main' | 8 | import { VideoService } from '@app/shared/shared-main' |
9 | import { UserSubscriptionService } from '@app/shared/shared-user-subscription' | 9 | import { UserSubscriptionService } from '@app/shared/shared-user-subscription' |
10 | import { AbstractVideoList, OwnerDisplayType } from '@app/shared/shared-video-miniature' | 10 | import { AbstractVideoList } from '@app/shared/shared-video-miniature' |
11 | import { FeedFormat, VideoSortField } from '@shared/models' | 11 | import { FeedFormat, VideoSortField } from '@shared/models' |
12 | import { environment } from '../../../environments/environment' | 12 | import { environment } from '../../../environments/environment' |
13 | import { copyToClipboard } from '../../../root-helpers/utils' | 13 | import { copyToClipboard } from '../../../root-helpers/utils' |
@@ -20,7 +20,6 @@ import { copyToClipboard } from '../../../root-helpers/utils' | |||
20 | export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy { | 20 | export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy { |
21 | titlePage: string | 21 | titlePage: string |
22 | sort = '-publishedAt' as VideoSortField | 22 | sort = '-publishedAt' as VideoSortField |
23 | ownerDisplayType: OwnerDisplayType = 'auto' | ||
24 | groupByDate = true | 23 | groupByDate = true |
25 | 24 | ||
26 | constructor ( | 25 | constructor ( |