From ad453580b20056fd80b3245d4db554f5ca1a5e29 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 2 Aug 2019 14:49:25 +0200 Subject: [PATCH] Fix infinite scroll on big screens --- .../about-follows.component.html | 2 +- .../about-follows/about-follows.component.ts | 11 +++- .../account-video-channels.component.html | 2 +- .../account-video-channels.component.ts | 6 +- .../plugin-list-installed.component.html | 2 +- .../plugin-list-installed.component.ts | 5 ++ .../plugin-search.component.html | 2 +- .../plugin-search/plugin-search.component.ts | 4 ++ .../my-account-history.component.html | 2 +- .../my-account-subscriptions.component.html | 2 +- .../my-account-subscriptions.component.ts | 5 ++ ...unt-video-playlist-elements.component.html | 2 +- ...unt-video-playlist-elements.component.scss | 2 +- ...count-video-playlist-elements.component.ts | 8 ++- .../my-account-video-playlists.component.html | 2 +- .../my-account-video-playlists.component.ts | 11 +++- .../video-channel-playlists.component.html | 2 +- .../video-channel-playlists.component.ts | 8 ++- .../users/user-notifications.component.html | 2 +- .../users/user-notifications.component.ts | 5 ++ .../video-add-to-playlist.component.ts | 2 +- .../video-playlist/video-playlist.service.ts | 15 +++-- .../app/shared/video/abstract-video-list.html | 2 +- .../app/shared/video/abstract-video-list.ts | 6 +- .../video/infinite-scroller.directive.ts | 65 +++++++++++++------ .../video/videos-selection.component.html | 2 +- .../comment/video-comments.component.html | 1 + .../comment/video-comments.component.ts | 6 +- 28 files changed, 135 insertions(+), 49 deletions(-) diff --git a/client/src/app/+about/about-follows/about-follows.component.html b/client/src/app/+about/about-follows/about-follows.component.html index 18689bbf7..5d7a50c74 100644 --- a/client/src/app/+about/about-follows/about-follows.component.html +++ b/client/src/app/+about/about-follows/about-follows.component.html @@ -1,4 +1,4 @@ -
+
Followers
diff --git a/client/src/app/+about/about-follows/about-follows.component.ts b/client/src/app/+about/about-follows/about-follows.component.ts index f0e1375d6..d60307928 100644 --- a/client/src/app/+about/about-follows/about-follows.component.ts +++ b/client/src/app/+about/about-follows/about-follows.component.ts @@ -4,6 +4,7 @@ import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pa import { Notifier } from '@app/core' import { RestService } from '@app/shared' import { SortMeta } from 'primeng/api' +import { Subject } from 'rxjs' @Component({ selector: 'my-about-follows', @@ -17,13 +18,13 @@ export class AboutFollowsComponent implements OnInit { followersPagination: ComponentPagination = { currentPage: 1, - itemsPerPage: 40, + itemsPerPage: 20, totalItems: null } followingsPagination: ComponentPagination = { currentPage: 1, - itemsPerPage: 40, + itemsPerPage: 20, totalItems: null } @@ -32,6 +33,8 @@ export class AboutFollowsComponent implements OnInit { order: -1 } + onDataSubject = new Subject() + constructor ( private restService: RestService, private notifier: Notifier, @@ -78,6 +81,8 @@ export class AboutFollowsComponent implements OnInit { this.followers = this.followers.concat(newFollowers) this.followersPagination.totalItems = resultList.total + + this.onDataSubject.next(newFollowers) }, err => this.notifier.error(err.message) @@ -94,6 +99,8 @@ export class AboutFollowsComponent implements OnInit { this.followings = this.followings.concat(newFollowings) this.followingsPagination.totalItems = resultList.total + + this.onDataSubject.next(newFollowings) }, err => this.notifier.error(err.message) diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.html b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html index ea5f61b18..4ebad514c 100644 --- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.html +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html @@ -2,7 +2,7 @@
This account does not have channels.
-
+
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts index 7144f4b5f..85dedd7de 100644 --- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts @@ -4,7 +4,7 @@ import { Account } from '@app/shared/account/account.model' import { AccountService } from '@app/shared/account/account.service' import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' import { concatMap, map, switchMap, tap } from 'rxjs/operators' -import { from, Subscription } from 'rxjs' +import { from, Subject, Subscription } from 'rxjs' import { VideoChannel } from '@app/shared/video-channel/video-channel.model' import { Video } from '@app/shared/video/video.model' import { AuthService } from '@app/core' @@ -33,6 +33,8 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy { } videosSort: VideoSortField = '-publishedAt' + onChannelDataSubject = new Subject() + private accountSub: Subscription constructor ( @@ -75,6 +77,8 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy { this.videoChannels.push(videoChannel) this.videos[videoChannel.id] = videos + + this.onChannelDataSubject.next([ videoChannel ]) }) } diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html index 6d2155332..4526aaf66 100644 --- a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html @@ -6,7 +6,7 @@ {{ getNoResultMessage() }}
-
+
diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts index dced14dee..b30b136bd 100644 --- a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts @@ -8,6 +8,7 @@ import { PeerTubePlugin } from '@shared/models/plugins/peertube-plugin.model' import { ActivatedRoute, Router } from '@angular/router' import { compareSemVer } from '@shared/core-utils/miscs/miscs' import { PluginService } from '@app/core/plugins/plugin.service' +import { Subject } from 'rxjs' @Component({ selector: 'my-plugin-list-installed', @@ -33,6 +34,8 @@ export class PluginListInstalledComponent implements OnInit { PluginType = PluginType + onDataSubject = new Subject() + constructor ( private i18n: I18n, private pluginService: PluginService, @@ -67,6 +70,8 @@ export class PluginListInstalledComponent implements OnInit { res => { this.plugins = this.plugins.concat(res.data) this.pagination.totalItems = res.total + + this.onDataSubject.next(res.data) }, err => this.notifier.error(err.message) diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html index 87f1c86ee..6ec6301b1 100644 --- a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html +++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html @@ -29,7 +29,7 @@ No results.
-
+
diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts index a6fbeed84..65566ab79 100644 --- a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts +++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts @@ -36,6 +36,8 @@ export class PluginSearchComponent implements OnInit { installing: { [name: string]: boolean } = {} pluginInstalled = false + onDataSubject = new Subject() + private searchSubject = new Subject() constructor ( @@ -90,6 +92,8 @@ export class PluginSearchComponent implements OnInit { this.plugins = this.plugins.concat(res.data) this.pagination.totalItems = res.total + + this.onDataSubject.next(res.data) }, err => { diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.html b/client/src/app/+my-account/my-account-history/my-account-history.component.html index 6e274f689..7258fcc1f 100644 --- a/client/src/app/+my-account/my-account-history/my-account-history.component.html +++ b/client/src/app/+my-account/my-account-history/my-account-history.component.html @@ -13,7 +13,7 @@
You don't have videos history yet.
-
+
You don't have any subscriptions yet.
-
+
Avatar diff --git a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts index 6ce22989b..b347fc3fe 100644 --- a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts +++ b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts @@ -3,6 +3,7 @@ import { Notifier } from '@app/core' import { VideoChannel } from '@app/shared/video-channel/video-channel.model' import { UserSubscriptionService } from '@app/shared/user-subscription' import { ComponentPagination } from '@app/shared/rest/component-pagination.model' +import { Subject } from 'rxjs' @Component({ selector: 'my-account-subscriptions', @@ -18,6 +19,8 @@ export class MyAccountSubscriptionsComponent implements OnInit { totalItems: null } + onDataSubject = new Subject() + constructor ( private userSubscriptionService: UserSubscriptionService, private notifier: Notifier @@ -33,6 +36,8 @@ export class MyAccountSubscriptionsComponent implements OnInit { res => { this.videoChannels = this.videoChannels.concat(res.data) this.pagination.totalItems = res.total + + this.onDataSubject.next(res.data) }, error => this.notifier.error(error.message) diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.html b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.html index 4de4e69da..a3de3da4a 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.html +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.html @@ -12,7 +12,7 @@
-
+
() + private user: User constructor ( @@ -78,11 +81,15 @@ export class MyAccountVideoPlaylistsComponent implements OnInit { } private loadVideoPlaylists () { + const playlistsObservable = this.videoPlaylistService.listAccountPlaylists(this.user.account, this.pagination, '-updatedAt') + this.authService.userInformationLoaded - .pipe(flatMap(() => this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt'))) + .pipe(flatMap(() => playlistsObservable)) .subscribe(res => { this.videoPlaylists = this.videoPlaylists.concat(res.data) this.pagination.totalItems = res.total + + this.onDataSubject.next(res.data) }) } } diff --git a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.html b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.html index befc7143c..1adc50180 100644 --- a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.html +++ b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.html @@ -4,7 +4,7 @@
This channel does not have playlists.
-
+
diff --git a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts index 7990044a2..0b0033082 100644 --- a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts +++ b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts @@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core' import { ConfirmService } from '../../core/confirm' import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { Subscription } from 'rxjs' +import { Subject, Subscription } from 'rxjs' import { Notifier } from '@app/core' import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model' @@ -22,6 +22,8 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy { totalItems: null } + onDataSubject = new Subject() + private videoChannelSub: Subscription private videoChannel: VideoChannel @@ -53,10 +55,12 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy { } private loadVideoPlaylists () { - this.videoPlaylistService.listChannelPlaylists(this.videoChannel) + this.videoPlaylistService.listChannelPlaylists(this.videoChannel, this.pagination) .subscribe(res => { this.videoPlaylists = this.videoPlaylists.concat(res.data) this.pagination.totalItems = res.total + + this.onDataSubject.next(res.data) }) } } diff --git a/client/src/app/shared/users/user-notifications.component.html b/client/src/app/shared/users/user-notifications.component.html index d0d9d9f35..292813426 100644 --- a/client/src/app/shared/users/user-notifications.component.html +++ b/client/src/app/shared/users/user-notifications.component.html @@ -1,6 +1,6 @@
You don't have notifications.
-
+
diff --git a/client/src/app/shared/users/user-notifications.component.ts b/client/src/app/shared/users/user-notifications.component.ts index ce43b604a..3c9eb369d 100644 --- a/client/src/app/shared/users/user-notifications.component.ts +++ b/client/src/app/shared/users/user-notifications.component.ts @@ -4,6 +4,7 @@ import { UserNotificationType } from '../../../../../shared' import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model' import { Notifier } from '@app/core' import { UserNotification } from '@app/shared/users/user-notification.model' +import { Subject } from 'rxjs' @Component({ selector: 'my-user-notifications', @@ -24,6 +25,8 @@ export class UserNotificationsComponent implements OnInit { componentPagination: ComponentPagination + onDataSubject = new Subject() + constructor ( private userNotificationService: UserNotificationService, private notifier: Notifier @@ -47,6 +50,8 @@ export class UserNotificationsComponent implements OnInit { this.componentPagination.totalItems = result.total this.notificationsLoaded.emit() + + this.onDataSubject.next(result.data) }, err => this.notifier.error(err.message) diff --git a/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts b/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts index 08ceb21bc..72de84703 100644 --- a/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts +++ b/client/src/app/shared/video-playlist/video-add-to-playlist.component.ts @@ -83,7 +83,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, load () { forkJoin([ - this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt'), + this.videoPlaylistService.listAccountPlaylists(this.user.account, undefined,'-updatedAt'), this.videoPlaylistService.doesVideoExistInPlaylist(this.video.id) ]) .subscribe( diff --git a/client/src/app/shared/video-playlist/video-playlist.service.ts b/client/src/app/shared/video-playlist/video-playlist.service.ts index b93a19356..376387082 100644 --- a/client/src/app/shared/video-playlist/video-playlist.service.ts +++ b/client/src/app/shared/video-playlist/video-playlist.service.ts @@ -45,21 +45,28 @@ export class VideoPlaylistService { ) } - listChannelPlaylists (videoChannel: VideoChannel): Observable> { + listChannelPlaylists (videoChannel: VideoChannel, componentPagination: ComponentPagination): Observable> { const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/video-playlists' + const pagination = this.restService.componentPaginationToRestPagination(componentPagination) - return this.authHttp.get>(url) + let params = new HttpParams() + params = this.restService.addRestGetParams(params, pagination) + + return this.authHttp.get>(url, { params }) .pipe( switchMap(res => this.extractPlaylists(res)), catchError(err => this.restExtractor.handleError(err)) ) } - listAccountPlaylists (account: Account, sort: string): Observable> { + listAccountPlaylists (account: Account, componentPagination: ComponentPagination, sort: string): Observable> { const url = AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-playlists' + const pagination = componentPagination + ? this.restService.componentPaginationToRestPagination(componentPagination) + : undefined let params = new HttpParams() - params = this.restService.addRestGetParams(params, undefined, sort) + params = this.restService.addRestGetParams(params, pagination, sort) return this.authHttp.get>(url, { params }) .pipe( diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index efd369bca..13aedcc74 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html @@ -19,7 +19,7 @@
No results.
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index 8a247a9af..2926b179b 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -1,7 +1,7 @@ import { debounceTime, first, tap } from 'rxjs/operators' import { OnDestroy, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { fromEvent, Observable, of, Subscription } from 'rxjs' +import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs' import { AuthService } from '../../core/auth' import { ComponentPagination } from '../rest/component-pagination.model' import { VideoSortField } from './sort-field.type' @@ -59,6 +59,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor blacklistInfo: false } + onDataSubject = new Subject() + protected abstract notifier: Notifier protected abstract authService: AuthService protected abstract route: ActivatedRoute @@ -147,6 +149,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor if (this.groupByDate) this.buildGroupedDateLabels() this.onMoreVideos() + + this.onDataSubject.next(data) }, error => this.notifier.error(error.message) diff --git a/client/src/app/shared/video/infinite-scroller.directive.ts b/client/src/app/shared/video/infinite-scroller.directive.ts index b1e88882c..9f613c5fa 100644 --- a/client/src/app/shared/video/infinite-scroller.directive.ts +++ b/client/src/app/shared/video/infinite-scroller.directive.ts @@ -1,14 +1,15 @@ -import { distinct, distinctUntilChanged, filter, map, share, startWith, throttleTime } from 'rxjs/operators' -import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core' -import { fromEvent, Subscription } from 'rxjs' +import { distinctUntilChanged, filter, map, share, startWith, tap, throttleTime } from 'rxjs/operators' +import { AfterContentChecked, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core' +import { fromEvent, Observable, Subscription } from 'rxjs' @Directive({ selector: '[myInfiniteScroller]' }) -export class InfiniteScrollerDirective implements OnInit, OnDestroy { +export class InfiniteScrollerDirective implements OnInit, OnDestroy, AfterContentChecked { @Input() percentLimit = 70 @Input() autoInit = false @Input() onItself = false + @Input() dataObservable: Observable @Output() nearOfBottom = new EventEmitter() @@ -17,10 +18,22 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy { private scrollDownSub: Subscription private container: HTMLElement + private checkScroll = false + constructor (private el: ElementRef) { this.decimalLimit = this.percentLimit / 100 } + ngAfterContentChecked () { + if (this.checkScroll) { + this.checkScroll = false + + console.log('Checking if the initial state has a scroll.') + + if (this.hasScroll() === false) this.nearOfBottom.emit() + } + } + ngOnInit () { if (this.autoInit === true) return this.initialize() } @@ -30,14 +43,15 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy { } initialize () { - if (this.onItself) { - this.container = this.el.nativeElement - } + this.container = this.onItself + ? this.el.nativeElement + : document.documentElement // Emit the last value const throttleOptions = { leading: true, trailing: true } - const scrollObservable = fromEvent(this.container || window, 'scroll') + const scrollableElement = this.onItself ? this.container : window + const scrollObservable = fromEvent(scrollableElement, 'scroll') .pipe( startWith(null as string), // FIXME: typings throttleTime(200, undefined, throttleOptions), @@ -49,23 +63,34 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy { // Scroll Down this.scrollDownSub = scrollObservable .pipe( - // Check we scroll down - filter(({ current }) => { - const res = this.lastCurrentBottom < current - - this.lastCurrentBottom = current - return res - }), - filter(({ current, maximumScroll }) => maximumScroll <= 0 || (current / maximumScroll) > this.decimalLimit) + filter(({ current }) => this.isScrollingDown(current)), + filter(({ current, maximumScroll }) => (current / maximumScroll) > this.decimalLimit) ) .subscribe(() => this.nearOfBottom.emit()) + + if (this.dataObservable) { + this.dataObservable + .pipe(filter(d => d.length !== 0)) + .subscribe(() => this.checkScroll = true) + } } private getScrollInfo () { - if (this.container) { - return { current: this.container.scrollTop, maximumScroll: this.container.scrollHeight } - } + return { current: this.container.scrollTop, maximumScroll: this.getMaximumScroll() } + } - return { current: window.scrollY, maximumScroll: document.body.clientHeight - window.innerHeight } + private getMaximumScroll () { + return this.container.scrollHeight - window.innerHeight + } + + private hasScroll () { + return this.getMaximumScroll() > 0 + } + + private isScrollingDown (current: number) { + const result = this.lastCurrentBottom < current + + this.lastCurrentBottom = current + return result } } diff --git a/client/src/app/shared/video/videos-selection.component.html b/client/src/app/shared/video/videos-selection.component.html index 120c168cd..2b4b353cf 100644 --- a/client/src/app/shared/video/videos-selection.component.html +++ b/client/src/app/shared/video/videos-selection.component.html @@ -1,6 +1,6 @@
No results.
-
+
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.html b/client/src/app/videos/+video-watch/comment/video-comments.component.html index 7b941454a..be20a8490 100644 --- a/client/src/app/videos/+video-watch/comment/video-comments.component.html +++ b/client/src/app/videos/+video-watch/comment/video-comments.component.html @@ -21,6 +21,7 @@ myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" + [dataObservable]="onDataSubject.asObservable()" >
() + private sub: Subscription constructor ( @@ -124,6 +126,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy { res => { this.comments = this.comments.concat(res.data) this.componentPagination.totalItems = res.total + + this.onDataSubject.next(res.data) }, err => this.notifier.error(err.message)