diff --git a/changes/changelog.d/719.enhancement b/changes/changelog.d/719.enhancement new file mode 100644 index 0000000000000000000000000000000000000000..e4c5b35bebdbe2d0d98793649ed71639a7ddd071 --- /dev/null +++ b/changes/changelog.d/719.enhancement @@ -0,0 +1 @@ +Added a "load more" button on artist pages to load more tracks/albums (#719) diff --git a/front/src/components/audio/track/Table.vue b/front/src/components/audio/track/Table.vue index 702ffe687617df4cbc2b8ab34e1384c7e28f6584..31327ee3a5e3286cec4eded21ccc801d73e0b1eb 100644 --- a/front/src/components/audio/track/Table.vue +++ b/front/src/components/audio/track/Table.vue @@ -19,14 +19,18 @@ :track="track" :artist="artist" :key="index + '-' + track.id" - v-for="(track, index) in tracks"></track-row> + v-for="(track, index) in allTracks"></track-row> </tbody> </table> + <button :class="['ui', {loading: isLoadingMore}, 'button']" v-if="loadMoreUrl" @click="loadMore(loadMoreUrl)"> + <translate translate-context="Content/*/Button.Label">Load more…</translate> + </button> </div> </template> <script> import backend from '@/audio/backend' +import axios from 'axios' import TrackRow from '@/components/audio/track/Row' import Modal from '@/components/semantic/Modal' @@ -35,6 +39,7 @@ export default { props: { tracks: {type: Array, required: true}, playable: {type: Boolean, required: false, default: false}, + nextUrl: {type: String, required: false, default: null}, artist: {type: Object, required: false}, displayPosition: {type: Boolean, default: false} }, @@ -44,7 +49,29 @@ export default { }, data () { return { - backend: backend + backend: backend, + loadMoreUrl: this.nextUrl, + isLoadingMore: false, + additionalTracks: [] + } + }, + computed: { + allTracks () { + return this.tracks.concat(this.additionalTracks) + } + }, + methods: { + loadMore (url) { + let self = this + self.isLoadingMore = true + axios.get(url).then((response) => { + self.additionalTracks = self.additionalTracks.concat(response.data.results) + self.loadMoreUrl = response.data.next + self.isLoadingMore = false + }, (error) => { + self.isLoadingMore = false + + }) } } } diff --git a/front/src/components/library/ArtistBase.vue b/front/src/components/library/ArtistBase.vue index d4efcb82ec101214830506fbe1f23057dbd32dcd..71f3abd5ca2a31247d950786ce7bd41f400541d1 100644 --- a/front/src/components/library/ArtistBase.vue +++ b/front/src/components/library/ArtistBase.vue @@ -3,7 +3,7 @@ <div v-if="isLoading" class="ui vertical segment"> <div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div> </div> - <template v-if="object"> + <template v-if="object && !isLoading"> <section :class="['ui', 'head', {'with-background': cover}, 'vertical', 'center', 'aligned', 'stripe', 'segment']" :style="headerStyle" v-title="object.name"> <div class="segment-content"> <h2 class="ui center aligned icon header"> @@ -98,7 +98,15 @@ </div> </div> </section> - <router-view v-if="object" :tracks="tracks" :albums="albums" :is-loading-albums="isLoadingAlbums" @libraries-loaded="libraries = $event" :object="object" object-type="artist" :key="$route.fullPath"></router-view> + <router-view + :tracks="tracks" + :next-tracks-url="nextTracksUrl" + :next-albums-url="nextAlbumsUrl" + :albums="albums" + :is-loading-albums="isLoadingAlbums" + @libraries-loaded="libraries = $event" + :object="object" object-type="artist" + :key="$route.fullPath"></router-view> </template> </main> </template> @@ -132,38 +140,45 @@ export default { libraries: [], showEmbedModal: false, tracks: [], + nextAlbumsUrl: null, + nextTracksUrl: null, + totalAlbums: null, + totalTracks: null, } }, - created() { - this.fetchData() + async created() { + await this.fetchData() }, methods: { - fetchData() { + async fetchData() { var self = this this.isLoading = true logger.default.debug('Fetching artist "' + this.id + '"') - axios.get("tracks/", { params: { artist: this.id, hidden: '' } }).then(response => { + let trackPromise = axios.get("tracks/", { params: { artist: this.id, hidden: '' } }).then(response => { self.tracks = response.data.results + self.nextTracksUrl = response.data.next self.totalTracks = response.data.count }) - axios.get("artists/" + this.id + "/").then(response => { - self.object = response.data - self.isLoading = false - self.isLoadingAlbums = true - axios - .get("albums/", { - params: { artist: self.id, ordering: "-release_date", hidden: '' } - }) - .then(response => { - self.totalAlbums = response.data.count - let parsed = JSON.parse(JSON.stringify(response.data.results)) - self.albums = parsed.map(album => { - return backend.Album.clean(album) - }) + let albumPromise = axios.get("albums/", { + params: { artist: self.id, ordering: "-release_date", hidden: '' } + }).then(response => { + self.nextAlbumsUrl = response.data.next + self.totalAlbums = response.data.count + let parsed = JSON.parse(JSON.stringify(response.data.results)) + self.albums = parsed.map(album => { + return backend.Album.clean(album) + }) - self.isLoadingAlbums = false - }) }) + + let artistPromise = axios.get("artists/" + this.id + "/").then(response => { + self.object = response.data + }) + await trackPromise + await albumPromise + await artistPromise + self.isLoadingAlbums = false + self.isLoading = false } }, computed: { diff --git a/front/src/components/library/ArtistDetail.vue b/front/src/components/library/ArtistDetail.vue index 50e1856e91cab720459674997c1b33581a316949..1dfbdd0d244720ec21fe731ae01e9629c30f6ffb 100644 --- a/front/src/components/library/ArtistDetail.vue +++ b/front/src/components/library/ArtistDetail.vue @@ -21,15 +21,19 @@ <h2> <translate translate-context="Content/Artist/Title">Albums by this artist</translate> </h2> - <div class="ui cards" > - <album-card :mode="'rich'" :album="album" :key="album.id" v-for="album in albums"></album-card> + <div class="ui cards"> + <album-card :mode="'rich'" :album="album" :key="album.id" v-for="album in allAlbums"></album-card> </div> + <div class="ui hidden divider"></div> + <button :class="['ui', {loading: isLoadingMoreAlbums}, 'button']" v-if="nextAlbumsUrl && loadMoreAlbumsUrl" @click="loadMoreAlbums(loadMoreAlbumsUrl)"> + <translate translate-context="Content/*/Button.Label">Load more…</translate> + </button> </section> <section v-if="tracks.length > 0" class="ui vertical stripe segment"> <h2> <translate translate-context="Content/Artist/Title">Tracks by this artist</translate> </h2> - <track-table :display-position="true" :tracks="tracks"></track-table> + <track-table :display-position="true" :tracks="tracks" :next-url="nextTracksUrl"></track-table> </section> <section class="ui vertical stripe segment"> <h2> @@ -52,23 +56,42 @@ import TrackTable from "@/components/audio/track/Table" import LibraryWidget from "@/components/federation/LibraryWidget" export default { - props: ["object", "tracks", "albums", "isLoadingAlbums"], + props: ["object", "tracks", "albums", "isLoadingAlbums", "nextTracksUrl", "nextAlbumsUrl"], components: { AlbumCard, TrackTable, LibraryWidget, }, + data () { + return { + loadMoreAlbumsUrl: this.nextAlbumsUrl, + additionalAlbums: [], + isLoadingMoreAlbums: false + } + }, computed: { contentFilter () { let self = this return this.$store.getters['moderation/artistFilters']().filter((e) => { return e.target.id === this.object.id })[0] + }, + allAlbums () { + return this.albums.concat(this.additionalAlbums) } }, - watch: { - id() { - this.fetchData() + methods: { + loadMoreAlbums (url) { + let self = this + self.isLoadingMoreAlbums = true + axios.get(url).then((response) => { + self.additionalAlbums = self.additionalAlbums.concat(response.data.results) + self.loadMoreAlbumsUrl = response.data.next + self.isLoadingMoreAlbums = false + }, (error) => { + self.isLoadingMoreAlbums = false + + }) } } }