From 8967cf7647442edb7215f008cdee5f6558842842 Mon Sep 17 00:00:00 2001
From: Kendall Garner <17521368+kgarner7@users.noreply.github.com>
Date: Tue, 26 Jul 2022 15:52:13 +0000
Subject: [PATCH] Paginate/infinite scroll for albums, playlists (#1234)
* Infinite scroll, pagination to album, playlists
* move pagination below tracks
* Make page size configurable
* remove renderer
---
src/i18n/en_US.json | 2 +
src/main/base/browserwindow.ts | 1 +
src/main/base/store.ts | 7 +-
src/renderer/views/components/pagination.ejs | 175 ++++++++++++++++++
.../views/components/settings-window.ejs | 21 +++
src/renderer/views/pages/cider-playlist.ejs | 78 +++++++-
src/renderer/views/pages/library-albums.ejs | 37 +++-
src/renderer/views/pages/library-songs.ejs | 158 ++--------------
8 files changed, 328 insertions(+), 151 deletions(-)
create mode 100644 src/renderer/views/components/pagination.ejs
diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json
index b01419a5..d8b8d5a8 100644
--- a/src/i18n/en_US.json
+++ b/src/i18n/en_US.json
@@ -360,6 +360,8 @@
"settings.prompt.general.keybindings.update.success": "Keybind updated successfully. Press OK to relaunch Cider",
"settings.option.general.themeUpdateNotification": "Automatically check for theme updates",
"settings.option.general.showLovedTracksInline": "Show loved tracks inline",
+ "settings.option.general.pagination": "Items to show per page",
+ "settings.options.general.pagination.description": "This determines how many songs/albums to show initially for infinite scrolling, or how many songs/albums to show for a single page",
"settings.description.search": "Search",
"settings.description.albums": "Library Albums",
"settings.description.artists": "Library Artists",
diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts
index 20addc89..a63dec93 100644
--- a/src/main/base/browserwindow.ts
+++ b/src/main/base/browserwindow.ts
@@ -125,6 +125,7 @@ export class BrowserWindow {
"components/hello-world",
"components/inline-collection-list",
"components/settings-window",
+ "components/pagination",
"components/settings-keybinds",
"components/settings-themes",
"components/settings-themes-github",
diff --git a/src/main/base/store.ts b/src/main/base/store.ts
index 2debe3ca..abce4f17 100644
--- a/src/main/base/store.ts
+++ b/src/main/base/store.ts
@@ -153,11 +153,16 @@ export class Store {
"size": "normal"
},
"albums": {
+ "scroll": "infinite",
"sort": "name",
"sortOrder": "asc",
"viewAs": "covers"
},
- "localPaths": []
+ "playlists": {
+ "scroll": "infinite"
+ },
+ "localPaths": [],
+ "pageSize": 250
},
"audio": {
"volume": 1,
diff --git a/src/renderer/views/components/pagination.ejs b/src/renderer/views/components/pagination.ejs
new file mode 100644
index 00000000..82fc0206
--- /dev/null
+++ b/src/renderer/views/components/pagination.ejs
@@ -0,0 +1,175 @@
+
+
+
\ No newline at end of file
diff --git a/src/renderer/views/components/settings-window.ejs b/src/renderer/views/components/settings-window.ejs
index 42415be2..246f7535 100644
--- a/src/renderer/views/components/settings-window.ejs
+++ b/src/renderer/views/components/settings-window.ejs
@@ -1262,6 +1262,27 @@
+
+
+
+ {{$root.getLz('settings.option.general.pagination')}}
+
+ {{$root.getLz('settings.options.general.pagination.description')}}
+
+
+
+
+
+
diff --git a/src/renderer/views/pages/cider-playlist.ejs b/src/renderer/views/pages/cider-playlist.ejs
index 4da96a35..6db45794 100644
--- a/src/renderer/views/pages/cider-playlist.ejs
+++ b/src/renderer/views/pages/cider-playlist.ejs
@@ -107,6 +107,12 @@
{{app.getLz('term.confirm')}}
+
+
@@ -172,7 +184,7 @@
-
+
@@ -186,18 +198,27 @@
class="search-input"
ref="search-bar">
+
-
+ v-for="(item,index) in currentSlice">
-
+
{{($root.getLz("term.discNumber") ??
"").replace("${discNumber}",disc.disc)}}
@@ -278,6 +299,7 @@
props: ["data"],
data: function () {
+ const pageSize = this.$root.cfg.libraryPrefs.pageSize;
return {
editorialNotesExpanded: false,
drag: false,
@@ -291,6 +313,7 @@
headerVisible: true,
useArtistChip: false,
nestedPlaylist: [],
+ nestedDisplayLength: 0,
classes: [],
editing: false,
inPlaylist: false,
@@ -298,6 +321,10 @@
displayListing: [],
hasNestedPlaylist: false,
showSearch: false,
+ pageSize: pageSize,
+ start: 0,
+ end: pageSize,
+ prefs: this.$root.cfg.libraryPrefs.playlists
}
},
mounted: function () {
@@ -346,7 +373,48 @@
deep: true
}
},
+ computed: {
+ currentSlice() {
+ return this.displayListing.slice(this.start, this.end);
+ },
+ nestedSlices() {
+ if (this.shouldPaginate) {
+ let songsSeen = 0;
+ const discs = [];
+
+ for (const disc of this.nestedPlaylist) {
+ songsSeen += disc.tracks.length;
+
+ if (songsSeen >= this.end) {
+ discs.push({
+ disc: disc.disc,
+ tracks: disc.tracks.slice(0, this.end + disc.tracks.length - songsSeen)
+ })
+ break;
+ } else if (songsSeen > this.start) {
+ discs.push({
+ disc: disc.disc,
+ tracks: disc.tracks.slice(this.start - songsSeen)
+ })
+ }
+ }
+
+ return discs;
+ } else {
+ return this.nestedPlaylist
+ }
+ },
+ shouldPaginate() {
+ const result = this.data.relationships.tracks.data.length > this.pageSize
+ console.log(result)
+ return result
+ }
+ },
methods: {
+ onRangeChange(newRange) {
+ this.start = newRange[0];
+ this.end = newRange[1];
+ },
isAlbum() {
return (this.data.attributes?.playParams?.kind ?? this.data.type ?? '').includes('album')
},
@@ -372,6 +440,8 @@
},
generateNestedPlaylist(songlists) {
this.nestedPlaylist = [];
+ this.nestedDisplayLength = songlists.length;
+
if (this.data?.type?.includes("album")) {
let discs = songlists.map(x => {
return x.attributes.discNumber
diff --git a/src/renderer/views/pages/library-albums.ejs b/src/renderer/views/pages/library-albums.ejs
index 0b98c83b..7f161afa 100644
--- a/src/renderer/views/pages/library-albums.ejs
+++ b/src/renderer/views/pages/library-albums.ejs
@@ -46,17 +46,33 @@
+
+
+
+
@@ -65,21 +81,34 @@
Vue.component('cider-library-albums', {
template: '#cider-library-albums',
data: function () {
+ const pageSize = this.$root.cfg.libraryPrefs.pageSize;
return {
library: this.$root.library,
mediaItemSize: "compact",
prefs: this.$root.cfg.libraryPrefs.albums,
- app : this.$root
+ app: this.$root,
+ pageSize: pageSize,
+ start: 0,
+ end: pageSize
}
},
mounted() {
this.$root.getLibraryAlbumsFull(null, 1);
this.$root.getAlbumSort();
this.$root.searchLibraryAlbums(1);
- this.$root.getLibrarySongsFull() ;
+ this.$root.getLibrarySongsFull();
this.$root.searchLibraryAlbums(1);
},
+ computed: {
+ currentSlice: function () {
+ return this.library.albums.displayListing.slice(this.start, this.end);
+ }
+ },
methods: {
+ onRangeChange: function (newRange) {
+ this.start = newRange[0];
+ this.end = newRange[1];
+ }
}
});
\ No newline at end of file
diff --git a/src/renderer/views/pages/library-songs.ejs b/src/renderer/views/pages/library-songs.ejs
index 589bc5ae..e1fc35f9 100644
--- a/src/renderer/views/pages/library-songs.ejs
+++ b/src/renderer/views/pages/library-songs.ejs
@@ -64,45 +64,13 @@
-
-
-
-
-
-
-
-
- / {{ numPages }}
-
-
+
Library contains no songs.
@@ -119,125 +87,31 @@
Vue.component('cider-library-songs', {
template: '#cider-library-songs',
data: function () {
+ const pageSize = this.$root.cfg.libraryPrefs.pageSize;
return {
// currentPage is oneIndexed
- currentPage: 1,
library: this.$root.library,
mediaItemSize: "compact",
- pageSize: 250,
prefs: this.$root.cfg.libraryPrefs.songs,
- app: this.$root
+ app: this.$root,
+ pageSize: pageSize,
+ start: 0,
+ end: pageSize
}
},
mounted() {
- document.querySelector("#app-content")
- .addEventListener("scroll", this.handleScroll)
this.$root.getLibrarySongsFull()
},
- destroyed() {
- document.querySelector("#app-content")
- .removeEventListener("scroll", this.handleScroll)
- },
- watch: {
- 'library.songs.displayListing.length': function () {
- if (this.isInfinite) {
- // If a search reduces the number of things to show, we want to limit
- // the number of songs shown as well. This is to prevent you scrolling
- // to load your entire library, searching for one song, and then having
- // th re-render the entire library
- if (this.currentPage > this.numPages) {
- this.currentPage = this.numPages;
- }
- }
- },
- 'prefs.scroll': function () {
- // When changing modes, set the page to 1. This is primarily to
- // prevent going to a high page (e.g., 50) and then switching to infinite
- // and showing 12.5k songs
- this.currentPage = 1;
- }
- },
computed: {
- isInfinite: function () {
- return this.prefs.scroll === "infinite"
- },
currentSlice: function () {
- if (this.isInfinite) {
- return this.library.songs.displayListing.slice(
- 0, this.currentPage * this.pageSize
- );
- } else {
- const startingPage = Math.min(this.numPages, this.currentPage);
-
- return this.library.songs.displayListing.slice(
- (startingPage - 1) * this.pageSize,
- startingPage * this.pageSize
- );
- }
- },
- numPages: function () {
- return Math.ceil(this.library.songs.displayListing.length / this.pageSize) || 1;
- },
- pagesToShow: function () {
- let start = this.currentPage - 2;
- let end = this.currentPage + 2;
-
- if (start < 1) {
- end += (1 - start);
- start = 1;
- }
-
- const endDifference = end - this.numPages;
- if (endDifference > 0) {
- end = this.numPages;
- start = Math.max(1, start - endDifference);
- }
-
- const array = [];
- for (let idx = start; idx <= end; idx++) {
- array.push(idx);
- }
- return array;
+ return this.library.songs.displayListing.slice(this.start, this.end);
}
},
methods: {
- // Infinite Scrolling
- handleScroll: function (event) {
- if (this.isInfinite &&
- this.currentPage < this.numPages &&
- event.target.scrollTop >= event.target.scrollHeight - event.target.clientHeight) {
- this.currentPage += 1;
- }
+ onRangeChange: function (newRange) {
+ this.start = newRange[0];
+ this.end = newRange[1];
},
- // Pagination
- isCurrentPage: function (idx) {
- return idx === this.currentPage ||
- (idx === this.numPages && this.currentPage > this.numPages);
- },
- changePage: function (event) {
- const value = event.target.valueAsNumber;
-
- if (!isNaN(value) && value >= 1 && value <= this.numPages) {
- this.currentPage = value;
- }
- },
- goToPage: function (page) {
- this.currentPage = page;
- },
- goToPrevious: function () {
- if (this.currentPage > 1) {
- this.currentPage -= 1;
- }
- },
- goToNext: function () {
- if (this.currentPage < this.numPages) {
- this.currentPage += 1;
- }
- },
- goToEnd: function () {
- this.currentPage = this.numPages;
- },
- // Miscellaneous
play: function () {
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {