From 83349700a99b730ed8f26b0df0f85f13dc827691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Ainsworth?= <cda@rootkey.co.uk> Date: Mon, 27 Jul 2020 11:02:56 +0200 Subject: [PATCH] Album pagination --- front/src/components/audio/AlbumEntries.vue | 3 ++ front/src/components/audio/ChannelEntries.vue | 32 +++++++++++++++---- .../src/components/audio/ChannelEntryCard.vue | 4 ++- front/src/components/library/AlbumBase.vue | 13 +++++--- front/src/components/library/AlbumDetail.vue | 21 ++++++++++-- front/src/style/components/_pagination.scss | 5 +++ front/src/views/channels/DetailBase.vue | 2 +- front/src/views/channels/DetailEpisodes.vue | 2 +- front/src/views/channels/DetailOverview.vue | 2 +- 9 files changed, 66 insertions(+), 18 deletions(-) diff --git a/front/src/components/audio/AlbumEntries.vue b/front/src/components/audio/AlbumEntries.vue index a7658d5a0..c17258951 100644 --- a/front/src/components/audio/AlbumEntries.vue +++ b/front/src/components/audio/AlbumEntries.vue @@ -16,6 +16,9 @@ </template> <human-duration v-if="track.uploads[0] && track.uploads[0].duration" :duration="track.uploads[0].duration"></human-duration> </div> + <div class="actions"> + <play-button class="play-button basic icon" :dropdown-only="true" :is-playable="track.is_playable" :dropdown-icon-classes="['ellipsis', 'vertical', 'large really discrete']" :track="track"></play-button> + </div> </div> </div> </template> diff --git a/front/src/components/audio/ChannelEntries.vue b/front/src/components/audio/ChannelEntries.vue index 23f70cbed..6d1440864 100644 --- a/front/src/components/audio/ChannelEntries.vue +++ b/front/src/components/audio/ChannelEntries.vue @@ -6,11 +6,16 @@ <div class="ui loader"></div> </div> <channel-entry-card v-for="entry in objects" :entry="entry" :key="entry.id" /> - <template v-if="nextPage"> + <template v-if="count > limit"> <div class="ui hidden divider"></div> - <button v-if="nextPage" @click="fetchData(nextPage)" :class="['ui', 'basic', 'button']"> - <translate translate-context="*/*/Button,Label">Show more</translate> - </button> + <div class = "ui center aligned basic segment"> + <pagination + @page-changed="updatePage" + :current="page" + :paginate-by="limit" + :total="count" + ></pagination> + </div> </template> <template v-if="!isLoading && objects.length === 0"> <empty-state @refresh="fetchData('tracks/')" :refresh="true"> @@ -26,6 +31,8 @@ import _ from '@/lodash' import axios from 'axios' import ChannelEntryCard from '@/components/audio/ChannelEntryCard' +import Pagination from "@/components/Pagination" +import PaginationMixin from "@/components/mixins/Pagination" export default { props: { @@ -33,7 +40,8 @@ export default { limit: {type: Number, default: 10}, }, components: { - ChannelEntryCard + ChannelEntryCard, + Pagination }, data () { return { @@ -41,7 +49,8 @@ export default { count: 0, isLoading: false, errors: null, - nextPage: null + nextPage: null, + page: 1 } }, created () { @@ -56,11 +65,12 @@ export default { let self = this let params = _.clone(this.filters) params.page_size = this.limit + params.page = this.page params.include_channels = true axios.get(url, {params: params}).then((response) => { self.nextPage = response.data.next self.isLoading = false - self.objects = self.objects.concat(response.data.results) + self.objects = response.data.results self.count = response.data.count self.$emit('fetched', response.data) }, error => { @@ -68,6 +78,14 @@ export default { self.errors = error.backendErrors }) }, + updatePage: function(page) { + this.page = page + } + }, + watch: { + page() { + this.fetchData('tracks/') + } } } </script> diff --git a/front/src/components/audio/ChannelEntryCard.vue b/front/src/components/audio/ChannelEntryCard.vue index 430f205f4..5efc812e0 100644 --- a/front/src/components/audio/ChannelEntryCard.vue +++ b/front/src/components/audio/ChannelEntryCard.vue @@ -36,7 +36,9 @@ <track-favorite-icon class="tiny" :track="entry"></track-favorite-icon> </template> <human-duration v-if="duration" :duration="duration"></human-duration> - + </div> + <div class="controls"> + <play-button class="play-button basic icon" :dropdown-only="true" :is-playable="entry.is_playable" :dropdown-icon-classes="['ellipsis', 'vertical', 'large really discrete']" :track="entry"></play-button> </div> </div> </template> diff --git a/front/src/components/library/AlbumBase.vue b/front/src/components/library/AlbumBase.vue index 7b572e145..b6bc2bb47 100644 --- a/front/src/components/library/AlbumBase.vue +++ b/front/src/components/library/AlbumBase.vue @@ -117,7 +117,7 @@ </template> </div> <div class="nine wide column"> - <router-view v-if="object" :is-serie="isSerie" :artist="artist" :discs="discs" @libraries-loaded="libraries = $event" :object="object" object-type="album" :key="$route.fullPath"></router-view> + <router-view v-if="object" :paginate-by="paginateBy" :page="page" :total-tracks="totalTracks" :is-serie="isSerie" :artist="artist" :discs="discs" @libraries-loaded="libraries = $event" :object="object" object-type="album" :key="$route.fullPath" @page-changed="page = $event"></router-view> </div> </div> </section> @@ -134,7 +134,6 @@ import TagsList from "@/components/tags/List" import ArtistLabel from '@/components/audio/ArtistLabel' import AlbumDropdown from './AlbumDropdown' - function groupByDisc(acc, track) { var dn = track.disc_number - 1 if (dn < 0) dn = 0 @@ -152,7 +151,7 @@ export default { PlayButton, TagsList, ArtistLabel, - AlbumDropdown, + AlbumDropdown }, data() { return { @@ -161,6 +160,8 @@ export default { artist: null, discs: [], libraries: [], + page: 1, + paginateBy: 50, } }, async created() { @@ -169,7 +170,7 @@ export default { methods: { async fetchData() { this.isLoading = true - let tracksResponse = axios.get(`tracks/`, {params: {ordering: 'disc_number,position', album: this.id, page_size: 100}}) + let tracksResponse = axios.get(`tracks/`, {params: {ordering: 'disc_number,position', album: this.id, page_size: this.paginateBy, page:this.page, include_channels: 'true'}}) let albumResponse = await axios.get(`albums/${this.id}/`, {params: {refresh: 'true'}}) let artistResponse = await axios.get(`artists/${albumResponse.data.artist.id}/`) this.artist = artistResponse.data @@ -181,7 +182,6 @@ export default { this.object.tracks = tracksResponse.data.results this.discs = this.object.tracks.reduce(groupByDisc, []) this.isLoading = false - }, remove () { let self = this @@ -232,6 +232,9 @@ export default { watch: { id() { this.fetchData() + }, + page() { + this.fetchData() } } } diff --git a/front/src/components/library/AlbumDetail.vue b/front/src/components/library/AlbumDetail.vue index dff0d1948..559a4a330 100644 --- a/front/src/components/library/AlbumDetail.vue +++ b/front/src/components/library/AlbumDetail.vue @@ -20,6 +20,15 @@ <template v-else> <album-entries :tracks="object.tracks"></album-entries> </template> + <div class="ui center aligned basic segment"> + <pagination + v-if="!isSerie && object.tracks && totalTracks > paginateBy" + @page-changed="updatePage" + :current="page" + :paginate-by="paginateBy" + :total="totalTracks" + ></pagination> + </div> <template v-if="!artist.channel && !isSerie"> <h2> <translate translate-context="Content/*/Title/Noun">User libraries</translate> @@ -41,14 +50,17 @@ import LibraryWidget from "@/components/federation/LibraryWidget" import TrackTable from "@/components/audio/track/Table" import ChannelEntries from '@/components/audio/ChannelEntries' import AlbumEntries from '@/components/audio/AlbumEntries' +import Pagination from "@/components/Pagination" +import PaginationMixin from "@/components/mixins/Pagination" export default { - props: ["object", "libraries", "discs", "isSerie", "artist"], + props: ["object", "libraries", "discs", "isSerie", "artist", "page", "paginateBy", "totalTracks"], components: { LibraryWidget, AlbumEntries, ChannelEntries, - TrackTable + TrackTable, + Pagination }, data() { return { @@ -56,5 +68,10 @@ export default { id: this.object.id, } }, + methods: { + updatePage: function(page) { + this.$emit('page-changed', page) + } + }, } </script> diff --git a/front/src/style/components/_pagination.scss b/front/src/style/components/_pagination.scss index 822c29d63..d00e924a9 100644 --- a/front/src/style/components/_pagination.scss +++ b/front/src/style/components/_pagination.scss @@ -9,4 +9,9 @@ + span { margin-left: 1em; } + color: var(--text-color); + background-color: var(--light-background-color); + .active.item { + color: var(--discrete-background-color); + } } diff --git a/front/src/views/channels/DetailBase.vue b/front/src/views/channels/DetailBase.vue index c5b796195..627c5010b 100644 --- a/front/src/views/channels/DetailBase.vue +++ b/front/src/views/channels/DetailBase.vue @@ -209,7 +209,7 @@ <translate translate-context="Content/Channels/Link">Overview</translate> </router-link> <router-link class="item" :exact="true" :to="{name: 'channels.detail.episodes', params: {id: id}}"> - <translate key="1" v-if="isPodcast" translate-context="Content/Channels/*">Episodes</translate> + <translate key="1" v-if="isPodcast" translate-context="Content/Channels/*">All Episodes</translate> <translate key="2" v-else translate-context="*/*/*">Tracks</translate> </router-link> </div> diff --git a/front/src/views/channels/DetailEpisodes.vue b/front/src/views/channels/DetailEpisodes.vue index 7535d7edf..385e58a67 100644 --- a/front/src/views/channels/DetailEpisodes.vue +++ b/front/src/views/channels/DetailEpisodes.vue @@ -1,6 +1,6 @@ <template> <section> - <channel-entries :limit="25" :filters="{channel: object.uuid, ordering: '-creation_date'}"> + <channel-entries :limit="25" :filters="{channel: object.uuid, ordering: 'creation_date'}"> </channel-entries> </section> </template> diff --git a/front/src/views/channels/DetailOverview.vue b/front/src/views/channels/DetailOverview.vue index 7d1212753..f25645a3a 100644 --- a/front/src/views/channels/DetailOverview.vue +++ b/front/src/views/channels/DetailOverview.vue @@ -49,7 +49,7 @@ :can-update="false"></rendered-description> <div class="ui hidden divider"></div> </div> - <channel-entries :key="String(episodesKey) + 'entries'" :filters="{channel: object.uuid, ordering: '-creation_date'}"> + <channel-entries :key="String(episodesKey) + 'entries'" :limit='25' :filters="{channel: object.uuid, ordering: '-creation_date', page_size: '25'}"> <h2 class="ui header"> <translate key="1" v-if="isPodcast" translate-context="Content/Channel/Paragraph">Latest episodes</translate> <translate key="2" v-else translate-context="Content/Channel/Paragraph">Latest tracks</translate> -- GitLab