]>
Commit | Line | Data |
---|---|---|
ad453580 | 1 | import { Subject, Subscription } from 'rxjs' |
bfbd9128 | 2 | import { CdkDragDrop } from '@angular/cdk/drag-drop' |
82f443de C |
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' | |
67ed6552 | 8 | import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist' |
82f443de C |
9 | import { I18n } from '@ngx-translate/i18n-polyfill' |
10 | import { VideoPlaylistType } from '@shared/models' | |
f0a39880 C |
11 | |
12 | @Component({ | |
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' ] | |
16 | }) | |
17 | export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestroy { | |
82f443de C |
18 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent |
19 | ||
bfbd9128 | 20 | playlistElements: VideoPlaylistElement[] = [] |
c5a1ae50 | 21 | playlist: VideoPlaylist |
f0a39880 | 22 | |
82f443de C |
23 | playlistActions: DropdownAction<VideoPlaylist>[][] = [] |
24 | ||
f0a39880 C |
25 | pagination: ComponentPagination = { |
26 | currentPage: 1, | |
ad453580 | 27 | itemsPerPage: 10, |
f0a39880 C |
28 | totalItems: null |
29 | } | |
30 | ||
ad453580 C |
31 | onDataSubject = new Subject<any[]>() |
32 | ||
f0a39880 C |
33 | private videoPlaylistId: string | number |
34 | private paramsSub: Subscription | |
35 | ||
36 | constructor ( | |
f0a39880 | 37 | private notifier: Notifier, |
82f443de C |
38 | private i18n: I18n, |
39 | private router: Router, | |
40 | private confirmService: ConfirmService, | |
f0a39880 | 41 | private route: ActivatedRoute, |
0c695c5c | 42 | private screenService: ScreenService, |
c5a1ae50 | 43 | private videoPlaylistService: VideoPlaylistService |
f0a39880 C |
44 | ) {} |
45 | ||
46 | ngOnInit () { | |
82f443de C |
47 | this.playlistActions = [ |
48 | [ | |
49 | { | |
50 | label: this.i18n('Update playlist'), | |
51 | iconName: 'edit', | |
52 | linkBuilder: playlist => [ '/my-account', 'video-playlists', 'update', playlist.uuid ] | |
53 | }, | |
54 | { | |
55 | label: this.i18n('Delete playlist'), | |
56 | iconName: 'delete', | |
57 | handler: playlist => this.deleteVideoPlaylist(playlist) | |
58 | } | |
59 | ] | |
60 | ] | |
61 | ||
f0a39880 C |
62 | this.paramsSub = this.route.params.subscribe(routeParams => { |
63 | this.videoPlaylistId = routeParams[ 'videoPlaylistId' ] | |
64 | this.loadElements() | |
c5a1ae50 C |
65 | |
66 | this.loadPlaylistInfo() | |
f0a39880 C |
67 | }) |
68 | } | |
69 | ||
70 | ngOnDestroy () { | |
71 | if (this.paramsSub) this.paramsSub.unsubscribe() | |
72 | } | |
73 | ||
15e9d5ca C |
74 | drop (event: CdkDragDrop<any>) { |
75 | const previousIndex = event.previousIndex | |
76 | const newIndex = event.currentIndex | |
77 | ||
78 | if (previousIndex === newIndex) return | |
79 | ||
bfbd9128 C |
80 | const oldPosition = this.playlistElements[previousIndex].position |
81 | let insertAfter = this.playlistElements[newIndex].position | |
b767c4a7 C |
82 | |
83 | if (oldPosition > insertAfter) insertAfter-- | |
15e9d5ca | 84 | |
bfbd9128 | 85 | const element = this.playlistElements[previousIndex] |
15e9d5ca | 86 | |
bfbd9128 C |
87 | this.playlistElements.splice(previousIndex, 1) |
88 | this.playlistElements.splice(newIndex, 0, element) | |
15e9d5ca | 89 | |
65af03a2 C |
90 | this.videoPlaylistService.reorderPlaylist(this.playlist.id, oldPosition, insertAfter) |
91 | .subscribe( | |
92 | () => { | |
93 | this.reorderClientPositions() | |
94 | }, | |
95 | ||
96 | err => this.notifier.error(err.message) | |
97 | ) | |
15e9d5ca C |
98 | } |
99 | ||
bfbd9128 | 100 | onElementRemoved (element: VideoPlaylistElement) { |
65af03a2 C |
101 | const oldFirst = this.findFirst() |
102 | ||
bfbd9128 | 103 | this.playlistElements = this.playlistElements.filter(v => v.id !== element.id) |
65af03a2 | 104 | this.reorderClientPositions(oldFirst) |
c5a1ae50 C |
105 | } |
106 | ||
f0a39880 C |
107 | onNearOfBottom () { |
108 | // Last page | |
109 | if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return | |
110 | ||
111 | this.pagination.currentPage += 1 | |
112 | this.loadElements() | |
113 | } | |
114 | ||
bfbd9128 | 115 | trackByFn (index: number, elem: VideoPlaylistElement) { |
bce47964 C |
116 | return elem.id |
117 | } | |
118 | ||
82f443de C |
119 | isRegularPlaylist (playlist: VideoPlaylist) { |
120 | return playlist?.type.id === VideoPlaylistType.REGULAR | |
121 | } | |
122 | ||
123 | showShareModal () { | |
124 | this.videoShareModal.show() | |
125 | } | |
126 | ||
127 | async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { | |
128 | const res = await this.confirmService.confirm( | |
129 | this.i18n( | |
130 | 'Do you really want to delete {{playlistDisplayName}}?', | |
131 | { playlistDisplayName: videoPlaylist.displayName } | |
132 | ), | |
133 | this.i18n('Delete') | |
134 | ) | |
135 | if (res === false) return | |
136 | ||
137 | this.videoPlaylistService.removeVideoPlaylist(videoPlaylist) | |
138 | .subscribe( | |
139 | () => { | |
140 | this.router.navigate([ '/my-account', 'video-playlists' ]) | |
141 | ||
142 | this.notifier.success( | |
143 | this.i18n('Playlist {{playlistDisplayName}} deleted.', { playlistDisplayName: videoPlaylist.displayName }) | |
144 | ) | |
145 | }, | |
146 | ||
147 | error => this.notifier.error(error.message) | |
148 | ) | |
149 | } | |
150 | ||
0c695c5c JM |
151 | /** |
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. | |
155 | * | |
156 | * @see {@link https://github.com/Chocobozzz/PeerTube/issues/2078} | |
157 | * | |
158 | * @returns {null|number} Null for no delay, or a number in milliseconds. | |
159 | */ | |
160 | getDragStartDelay (): null | number { | |
161 | if (this.screenService.isInTouchScreen()) { | |
162 | return 500 | |
163 | } | |
164 | ||
165 | return null | |
166 | } | |
167 | ||
f0a39880 | 168 | private loadElements () { |
bfbd9128 | 169 | this.videoPlaylistService.getPlaylistVideos(this.videoPlaylistId, this.pagination) |
93cae479 | 170 | .subscribe(({ total, data }) => { |
bfbd9128 | 171 | this.playlistElements = this.playlistElements.concat(data) |
93cae479 | 172 | this.pagination.totalItems = total |
ad453580 C |
173 | |
174 | this.onDataSubject.next(data) | |
f0a39880 C |
175 | }) |
176 | } | |
c5a1ae50 C |
177 | |
178 | private loadPlaylistInfo () { | |
179 | this.videoPlaylistService.getVideoPlaylist(this.videoPlaylistId) | |
180 | .subscribe(playlist => { | |
181 | this.playlist = playlist | |
182 | }) | |
183 | } | |
15e9d5ca | 184 | |
65af03a2 C |
185 | private reorderClientPositions (first?: VideoPlaylistElement) { |
186 | if (this.playlistElements.length === 0) return | |
187 | ||
188 | const oldFirst = first || this.findFirst() | |
15e9d5ca C |
189 | let i = 1 |
190 | ||
bfbd9128 C |
191 | for (const element of this.playlistElements) { |
192 | element.position = i | |
15e9d5ca C |
193 | i++ |
194 | } | |
65af03a2 C |
195 | |
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() | |
200 | } | |
201 | } | |
202 | ||
203 | private findFirst () { | |
204 | return this.playlistElements.find(e => e.position === 1) | |
15e9d5ca | 205 | } |
f0a39880 | 206 | } |