1 import { Subject, Subscription } from 'rxjs'
2 import { CdkDragDrop } from '@angular/cdk/drag-drop'
3 import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
4 import { ActivatedRoute, Router } from '@angular/router'
5 import { ComponentPagination, ConfirmService, Notifier, ScreenService } from '@app/core'
6 import { DropdownAction } from '@app/shared/shared-main'
7 import { VideoShareComponent } from '@app/shared/shared-share-modal'
8 import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
9 import { I18n } from '@ngx-translate/i18n-polyfill'
10 import { VideoPlaylistType } from '@shared/models'
13 selector: 'my-account-video-playlist-elements',
14 templateUrl: './my-account-video-playlist-elements.component.html',
15 styleUrls: [ './my-account-video-playlist-elements.component.scss' ]
17 export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestroy {
18 @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
20 playlistElements: VideoPlaylistElement[] = []
21 playlist: VideoPlaylist
23 playlistActions: DropdownAction<VideoPlaylist>[][] = []
25 pagination: ComponentPagination = {
31 onDataSubject = new Subject<any[]>()
33 private videoPlaylistId: string | number
34 private paramsSub: Subscription
37 private notifier: Notifier,
39 private router: Router,
40 private confirmService: ConfirmService,
41 private route: ActivatedRoute,
42 private screenService: ScreenService,
43 private videoPlaylistService: VideoPlaylistService
47 this.playlistActions = [
50 label: this.i18n('Update playlist'),
52 linkBuilder: playlist => [ '/my-account', 'video-playlists', 'update', playlist.uuid ]
55 label: this.i18n('Delete playlist'),
57 handler: playlist => this.deleteVideoPlaylist(playlist)
62 this.paramsSub = this.route.params.subscribe(routeParams => {
63 this.videoPlaylistId = routeParams[ 'videoPlaylistId' ]
66 this.loadPlaylistInfo()
71 if (this.paramsSub) this.paramsSub.unsubscribe()
74 drop (event: CdkDragDrop<any>) {
75 const previousIndex = event.previousIndex
76 const newIndex = event.currentIndex
78 if (previousIndex === newIndex) return
80 const oldPosition = this.playlistElements[previousIndex].position
81 let insertAfter = this.playlistElements[newIndex].position
83 if (oldPosition > insertAfter) insertAfter--
85 const element = this.playlistElements[previousIndex]
87 this.playlistElements.splice(previousIndex, 1)
88 this.playlistElements.splice(newIndex, 0, element)
90 this.videoPlaylistService.reorderPlaylist(this.playlist.id, oldPosition, insertAfter)
93 this.reorderClientPositions()
96 err => this.notifier.error(err.message)
100 onElementRemoved (element: VideoPlaylistElement) {
101 const oldFirst = this.findFirst()
103 this.playlistElements = this.playlistElements.filter(v => v.id !== element.id)
104 this.reorderClientPositions(oldFirst)
109 if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
111 this.pagination.currentPage += 1
115 trackByFn (index: number, elem: VideoPlaylistElement) {
119 isRegularPlaylist (playlist: VideoPlaylist) {
120 return playlist?.type.id === VideoPlaylistType.REGULAR
124 this.videoShareModal.show()
127 async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) {
128 const res = await this.confirmService.confirm(
130 'Do you really want to delete {{playlistDisplayName}}?',
131 { playlistDisplayName: videoPlaylist.displayName }
135 if (res === false) return
137 this.videoPlaylistService.removeVideoPlaylist(videoPlaylist)
140 this.router.navigate([ '/my-account', 'video-playlists' ])
142 this.notifier.success(
143 this.i18n('Playlist {{playlistDisplayName}} deleted.', { playlistDisplayName: videoPlaylist.displayName })
147 error => this.notifier.error(error.message)
152 * Returns null to not have drag and drop delay.
153 * In small views, where elements are about 100% wide,
154 * we add a delay to prevent unwanted drag&drop.
156 * @see {@link https://github.com/Chocobozzz/PeerTube/issues/2078}
158 * @returns {null|number} Null for no delay, or a number in milliseconds.
160 getDragStartDelay (): null | number {
161 if (this.screenService.isInTouchScreen()) {
168 private loadElements () {
169 this.videoPlaylistService.getPlaylistVideos(this.videoPlaylistId, this.pagination)
170 .subscribe(({ total, data }) => {
171 this.playlistElements = this.playlistElements.concat(data)
172 this.pagination.totalItems = total
174 this.onDataSubject.next(data)
178 private loadPlaylistInfo () {
179 this.videoPlaylistService.getVideoPlaylist(this.videoPlaylistId)
180 .subscribe(playlist => {
181 this.playlist = playlist
185 private reorderClientPositions (first?: VideoPlaylistElement) {
186 if (this.playlistElements.length === 0) return
188 const oldFirst = first || this.findFirst()
191 for (const element of this.playlistElements) {
196 // Reload playlist thumbnail if the first element changed
197 const newFirst = this.findFirst()
198 if (oldFirst && newFirst && oldFirst.id !== newFirst.id) {
199 this.playlist.refreshThumbnail()
203 private findFirst () {
204 return this.playlistElements.find(e => e.position === 1)