aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+my-account/my-account-videos
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-04-04 10:44:18 +0200
committerChocobozzz <me@florianbigard.com>2019-04-05 10:53:08 +0200
commit693263e936763a851e3c8c020e3739def8bd4eca (patch)
tree7fd333fcf76edbc24f3daf4a78e47ff55f048b04 /client/src/app/+my-account/my-account-videos
parent9ba1d64b1ac77304d9ffb1b3432a90ea00ff3281 (diff)
downloadPeerTube-693263e936763a851e3c8c020e3739def8bd4eca.tar.gz
PeerTube-693263e936763a851e3c8c020e3739def8bd4eca.tar.zst
PeerTube-693263e936763a851e3c8c020e3739def8bd4eca.zip
Refactor videos selection components
Diffstat (limited to 'client/src/app/+my-account/my-account-videos')
-rw-r--r--client/src/app/+my-account/my-account-videos/my-account-videos.component.html63
-rw-r--r--client/src/app/+my-account/my-account-videos/my-account-videos.component.scss76
-rw-r--r--client/src/app/+my-account/my-account-videos/my-account-videos.component.ts72
3 files changed, 57 insertions, 154 deletions
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
index 3a4054de8..d7993fdc2 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
@@ -1,39 +1,30 @@
1<div i18n *ngIf="pagination.totalItems === 0">No results.</div> 1<my-videos-selection
2 [(selection)]="selection"
3 [(videosModel)]="videos"
4 [miniatureDisplayOptions]="miniatureDisplayOptions"
5 [titlePage]="titlePage"
6 [getVideosObservableFunction]="getVideosObservableFunction"
7 #videosSelection
8>
9 <ng-template ptTemplate="globalButtons">
10 <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
11 <my-global-icon iconName="delete"></my-global-icon>
12 <ng-container i18n>Delete</ng-container>
13 </span>
14 </ng-template>
15
16 <ng-template ptTemplate="rowButtons" let-video>
17 <my-delete-button (click)="deleteVideo(video)"></my-delete-button>
18
19 <my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button>
20
21 <my-button i18n-label label="Change ownership"
22 className="action-button-change-ownership"
23 icon="im-with-her"
24 (click)="changeOwnership($event, video)"
25 ></my-button>
26 </ng-template>
27</my-videos-selection>
2 28
3<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" class="videos">
4 <div class="video" *ngFor="let video of videos; let i = index">
5 <div class="checkbox-container">
6 <my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox>
7 </div>
8
9 <my-video-miniature [video]="video" [displayOptions]="miniatureDisplayOptions" [displayAsRow]="true"></my-video-miniature>
10
11 <!-- Display only once -->
12 <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
13 <div class="action-selection-mode-child">
14 <span i18n class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
15 Cancel
16 </span>
17
18 <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
19 <my-global-icon iconName="delete"></my-global-icon>
20 <ng-container i18n>Delete</ng-container>
21 </span>
22 </div>
23 </div>
24
25 <div class="video-buttons" *ngIf="isInSelectionMode() === false">
26 <my-delete-button (click)="deleteVideo(video)"></my-delete-button>
27
28 <my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button>
29
30 <my-button i18n-label label="Change ownership"
31 className="action-button-change-ownership"
32 icon="im-with-her"
33 (click)="changeOwnership($event, video)"
34 ></my-button>
35 </div>
36 </div>
37</div>
38 29
39<my-video-change-ownership #videoChangeOwnershipModal></my-video-change-ownership> 30<my-video-change-ownership #videoChangeOwnershipModal></my-video-change-ownership>
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
index 405ded3f8..87398e7c8 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
@@ -1,75 +1,19 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4.action-selection-mode { 4.action-button-delete-selection {
5 width: 174px; 5 display: inline-block;
6 display: flex;
7 justify-content: flex-end;
8 6
9 .action-selection-mode-child { 7 @include peertube-button;
10 position: fixed; 8 @include orange-button;
9 @include button-with-icon(21px);
11 10
12 .action-button { 11 my-global-icon {
13 display: inline-block; 12 @include apply-svg-color(#fff);
14 }
15
16 .action-button-cancel-selection {
17 @include peertube-button;
18 @include grey-button;
19
20 margin-right: 10px;
21 }
22
23 .action-button-delete-selection {
24 @include peertube-button;
25 @include orange-button;
26 @include button-with-icon(21px);
27
28 my-global-icon {
29 @include apply-svg-color(#fff);
30 }
31 }
32 }
33}
34
35.video {
36 @include row-blocks;
37
38 &:first-child {
39 margin-top: 47px;
40 }
41
42 .checkbox-container {
43 display: flex;
44 align-items: center;
45 margin-right: 20px;
46 margin-left: 12px;
47 }
48
49 my-video-miniature {
50 flex-grow: 1;
51 }
52
53 .video-buttons {
54 min-width: 190px;
55
56 *:not(:last-child) {
57 margin-right: 10px;
58 }
59 } 13 }
60} 14}
61 15
62@media screen and (max-width: $small-view) { 16my-delete-button,
63 .video { 17my-edit-button {
64 flex-direction: column; 18 margin-right: 10px;
65 height: auto;
66
67 .checkbox-container {
68 display: none;
69 }
70
71 .video-buttons {
72 margin-top: 10px;
73 }
74 }
75} 19}
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
index bbe86af73..5f29364a8 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
@@ -1,31 +1,33 @@
1import { concat, Observable } from 'rxjs' 1import { concat, Observable } from 'rxjs'
2import { tap, toArray } from 'rxjs/operators' 2import { tap, toArray } from 'rxjs/operators'
3import { Component, Inject, LOCALE_ID, OnDestroy, OnInit, ViewChild } from '@angular/core' 3import { Component, ViewChild } from '@angular/core'
4import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
5import { immutableAssign } from '@app/shared/misc/utils' 5import { immutableAssign } from '@app/shared/misc/utils'
6import { ComponentPagination } from '@app/shared/rest/component-pagination.model' 6import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
7import { Notifier, ServerService } from '@app/core' 7import { Notifier, ServerService } from '@app/core'
8import { AuthService } from '../../core/auth' 8import { AuthService } from '../../core/auth'
9import { ConfirmService } from '../../core/confirm' 9import { ConfirmService } from '../../core/confirm'
10import { AbstractVideoList } from '../../shared/video/abstract-video-list'
11import { Video } from '../../shared/video/video.model' 10import { Video } from '../../shared/video/video.model'
12import { VideoService } from '../../shared/video/video.service' 11import { VideoService } from '../../shared/video/video.service'
13import { I18n } from '@ngx-translate/i18n-polyfill' 12import { I18n } from '@ngx-translate/i18n-polyfill'
14import { VideoPrivacy, VideoState } from '../../../../../shared/models/videos'
15import { ScreenService } from '@app/shared/misc/screen.service' 13import { ScreenService } from '@app/shared/misc/screen.service'
16import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component' 14import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component'
17import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component' 15import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
16import { SelectionType, VideosSelectionComponent } from '@app/shared/video/videos-selection.component'
17import { VideoSortField } from '@app/shared/video/sort-field.type'
18import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
18 19
19@Component({ 20@Component({
20 selector: 'my-account-videos', 21 selector: 'my-account-videos',
21 templateUrl: './my-account-videos.component.html', 22 templateUrl: './my-account-videos.component.html',
22 styleUrls: [ './my-account-videos.component.scss' ] 23 styleUrls: [ './my-account-videos.component.scss' ]
23}) 24})
24export class MyAccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy { 25export class MyAccountVideosComponent implements DisableForReuseHook {
26 @ViewChild('videosSelection') videosSelection: VideosSelectionComponent
25 @ViewChild('videoChangeOwnershipModal') videoChangeOwnershipModal: VideoChangeOwnershipComponent 27 @ViewChild('videoChangeOwnershipModal') videoChangeOwnershipModal: VideoChangeOwnershipComponent
26 28
27 titlePage: string 29 titlePage: string
28 checkedVideos: { [ id: number ]: boolean } = {} 30 selection: SelectionType = {}
29 pagination: ComponentPagination = { 31 pagination: ComponentPagination = {
30 currentPage: 1, 32 currentPage: 1,
31 itemsPerPage: 5, 33 itemsPerPage: 5,
@@ -40,6 +42,8 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
40 state: true, 42 state: true,
41 blacklistInfo: true 43 blacklistInfo: true
42 } 44 }
45 videos: Video[] = []
46 getVideosObservableFunction = this.getVideosObservable.bind(this)
43 47
44 constructor ( 48 constructor (
45 protected router: Router, 49 protected router: Router,
@@ -50,43 +54,28 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
50 protected screenService: ScreenService, 54 protected screenService: ScreenService,
51 private i18n: I18n, 55 private i18n: I18n,
52 private confirmService: ConfirmService, 56 private confirmService: ConfirmService,
53 private videoService: VideoService, 57 private videoService: VideoService
54 @Inject(LOCALE_ID) private localeId: string
55 ) { 58 ) {
56 super()
57
58 this.titlePage = this.i18n('My videos') 59 this.titlePage = this.i18n('My videos')
59 } 60 }
60 61
61 ngOnInit () { 62 disableForReuse () {
62 super.ngOnInit() 63 this.videosSelection.disableForReuse()
63 }
64
65 ngOnDestroy () {
66 super.ngOnDestroy()
67 } 64 }
68 65
69 abortSelectionMode () { 66 enabledForReuse () {
70 this.checkedVideos = {} 67 this.videosSelection.enabledForReuse()
71 } 68 }
72 69
73 isInSelectionMode () { 70 getVideosObservable (page: number, sort: VideoSortField) {
74 return Object.keys(this.checkedVideos).some(k => this.checkedVideos[ k ] === true)
75 }
76
77 getVideosObservable (page: number) {
78 const newPagination = immutableAssign(this.pagination, { currentPage: page }) 71 const newPagination = immutableAssign(this.pagination, { currentPage: page })
79 72
80 return this.videoService.getMyVideos(newPagination, this.sort) 73 return this.videoService.getMyVideos(newPagination, sort)
81 }
82
83 generateSyndicationList () {
84 throw new Error('Method not implemented.')
85 } 74 }
86 75
87 async deleteSelectedVideos () { 76 async deleteSelectedVideos () {
88 const toDeleteVideosIds = Object.keys(this.checkedVideos) 77 const toDeleteVideosIds = Object.keys(this.selection)
89 .filter(k => this.checkedVideos[ k ] === true) 78 .filter(k => this.selection[ k ] === true)
90 .map(k => parseInt(k, 10)) 79 .map(k => parseInt(k, 10))
91 80
92 const res = await this.confirmService.confirm( 81 const res = await this.confirmService.confirm(
@@ -109,7 +98,7 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
109 () => { 98 () => {
110 this.notifier.success(this.i18n('{{deleteLength}} videos deleted.', { deleteLength: toDeleteVideosIds.length })) 99 this.notifier.success(this.i18n('{{deleteLength}} videos deleted.', { deleteLength: toDeleteVideosIds.length }))
111 100
112 this.abortSelectionMode() 101 this.selection = {}
113 }, 102 },
114 103
115 err => this.notifier.error(err.message) 104 err => this.notifier.error(err.message)
@@ -127,7 +116,7 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
127 .subscribe( 116 .subscribe(
128 () => { 117 () => {
129 this.notifier.success(this.i18n('Video {{videoName}} deleted.', { videoName: video.name })) 118 this.notifier.success(this.i18n('Video {{videoName}} deleted.', { videoName: video.name }))
130 this.reloadVideos() 119 this.removeVideoFromArray(video.id)
131 }, 120 },
132 121
133 error => this.notifier.error(error.message) 122 error => this.notifier.error(error.message)
@@ -139,27 +128,6 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
139 this.videoChangeOwnershipModal.show(video) 128 this.videoChangeOwnershipModal.show(video)
140 } 129 }
141 130
142 getStateLabel (video: Video) {
143 let suffix: string
144
145 if (video.privacy.id !== VideoPrivacy.PRIVATE && video.state.id === VideoState.PUBLISHED) {
146 suffix = this.i18n('Published')
147 } else if (video.scheduledUpdate) {
148 const updateAt = new Date(video.scheduledUpdate.updateAt.toString()).toLocaleString(this.localeId)
149 suffix = this.i18n('Publication scheduled on ') + updateAt
150 } else if (video.state.id === VideoState.TO_TRANSCODE && video.waitTranscoding === true) {
151 suffix = this.i18n('Waiting transcoding')
152 } else if (video.state.id === VideoState.TO_TRANSCODE) {
153 suffix = this.i18n('To transcode')
154 } else if (video.state.id === VideoState.TO_IMPORT) {
155 suffix = this.i18n('To import')
156 } else {
157 return ''
158 }
159
160 return ' - ' + suffix
161 }
162
163 private removeVideoFromArray (id: number) { 131 private removeVideoFromArray (id: number) {
164 this.videos = this.videos.filter(v => v.id !== id) 132 this.videos = this.videos.filter(v => v.id !== id)
165 } 133 }