aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/my-account/my-account-videos
diff options
context:
space:
mode:
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.html45
-rw-r--r--client/src/app/my-account/my-account-videos/my-account-videos.component.scss114
-rw-r--r--client/src/app/my-account/my-account-videos/my-account-videos.component.ts133
3 files changed, 292 insertions, 0 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
new file mode 100644
index 000000000..66ce3a77b
--- /dev/null
+++ b/client/src/app/my-account/my-account-videos/my-account-videos.component.html
@@ -0,0 +1,45 @@
1<div *ngIf="pagination.totalItems === 0">No results.</div>
2
3<div
4 myInfiniteScroller
5 [pageHeight]="pageHeight"
6 (nearOfTop)="onNearOfTop()" (nearOfBottom)="onNearOfBottom()" (pageChanged)="onPageChanged($event)"
7 class="videos" #videosElement
8>
9 <div *ngFor="let videos of videoPages; let i = index" class="videos-page">
10 <div class="video" *ngFor="let video of videos; let j = index">
11 <div class="checkbox-container">
12 <input [id]="'video-check-' + video.id" type="checkbox" [(ngModel)]="checkedVideos[video.id]" />
13 <label [for]="'video-check-' + video.id"></label>
14 </div>
15
16 <my-video-thumbnail [video]="video"></my-video-thumbnail>
17
18 <div class="video-info">
19 <a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
20 <span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
21 <div class="video-info-private">{{ video.privacy.label }}</div>
22 </div>
23
24 <!-- Display only once -->
25 <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0 && j === 0">
26 <div class="action-selection-mode-child">
27 <span class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
28 Cancel
29 </span>
30
31 <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
32 <span class="icon icon-delete-white"></span>
33 Delete
34 </span>
35 </div>
36 </div>
37
38 <div class="video-buttons" *ngIf="isInSelectionMode() === false">
39 <my-delete-button (click)="deleteVideo(video)"></my-delete-button>
40
41 <my-edit-button [routerLink]="[ '/videos', 'edit', video.uuid ]"></my-edit-button>
42 </div>
43 </div>
44 </div>
45</div>
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
new file mode 100644
index 000000000..f276ea389
--- /dev/null
+++ b/client/src/app/my-account/my-account-videos/my-account-videos.component.scss
@@ -0,0 +1,114 @@
1@import '_variables';
2@import '_mixins';
3
4.action-selection-mode {
5 width: 174px;
6 display: flex;
7 justify-content: flex-end;
8
9 .action-selection-mode-child {
10 position: fixed;
11
12 .action-button {
13 display: inline-block;
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 }
27
28 .icon.icon-delete-white {
29 @include icon(21px);
30
31 position: relative;
32 top: -2px;
33 background-image: url('../../../assets/images/global/delete-white.svg');
34 }
35 }
36}
37
38/deep/ .action-button {
39 &.action-button-delete {
40 margin-right: 10px;
41 }
42}
43
44.video {
45 display: flex;
46 min-height: 130px;
47 padding-bottom: 20px;
48 margin-bottom: 20px;
49 border-bottom: 1px solid #C6C6C6;
50
51 &:first-child {
52 margin-top: 47px;
53 }
54
55 .checkbox-container {
56 display: flex;
57 align-items: center;
58 margin-right: 20px;
59 margin-left: 12px;
60
61 input[type=checkbox] {
62 @include peertube-checkbox(2px);
63 }
64 }
65
66 my-video-thumbnail {
67 margin-right: 10px;
68 }
69
70 .video-info {
71 flex-grow: 1;
72
73 .video-info-name {
74 @include disable-default-a-behaviour;
75
76 color: #000;
77 display: block;
78 font-size: 16px;
79 font-weight: $font-semibold;
80 }
81
82 .video-info-date-views, .video-info-private {
83 font-size: 13px;
84
85 &.video-info-private {
86 font-weight: $font-semibold;
87 }
88 }
89 }
90
91 .video-buttons {
92 min-width: 190px;
93 }
94}
95
96@media screen and (max-width: 800px) {
97 .video {
98 flex-direction: column;
99 height: auto;
100 text-align: center;
101
102 input[type=checkbox] {
103 display: none;
104 }
105
106 my-video-thumbnail {
107 margin-right: 0;
108 }
109
110 .video-buttons {
111 margin-top: 10px;
112 }
113 }
114}
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
new file mode 100644
index 000000000..a6cef361e
--- /dev/null
+++ b/client/src/app/my-account/my-account-videos/my-account-videos.component.ts
@@ -0,0 +1,133 @@
1import { Component, OnInit, OnDestroy } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { Location } from '@angular/common'
4import { immutableAssign } from '@app/shared/misc/utils'
5import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
6import { NotificationsService } from 'angular2-notifications'
7import 'rxjs/add/observable/from'
8import 'rxjs/add/operator/concatAll'
9import { Observable } from 'rxjs/Observable'
10import { AuthService } from '../../core/auth'
11import { ConfirmService } from '../../core/confirm'
12import { AbstractVideoList } from '../../shared/video/abstract-video-list'
13import { Video } from '../../shared/video/video.model'
14import { VideoService } from '../../shared/video/video.service'
15
16@Component({
17 selector: 'my-account-videos',
18 templateUrl: './my-account-videos.component.html',
19 styleUrls: [ './my-account-videos.component.scss' ]
20})
21export class MyAccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
22 titlePage = 'My videos'
23 currentRoute = '/my-account/videos'
24 checkedVideos: { [ id: number ]: boolean } = {}
25 pagination: ComponentPagination = {
26 currentPage: 1,
27 itemsPerPage: 5,
28 totalItems: null
29 }
30
31 protected baseVideoWidth = -1
32 protected baseVideoHeight = 155
33
34 constructor (protected router: Router,
35 protected route: ActivatedRoute,
36 protected authService: AuthService,
37 protected notificationsService: NotificationsService,
38 protected confirmService: ConfirmService,
39 protected location: Location,
40 private videoService: VideoService) {
41 super()
42 }
43
44 ngOnInit () {
45 super.ngOnInit()
46
47 // this.generateSyndicationList()
48 }
49
50 ngOnDestroy () {
51 super.ngOnDestroy()
52 }
53
54 abortSelectionMode () {
55 this.checkedVideos = {}
56 }
57
58 isInSelectionMode () {
59 return Object.keys(this.checkedVideos).some(k => this.checkedVideos[k] === true)
60 }
61
62 getVideosObservable (page: number) {
63 const newPagination = immutableAssign(this.pagination, { currentPage: page })
64
65 return this.videoService.getMyVideos(newPagination, this.sort)
66 }
67
68 generateSyndicationList () {
69 throw new Error('Method not implemented.')
70 }
71
72 async deleteSelectedVideos () {
73 const toDeleteVideosIds = Object.keys(this.checkedVideos)
74 .filter(k => this.checkedVideos[k] === true)
75 .map(k => parseInt(k, 10))
76
77 const res = await this.confirmService.confirm(`Do you really want to delete ${toDeleteVideosIds.length} videos?`, 'Delete')
78 if (res === false) return
79
80 const observables: Observable<any>[] = []
81 for (const videoId of toDeleteVideosIds) {
82 const o = this.videoService
83 .removeVideo(videoId)
84 .do(() => this.spliceVideosById(videoId))
85
86 observables.push(o)
87 }
88
89 Observable.from(observables)
90 .concatAll()
91 .subscribe(
92 res => {
93 this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`)
94 this.buildVideoPages()
95 },
96
97 err => this.notificationsService.error('Error', err.message)
98 )
99 }
100
101 async deleteVideo (video: Video) {
102 const res = await this.confirmService.confirm(`Do you really want to delete ${video.name}?`, 'Delete')
103 if (res === false) return
104
105 this.videoService.removeVideo(video.id)
106 .subscribe(
107 status => {
108 this.notificationsService.success('Success', `Video ${video.name} deleted.`)
109 this.spliceVideosById(video.id)
110 this.buildVideoPages()
111 },
112
113 error => this.notificationsService.error('Error', error.message)
114 )
115 }
116
117 protected buildVideoHeight () {
118 // In account videos, the video height is fixed
119 return this.baseVideoHeight
120 }
121
122 private spliceVideosById (id: number) {
123 for (const key of Object.keys(this.loadedPages)) {
124 const videos = this.loadedPages[key]
125 const index = videos.findIndex(v => v.id === id)
126
127 if (index !== -1) {
128 videos.splice(index, 1)
129 return
130 }
131 }
132 }
133}