Fix black theme on some screens
[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 { MiniatureDisplayOptions, 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   videos: Video[] = []
30   ownerDisplayType: OwnerDisplayType = 'account'
31   displayModerationBlock = false
32   titleTooltip: string
33   displayVideoActions = true
34
35   disabled = false
36
37   displayOptions: MiniatureDisplayOptions = {
38     date: true,
39     views: true,
40     by: true,
41     privacyLabel: true,
42     privacyText: false,
43     state: false,
44     blacklistInfo: false
45   }
46
47   protected abstract notifier: Notifier
48   protected abstract authService: AuthService
49   protected abstract route: ActivatedRoute
50   protected abstract serverService: ServerService
51   protected abstract screenService: ScreenService
52   protected abstract router: Router
53   abstract titlePage: string
54
55   private resizeSubscription: Subscription
56   private angularState: number
57
58   abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }>
59
60   abstract generateSyndicationList (): void
61
62   get user () {
63     return this.authService.getUser()
64   }
65
66   ngOnInit () {
67     // Subscribe to route changes
68     const routeParams = this.route.snapshot.queryParams
69     this.loadRouteParams(routeParams)
70
71     this.resizeSubscription = fromEvent(window, 'resize')
72       .pipe(debounceTime(500))
73       .subscribe(() => this.calcPageSizes())
74
75     this.calcPageSizes()
76     if (this.loadOnInit === true) this.loadMoreVideos()
77   }
78
79   ngOnDestroy () {
80     if (this.resizeSubscription) this.resizeSubscription.unsubscribe()
81   }
82
83   disableForReuse () {
84     this.disabled = true
85   }
86
87   enabledForReuse () {
88     this.disabled = false
89   }
90
91   videoById (index: number, video: Video) {
92     return video.id
93   }
94
95   onNearOfBottom () {
96     if (this.disabled) return
97
98     // Last page
99     if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
100
101     this.pagination.currentPage += 1
102
103     this.setScrollRouteParams()
104
105     this.loadMoreVideos()
106   }
107
108   loadMoreVideos () {
109     const observable = this.getVideosObservable(this.pagination.currentPage)
110
111     observable.subscribe(
112       ({ videos, totalVideos }) => {
113         this.pagination.totalItems = totalVideos
114         this.videos = this.videos.concat(videos)
115
116         this.onMoreVideos()
117       },
118
119       error => this.notifier.error(error.message)
120     )
121   }
122
123   reloadVideos () {
124     this.pagination.currentPage = 1
125     this.videos = []
126     this.loadMoreVideos()
127   }
128
129   toggleModerationDisplay () {
130     throw new Error('toggleModerationDisplay is not implemented')
131   }
132
133   removeVideoFromArray (video: Video) {
134     this.videos = this.videos.filter(v => v.id !== video.id)
135   }
136
137   // On videos hook for children that want to do something
138   protected onMoreVideos () { /* empty */ }
139
140   protected loadRouteParams (routeParams: { [ key: string ]: any }) {
141     this.sort = routeParams[ 'sort' ] as VideoSortField || this.defaultSort
142     this.categoryOneOf = routeParams[ 'categoryOneOf' ]
143     this.angularState = routeParams[ 'a-state' ]
144   }
145
146   private calcPageSizes () {
147     if (this.screenService.isInMobileView()) {
148       this.pagination.itemsPerPage = 5
149     }
150   }
151
152   private setScrollRouteParams () {
153     // Already set
154     if (this.angularState) return
155
156     this.angularState = 42
157
158     const queryParams = {
159       'a-state': this.angularState,
160       categoryOneOf: this.categoryOneOf
161     }
162
163     let path = this.router.url
164     if (!path || path === '/') path = this.serverService.getConfig().instance.defaultClientRoute
165
166     this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' })
167   }
168 }