09965012999bdf5e0a4d485c6e83eea41d922a0d
[oweals/peertube.git] / client / src / app / shared / video / abstract-video-list.ts
1 import { debounceTime } from 'rxjs/operators'
2 import { OnDestroy, OnInit } from '@angular/core'
3 import { ActivatedRoute, Router } from '@angular/router'
4 import { fromEvent, Observable, Subscription } from 'rxjs'
5 import { AuthService } from '../../core/auth'
6 import { ComponentPagination } from '../rest/component-pagination.model'
7 import { VideoSortField } from './sort-field.type'
8 import { Video } from './video.model'
9 import { ScreenService } from '@app/shared/misc/screen.service'
10 import { OwnerDisplayType } from '@app/shared/video/video-miniature.component'
11 import { Syndication } from '@app/shared/video/syndication.model'
12 import { Notifier, ServerService } from '@app/core'
13 import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
14
15 export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook {
16   pagination: ComponentPagination = {
17     currentPage: 1,
18     itemsPerPage: 25,
19     totalItems: null
20   }
21   sort: VideoSortField = '-publishedAt'
22
23   categoryOneOf?: number
24   defaultSort: VideoSortField = '-publishedAt'
25
26   syndicationItems: Syndication[] = []
27
28   loadOnInit = true
29   marginContent = true
30   videos: Video[] = []
31   ownerDisplayType: OwnerDisplayType = 'account'
32   displayModerationBlock = false
33   titleTooltip: string
34
35   disabled = false
36
37   protected abstract notifier: Notifier
38   protected abstract authService: AuthService
39   protected abstract route: ActivatedRoute
40   protected abstract serverService: ServerService
41   protected abstract screenService: ScreenService
42   protected abstract router: Router
43   abstract titlePage: string
44
45   private resizeSubscription: Subscription
46   private angularState: number
47
48   abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }>
49
50   abstract generateSyndicationList (): void
51
52   get user () {
53     return this.authService.getUser()
54   }
55
56   ngOnInit () {
57     // Subscribe to route changes
58     const routeParams = this.route.snapshot.queryParams
59     this.loadRouteParams(routeParams)
60
61     this.resizeSubscription = fromEvent(window, 'resize')
62       .pipe(debounceTime(500))
63       .subscribe(() => this.calcPageSizes())
64
65     this.calcPageSizes()
66     if (this.loadOnInit === true) this.loadMoreVideos()
67   }
68
69   ngOnDestroy () {
70     if (this.resizeSubscription) this.resizeSubscription.unsubscribe()
71   }
72
73   disableForReuse () {
74     this.disabled = true
75   }
76
77   enabledForReuse () {
78     this.disabled = false
79   }
80
81   videoById (index: number, video: Video) {
82     return video.id
83   }
84
85   onNearOfBottom () {
86     if (this.disabled) return
87
88     // Last page
89     if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
90
91     this.pagination.currentPage += 1
92
93     this.setScrollRouteParams()
94
95     this.loadMoreVideos()
96   }
97
98   loadMoreVideos () {
99     const observable = this.getVideosObservable(this.pagination.currentPage)
100
101     observable.subscribe(
102       ({ videos, totalVideos }) => {
103         this.pagination.totalItems = totalVideos
104         this.videos = this.videos.concat(videos)
105
106         this.onMoreVideos()
107       },
108
109       error => this.notifier.error(error.message)
110     )
111   }
112
113   reloadVideos () {
114     this.pagination.currentPage = 1
115     this.videos = []
116     this.loadMoreVideos()
117   }
118
119   toggleModerationDisplay () {
120     throw new Error('toggleModerationDisplay is not implemented')
121   }
122
123   // On videos hook for children that want to do something
124   protected onMoreVideos () { /* empty */ }
125
126   protected loadRouteParams (routeParams: { [ key: string ]: any }) {
127     this.sort = routeParams[ 'sort' ] as VideoSortField || this.defaultSort
128     this.categoryOneOf = routeParams[ 'categoryOneOf' ]
129     this.angularState = routeParams[ 'a-state' ]
130   }
131
132   private calcPageSizes () {
133     if (this.screenService.isInMobileView()) {
134       this.pagination.itemsPerPage = 5
135     }
136   }
137
138   private setScrollRouteParams () {
139     // Already set
140     if (this.angularState) return
141
142     this.angularState = 42
143
144     const queryParams = {
145       'a-state': this.angularState,
146       categoryOneOf: this.categoryOneOf
147     }
148
149     let path = this.router.url
150     if (!path || path === '/') path = this.serverService.getConfig().instance.defaultClientRoute
151
152     this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' })
153   }
154 }