Add auto scroll to videos list
authorChocobozzz <florian.bigard@gmail.com>
Fri, 1 Dec 2017 15:17:32 +0000 (16:17 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Fri, 1 Dec 2017 15:17:32 +0000 (16:17 +0100)
client/package.json
client/src/app/app-routing.module.ts
client/src/app/shared/misc/from-now.pipe.ts
client/src/app/shared/search/search.component.ts
client/src/app/shared/shared.module.ts
client/src/app/videos/video-list/shared/abstract-video-list.html
client/src/app/videos/video-list/shared/abstract-video-list.ts
client/src/app/videos/video-list/video-recently-added.component.ts
client/src/app/videos/video-list/video-trending.component.ts
client/src/app/videos/videos.module.ts
client/yarn.lock

index 310860fecc8c14e394021c541c17ac66cfe63139..45f555f2968e95e9792cef85b49bbf3604f2c34f 100644 (file)
@@ -71,6 +71,7 @@
     "ngc-webpack": "3.2.2",
     "ngx-bootstrap": "2.0.0-beta.9",
     "ngx-chips": "1.5.3",
+    "ngx-infinite-scroll": "^0.7.0",
     "ngx-pipes": "^2.0.5",
     "node-sass": "^4.1.1",
     "normalize.css": "^7.0.0",
index 0f948434410ad488b80a77a6c90ce68134c6f947..fe72c9181b0ea0faed03a44209d7ca0503391631 100644 (file)
@@ -6,7 +6,7 @@ import { PreloadSelectedModulesList } from './core'
 const routes: Routes = [
   {
     path: '',
-    redirectTo: '/videos/list',
+    redirectTo: '/videos/trending',
     pathMatch: 'full'
   },
   {
index 25e5d6a85791ad4aed7b6b549d1e6ba938fb3619..80dab02ba65630f5706f83c4cba57a6b46ae4bc0 100644 (file)
@@ -1,6 +1,6 @@
 import { Pipe, PipeTransform } from '@angular/core'
 
-// Thanks: https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
+// Thanks: https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site
 
 @Pipe({name: 'fromNow'})
 export class FromNowPipe implements PipeTransform {
index 6ef19c97a49d31e1e95b204e5aabad1f985780ec..f49ecc8ada553ac6df07a037574d573b27051cf3 100644 (file)
@@ -1,8 +1,6 @@
 import { Component, OnInit } from '@angular/core'
 import { Router } from '@angular/router'
-
 import { Search } from './search.model'
-import { SearchField } from './search-field.type'
 import { SearchService } from './search.service'
 
 @Component({
@@ -12,12 +10,6 @@ import { SearchService } from './search.service'
 })
 
 export class SearchComponent implements OnInit {
-  fieldChoices = {
-    name: 'Name',
-    account: 'Account',
-    host: 'Host',
-    tags: 'Tags'
-  }
   searchCriteria: Search = {
     field: 'name',
     value: ''
@@ -40,30 +32,11 @@ export class SearchComponent implements OnInit {
     )
   }
 
-  get choiceKeys () {
-    return Object.keys(this.fieldChoices)
-  }
-
-  choose ($event: MouseEvent, choice: SearchField) {
-    $event.preventDefault()
-    $event.stopPropagation()
-
-    this.searchCriteria.field = choice
-
-    if (this.searchCriteria.value) {
-      this.doSearch()
-    }
-  }
-
   doSearch () {
-    if (this.router.url.indexOf('/videos/list') === -1) {
-      this.router.navigate([ '/videos/list' ])
-    }
+    // if (this.router.url.indexOf('/videos/list') === -1) {
+    //   this.router.navigate([ '/videos/list' ])
+    // }
 
     this.searchService.searchUpdated.next(this.searchCriteria)
   }
-
-  getStringChoice (choiceKey: SearchField) {
-    return this.fieldChoices[choiceKey]
-  }
 }
index c7ea6e603ad236d00ca366bb3ab05c0081d28dda..7618748e9820054d33d48481f7393e61689e1f28 100644 (file)
@@ -6,21 +6,20 @@ import { RouterModule } from '@angular/router'
 
 import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
 import { ModalModule } from 'ngx-bootstrap/modal'
-import { PaginationModule } from 'ngx-bootstrap/pagination'
 import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
 import { BytesPipe, KeysPipe } from 'ngx-pipes'
 import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
 import { DataTableModule } from 'primeng/components/datatable/datatable'
 
 import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
+import { FromNowPipe } from './misc/from-now.pipe'
 import { LoaderComponent } from './misc/loader.component'
+import { NumberFormatterPipe } from './misc/number-formatter.pipe'
 import { RestExtractor, RestService } from './rest'
 import { SearchComponent, SearchService } from './search'
 import { UserService } from './users'
 import { VideoAbuseService } from './video-abuse'
 import { VideoBlacklistService } from './video-blacklist'
-import { NumberFormatterPipe } from './misc/number-formatter.pipe'
-import { FromNowPipe } from './misc/from-now.pipe'
 
 @NgModule({
   imports: [
@@ -32,7 +31,6 @@ import { FromNowPipe } from './misc/from-now.pipe'
 
     BsDropdownModule.forRoot(),
     ModalModule.forRoot(),
-    PaginationModule.forRoot(),
     ProgressbarModule.forRoot(),
 
     DataTableModule,
@@ -57,7 +55,6 @@ import { FromNowPipe } from './misc/from-now.pipe'
 
     BsDropdownModule,
     ModalModule,
-    PaginationModule,
     ProgressbarModule,
     DataTableModule,
     PrimeSharedModule,
index ab5530e6850b00659e1e0c7e15344cb913a1e4a4..69e16319efdb5d1da35fcfe1268167a5a6067e5c 100644 (file)
@@ -2,15 +2,17 @@
   {{ titlePage }}
 </div>
 
-<div class="videos-miniatures">
+<div
+  class="videos-miniatures"
+  infiniteScroll
+  [infiniteScrollUpDistance]="1.5"
+  [infiniteScrollDistance]="0.5"
+  (scrolled)="onNearOfBottom()"
+  (scrolledUp)="onNearOfTop()"
+>
   <my-video-miniature
     class="ng-animate"
     *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort"
   >
   </my-video-miniature>
 </div>
-
-<pagination *ngIf="pagination.totalItems !== null && pagination.totalItems !== 0"
-  [totalItems]="pagination.totalItems" [itemsPerPage]="pagination.itemsPerPage" [maxSize]="6" [boundaryLinks]="true" [rotate]="false"
-  [(ngModel)]="pagination.currentPage" (pageChanged)="onPageChanged($event)"
-></pagination>
index 262ea4e2108ed18ec94647de2be0faa2ae63d1b7..44cdc1d9fce1809bd2810132ccdd00c91f48c3aa 100644 (file)
@@ -19,44 +19,77 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
   protected notificationsService: NotificationsService
   protected router: Router
   protected route: ActivatedRoute
-
   protected subActivatedRoute: Subscription
 
+  protected abstract currentRoute: string
+
   abstract titlePage: string
+  private loadedPages: { [ id: number ]: boolean } = {}
+
   abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
 
   ngOnInit () {
     // Subscribe to route changes
-    this.subActivatedRoute = this.route.params.subscribe(routeParams => {
-      this.loadRouteParams(routeParams)
-
-      this.getVideos()
-    })
+    const routeParams = this.route.snapshot.params
+    this.loadRouteParams(routeParams)
+    this.loadMoreVideos('after')
   }
 
   ngOnDestroy () {
     this.subActivatedRoute.unsubscribe()
   }
 
-  getVideos () {
-    this.videos = []
+  onNearOfTop () {
+    if (this.pagination.currentPage > 1) {
+      this.previousPage()
+    }
+  }
+
+  onNearOfBottom () {
+    if (this.hasMoreVideos()) {
+      this.nextPage()
+    }
+  }
+
+  loadMoreVideos (where: 'before' | 'after') {
+    if (this.loadedPages[this.pagination.currentPage] === true) return
 
     const observable = this.getVideosObservable()
 
     observable.subscribe(
       ({ videos, totalVideos }) => {
-        this.videos = videos
+        this.loadedPages[this.pagination.currentPage] = true
         this.pagination.totalItems = totalVideos
+
+        if (where === 'before') {
+          this.videos = videos.concat(this.videos)
+        } else {
+          this.videos = this.videos.concat(videos)
+        }
       },
       error => this.notificationsService.error('Error', error.text)
     )
   }
 
-  onPageChanged (event: { page: number }) {
-    // Be sure the current page is set
-    this.pagination.currentPage = event.page
+  protected hasMoreVideos () {
+    if (!this.pagination.totalItems) return true
+
+    const maxPage = this.pagination.totalItems/this.pagination.itemsPerPage
+    return maxPage > this.pagination.currentPage
+  }
+
+  protected previousPage () {
+    this.pagination.currentPage--
+
+    this.setNewRouteParams()
+    this.loadMoreVideos('before')
+  }
+
+  protected nextPage () {
+    this.pagination.currentPage++
 
-    this.navigateToNewParams()
+    this.setNewRouteParams()
+    this.loadMoreVideos('after')
   }
 
   protected buildRouteParams () {
@@ -79,8 +112,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
     }
   }
 
-  protected navigateToNewParams () {
+  protected setNewRouteParams () {
     const routeParams = this.buildRouteParams()
-    this.router.navigate([ '/videos/list', routeParams ])
+    this.router.navigate([ this.currentRoute, routeParams ])
   }
 }
index dbba264df1d1db517aa0440aebfee2bacccae679..9bf69bd7875005e75ad2500bf75d030937fd0320 100644 (file)
@@ -11,6 +11,7 @@ import { AbstractVideoList } from './shared'
 })
 export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
   titlePage = 'Recently added'
+  currentRoute = '/videos/recently-added'
 
   constructor (protected router: Router,
                protected route: ActivatedRoute,
index b97966c12b36c6208d9d2986c427dbcb486297ea..a1df68711590f4534b2f026993f317771b28cf02 100644 (file)
@@ -11,6 +11,7 @@ import { AbstractVideoList } from './shared'
 })
 export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy {
   titlePage = 'Trending'
+  currentRoute = '/videos/trending'
 
   constructor (protected router: Router,
                protected route: ActivatedRoute,
index 93193000c6cd8c04d0821aa9d5285aff4dd94181..f3981d27523429439df4ecfaf16aff9c3dad51ef 100644 (file)
@@ -1,4 +1,5 @@
 import { NgModule } from '@angular/core'
+import { InfiniteScrollModule } from 'ngx-infinite-scroll'
 import { SharedModule } from '../shared'
 import { VideoService } from './shared'
 import { MyVideosComponent, VideoMiniatureComponent } from './video-list'
@@ -10,7 +11,8 @@ import { VideosComponent } from './videos.component'
 @NgModule({
   imports: [
     VideosRoutingModule,
-    SharedModule
+    SharedModule,
+    InfiniteScrollModule
   ],
 
   declarations: [
index fa1802a29033f598a172a1e7d62098a9971245d4..bd6870061a3c285d7f69f0486a169daa51e0ad9d 100644 (file)
@@ -4714,6 +4714,10 @@ ngx-chips@1.5.3:
   dependencies:
     ng2-material-dropdown "0.7.10"
 
+ngx-infinite-scroll@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/ngx-infinite-scroll/-/ngx-infinite-scroll-0.7.0.tgz#a390c61c6a05ac14485e1c5bc8b4e6f6bd62fd6a"
+
 ngx-pipes@^2.0.5:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-2.0.5.tgz#743b827e350b1e66f5bdae49e90a02fa631d4c54"