Merge branch 'release/v1.3.0' into develop
[oweals/peertube.git] / client / src / app / +my-account / my-account-video-playlists / my-account-video-playlist-elements.component.ts
1 import { Component, OnDestroy, OnInit } from '@angular/core'
2 import { Notifier, ServerService } from '@app/core'
3 import { AuthService } from '../../core/auth'
4 import { ConfirmService } from '../../core/confirm'
5 import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
6 import { Video } from '@app/shared/video/video.model'
7 import { Subject, Subscription } from 'rxjs'
8 import { ActivatedRoute } from '@angular/router'
9 import { VideoService } from '@app/shared/video/video.service'
10 import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
11 import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
12 import { I18n } from '@ngx-translate/i18n-polyfill'
13 import { CdkDragDrop, CdkDragMove } from '@angular/cdk/drag-drop'
14 import { throttleTime } from 'rxjs/operators'
15
16 @Component({
17   selector: 'my-account-video-playlist-elements',
18   templateUrl: './my-account-video-playlist-elements.component.html',
19   styleUrls: [ './my-account-video-playlist-elements.component.scss' ]
20 })
21 export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestroy {
22   videos: Video[] = []
23   playlist: VideoPlaylist
24
25   pagination: ComponentPagination = {
26     currentPage: 1,
27     itemsPerPage: 30,
28     totalItems: null
29   }
30
31   private videoPlaylistId: string | number
32   private paramsSub: Subscription
33   private dragMoveSubject = new Subject<number>()
34
35   constructor (
36     private authService: AuthService,
37     private serverService: ServerService,
38     private notifier: Notifier,
39     private confirmService: ConfirmService,
40     private route: ActivatedRoute,
41     private i18n: I18n,
42     private videoService: VideoService,
43     private videoPlaylistService: VideoPlaylistService
44   ) {}
45
46   ngOnInit () {
47     this.paramsSub = this.route.params.subscribe(routeParams => {
48       this.videoPlaylistId = routeParams[ 'videoPlaylistId' ]
49       this.loadElements()
50
51       this.loadPlaylistInfo()
52     })
53
54     this.dragMoveSubject.asObservable()
55       .pipe(throttleTime(200))
56       .subscribe(y => this.checkScroll(y))
57   }
58
59   ngOnDestroy () {
60     if (this.paramsSub) this.paramsSub.unsubscribe()
61   }
62
63   drop (event: CdkDragDrop<any>) {
64     const previousIndex = event.previousIndex
65     const newIndex = event.currentIndex
66
67     if (previousIndex === newIndex) return
68
69     const oldPosition = this.videos[previousIndex].playlistElement.position
70     let insertAfter = this.videos[newIndex].playlistElement.position
71
72     if (oldPosition > insertAfter) insertAfter--
73
74     this.videoPlaylistService.reorderPlaylist(this.playlist.id, oldPosition, insertAfter)
75       .subscribe(
76         () => { /* nothing to do */ },
77
78         err => this.notifier.error(err.message)
79       )
80
81     const video = this.videos[previousIndex]
82
83     this.videos.splice(previousIndex, 1)
84     this.videos.splice(newIndex, 0, video)
85
86     this.reorderClientPositions()
87   }
88
89   onDragMove (event: CdkDragMove<any>) {
90     this.dragMoveSubject.next(event.pointerPosition.y)
91   }
92
93   checkScroll (pointerY: number) {
94     // FIXME: Uncomment when https://github.com/angular/material2/issues/14098 is fixed
95     // FIXME: Remove when https://github.com/angular/material2/issues/13588 is implemented
96     // if (pointerY < 150) {
97     //   window.scrollBy({
98     //     left: 0,
99     //     top: -20,
100     //     behavior: 'smooth'
101     //   })
102     //
103     //   return
104     // }
105     //
106     // if (window.innerHeight - pointerY <= 50) {
107     //   window.scrollBy({
108     //     left: 0,
109     //     top: 20,
110     //     behavior: 'smooth'
111     //   })
112     // }
113   }
114
115   onElementRemoved (video: Video) {
116     this.videos = this.videos.filter(v => v.id !== video.id)
117     this.reorderClientPositions()
118   }
119
120   onNearOfBottom () {
121     // Last page
122     if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
123
124     this.pagination.currentPage += 1
125     this.loadElements()
126   }
127
128   trackByFn (index: number, elem: Video) {
129     return elem.id
130   }
131
132   private loadElements () {
133     this.videoService.getPlaylistVideos(this.videoPlaylistId, this.pagination)
134         .subscribe(({ totalVideos, videos }) => {
135           this.videos = this.videos.concat(videos)
136           this.pagination.totalItems = totalVideos
137         })
138   }
139
140   private loadPlaylistInfo () {
141     this.videoPlaylistService.getVideoPlaylist(this.videoPlaylistId)
142       .subscribe(playlist => {
143         this.playlist = playlist
144       })
145   }
146
147   private reorderClientPositions () {
148     let i = 1
149
150     for (const video of this.videos) {
151       video.playlistElement.position = i
152       i++
153     }
154   }
155 }