From 6d821350eaccad2780f7a3703a0550f6a695ee49 Mon Sep 17 00:00:00 2001
From: Jonas Heinrich <onny@project-insanity.org>
Date: Thu, 18 Mar 2021 14:58:20 +0100
Subject: [PATCH] beginning to implement pagination for library and listening

---
 lib/Controller/EpisodeController.php | 31 +++++++++++++++---------
 lib/Controller/ShowController.php    | 12 +++++++++-
 lib/Service/FyydApiService.php       |  2 ++
 src/services/Player.js               |  3 ---
 src/store/episode.js                 |  4 ++--
 src/store/player.js                  | 12 ++++------
 src/store/show.js                    |  2 +-
 src/views/Library.vue                | 34 ++++++++++++++++++++++++++
 src/views/Listening.vue              | 36 ++++++++++++++++++++++++++++
 9 files changed, 110 insertions(+), 26 deletions(-)

diff --git a/lib/Controller/EpisodeController.php b/lib/Controller/EpisodeController.php
index e8f3818..db66b5b 100644
--- a/lib/Controller/EpisodeController.php
+++ b/lib/Controller/EpisodeController.php
@@ -66,7 +66,16 @@ class EpisodeController extends Controller {
 			return new DataResponse($this->fyydapi->queryEpisodes($podcast_id, $count, $page));
 		}
 
-		return new DataResponse($this->service->findAll($this->userId));
+		$data = $this->service->findAll($this->userId);
+		$data = array_slice($data, $page * $count, $count);
+
+		$response = [
+			"meta" => [
+				"paging" => null
+			],
+			"data" => $data,
+		];
+		return new DataResponse($response);
 	}
 
 	/**
@@ -81,27 +90,27 @@ class EpisodeController extends Controller {
 	/**
 	 * @NoAdminRequired
 	 */
-	 public function create(int $id, string $imgurl, string $title,
+	 public function create(int $id, string $imgURL, string $title,
 	 	string $pubdate, int $duration, int $playtime, int $lastplayed,
-		string $enclosure, string $description, int $podcastid
+		string $enclosure, string $description, int $podcast_id
 		): DataResponse {
- 		return new DataResponse($this->service->create($id, $imgurl, $title,
+ 		return new DataResponse($this->service->create($id, $imgURL, $title,
 			$pubdate, $duration, $playtime, $lastplayed, $enclosure, $description,
-			$podcastid, $this->userId));
+			$podcast_id, $this->userId));
  	}
 
 	/**
 	 * @NoAdminRequired
 	 */
-	public function update(int $id, string $imgurl, string $title,
+	public function update(int $id, string $imgURL, string $title,
 		string $pubdate, int $duration, int $playtime, int $lastplayed,
-		string $enclosure, string $description, int $podcastid
+		string $enclosure, string $description, int $podcast_id
 		): DataResponse {
-		return $this->handleNotFound(function () use ($id, $imgurl, $title,
+		return $this->handleNotFound(function () use ($id, $imgURL, $title,
 			$pubdate, $duration, $playtime, $lastplayed, $enclosure, $description,
-			$podcastid) {
-			return $this->service->update($id, $imgurl, $title, $pubdate, $duration,
-				$playtime, $lastplayed, $enclosure, $description, $podcastid,
+			$podcast_id) {
+			return $this->service->update($id, $imgURL, $title, $pubdate, $duration,
+				$playtime, $lastplayed, $enclosure, $description, $podcast_id,
 				$this->userId);
  		});
  	}
diff --git a/lib/Controller/ShowController.php b/lib/Controller/ShowController.php
index e917b44..50d35a6 100644
--- a/lib/Controller/ShowController.php
+++ b/lib/Controller/ShowController.php
@@ -65,7 +65,17 @@ class ShowController extends Controller {
 			return new DataResponse($this->fyydapi->queryPodcast($podcast_id));
 		}
 
-		return new DataResponse($this->service->findAll($this->userId));
+		$data = $this->service->findAll($this->userId);
+		$data = array_slice($data, $page * $count, $count);
+
+		$response = [
+			"meta" => [
+				"paging" => null,
+			],
+			"data" => $data,
+		];
+		return new DataResponse($response);
+
 	}
 
 	/**
diff --git a/lib/Service/FyydApiService.php b/lib/Service/FyydApiService.php
index f109e52..0d5cb09 100644
--- a/lib/Service/FyydApiService.php
+++ b/lib/Service/FyydApiService.php
@@ -64,8 +64,10 @@ class FyydApiService {
 			throw $e;
 		}
 		$body = $response->getBody();
+
 		$parsed = json_decode($body, true);
 
+
 		return $parsed;
 	}
 
diff --git a/src/services/Player.js b/src/services/Player.js
index 07bb607..2695794 100644
--- a/src/services/Player.js
+++ b/src/services/Player.js
@@ -44,12 +44,9 @@ export class Player {
 				store.dispatch('setBuffering', true)
 			},
 			onplay() {
-				const duration = audioPlayer.duration()
 				store.dispatch('setPlaying', true)
 				store.dispatch('setBuffering', false)
 				store.dispatch('setPausing', false)
-				store.dispatch('setDuration', duration)
-
 			},
 			onpause() {
 				store.dispatch('setPlaying', false)
diff --git a/src/store/episode.js b/src/store/episode.js
index 5d82e97..d5af04d 100644
--- a/src/store/episode.js
+++ b/src/store/episode.js
@@ -63,9 +63,9 @@ export default {
 		async loadEpisodes(context) {
 			const episodes = await apiClient.loadEpisodes()
 			if (episodes) {
-				context.dispatch('loadEpisode', episodes[0])
+				context.dispatch('loadEpisode', episodes.data[0])
 			}
-			context.commit('setEpisodes', episodes)
+			context.commit('setEpisodes', episodes.data)
 		},
 		addEpisode({ commit, getters }, episode) {
 			if (getters.episodeExists(episode.id)) {
diff --git a/src/store/player.js b/src/store/player.js
index 1a35e99..6a9a6a4 100644
--- a/src/store/player.js
+++ b/src/store/player.js
@@ -65,7 +65,7 @@ export default {
 			return state.isBuffering
 		},
 		isPaused: state => (id) => {
-			return (state.episodeId === id && state.isPaused)
+			return (state.episode.id === id && state.isPaused)
 		},
 		episodeLoaded: state => (id) => {
 			return (state.episode.id === id)
@@ -158,7 +158,7 @@ export default {
 			player.load(episode.enclosure)
 		},
 		playEpisode(context, episode) {
-			if (context.state.isPaused && episode.id === context.state.episodeId) {
+			if (context.state.isPaused && episode.id === context.state.episode.id) {
 				player.play()
 			} else {
 				context.dispatch('loadEpisode', episode)
@@ -175,7 +175,7 @@ export default {
 		},
 
 		togglePlay(context) {
-			if (context.state.episodeId === null) {
+			if (context.state.episode.id === null) {
 				return true
 			}
 			if (context.state.isPaused) {
@@ -185,10 +185,6 @@ export default {
 			}
 		},
 
-		setDuration(context, duration) {
-			context.commit('setDuration', duration)
-		},
-
 		seekEpisode(context, startTime) {
 			context.commit('seekEpisode', startTime)
 		},
@@ -198,7 +194,7 @@ export default {
 		},
 
 		storePlaybacktime(context, position) {
-			const episodeId = context.state.episodeId
+			const episodeId = context.state.episode.id
 			const episode = context.getters.episodeById(episodeId)
 			const episodeLastPlayed = episode.lastplayed
 			const dateNow = Date.now()
diff --git a/src/store/show.js b/src/store/show.js
index 0ae2640..4953c75 100644
--- a/src/store/show.js
+++ b/src/store/show.js
@@ -59,7 +59,7 @@ export default {
 	actions: {
 		async loadShows({ commit }) {
 			const shows = await apiClient.loadShows()
-			commit('setShows', shows)
+			commit('setShows', shows.data)
 		},
 		addShow({ commit }, show) {
 			apiClient.addShow(show)
diff --git a/src/views/Library.vue b/src/views/Library.vue
index 17d3f97..2ff4ed9 100644
--- a/src/views/Library.vue
+++ b/src/views/Library.vue
@@ -22,6 +22,7 @@
 <template>
 	<div class="mainContent">
 		<ItemGrid
+			v-resize:debounce="onResize"
 			:title="t('podcast', 'Library')"
 			:show-menu="true"
 			:podcasts="podcasts"
@@ -34,12 +35,19 @@ import ItemGrid from '../components/ItemGrid'
 import { mapGetters } from 'vuex'
 import { setBrowserTitle } from '../utils/misc.js'
 import { getRequestToken } from '@nextcloud/auth'
+import resize from 'vue-resize-directive'
 
 export default {
 	name: 'Library',
 	components: {
 		ItemGrid,
 	},
+	directives: {
+		resize,
+	},
+	data: () => ({
+		page: 0,
+	}),
 	computed: {
 		...mapGetters([
 			'subscribedShows',
@@ -53,9 +61,35 @@ export default {
 	},
 	mounted() {
 		setBrowserTitle(t('podcast', 'Library'))
+		document.getElementById('app-content-vue').addEventListener('scroll', this.handleScroll)
+	},
+	destroyed() {
+	  document.getElementById('app-content-vue').removeEventListener('scroll', this.handleScroll)
 	},
 	methods: {
 
+		preFill() {
+			const yFill = document.getElementsByClassName('tableLoading')[0].getBoundingClientRect().bottom
+			const playerPosY = document.getElementsByClassName('player')[0].getBoundingClientRect().top
+			if (yFill > 0 && yFill < playerPosY) {
+				this.queryPodcasts(this.page)
+			}
+		},
+
+		/**
+		 * On scroll event, load more episodes if bottom reached
+		 */
+		handleScroll() {
+			const appContent = document.getElementById('app-content-vue')
+			if (appContent.scrollTop === (appContent.scrollHeight - appContent.clientHeight)) {
+				this.queryPodcasts(this.page)
+			}
+		},
+
+		onResize() {
+			this.preFill()
+		},
+
 		doExport() {
 			window.location
 				= 'export?requesttoken='
diff --git a/src/views/Listening.vue b/src/views/Listening.vue
index 1d639ad..f71ddf1 100644
--- a/src/views/Listening.vue
+++ b/src/views/Listening.vue
@@ -25,6 +25,7 @@
 			<h1>{{ t('podcast', 'Currently listening') }}</h1>
 		</div>
 		<Table
+			v-resize:debounce="onResize"
 			:episodes="episodes"
 			:extended="true"
 			@doPlay="doPlay" />
@@ -35,12 +36,19 @@
 import Table from '../components/Table'
 import { mapGetters, mapActions } from 'vuex'
 import { setBrowserTitle } from '../utils/misc.js'
+import resize from 'vue-resize-directive'
 
 export default {
 	name: 'Listening',
 	components: {
 		Table,
 	},
+	directives: {
+		resize,
+	},
+	data: () => ({
+		page: 0,
+	}),
 	computed: {
 		...mapGetters([
 			'getEpisodes',
@@ -55,12 +63,39 @@ export default {
 	},
 	mounted() {
 		setBrowserTitle(t('podcast', 'Currently listening'))
+		document.getElementById('app-content-vue').addEventListener('scroll', this.handleScroll)
+	},
+	destroyed() {
+	  document.getElementById('app-content-vue').removeEventListener('scroll', this.handleScroll)
 	},
 	methods: {
 		...mapActions([
 			'pauseEpisode',
 			'playEpisode',
 		]),
+
+		preFill() {
+			const yFill = document.getElementsByClassName('tableLoading')[0].getBoundingClientRect().bottom
+			const playerPosY = document.getElementsByClassName('player')[0].getBoundingClientRect().top
+			if (yFill > 0 && yFill < playerPosY) {
+				this.queryPodcasts(this.page)
+			}
+		},
+
+		/**
+		 * On scroll event, load more episodes if bottom reached
+		 */
+		handleScroll() {
+			const appContent = document.getElementById('app-content-vue')
+			if (appContent.scrollTop === (appContent.scrollHeight - appContent.clientHeight)) {
+				this.queryPodcasts(this.page)
+			}
+		},
+
+		onResize() {
+			this.preFill()
+		},
+
 		doPlay(episode) {
 			if (this.episodePlaying(episode.id)) {
 				this.pauseEpisode()
@@ -68,6 +103,7 @@ export default {
 				this.playEpisode(episode)
 			}
 		},
+
 	},
 }
 </script>
-- 
GitLab