deemixer/src/components/pages/Favorites.vue
2021-12-29 18:46:11 +01:00

305 lines
8.5 KiB
Vue

<template>
<div>
<h1 class="mb-8 text-5xl">
{{ $t('favorites.title') }}
<div
ref="reloadButton"
aria-label="reload"
class="inline-block clickable"
role="button"
@click="refreshFavorites"
>
<i :class="{ spin: isRefreshingFavorites }" class="material-icons">sync</i>
</div>
</h1>
<BaseTabs>
<BaseTab v-for="tab in tabs" :key="tab" :class="{ active: activeTab === tab }" @click="activeTab = tab">
{{ $tc(`globals.listTabs.${tab}`, 2) }}
</BaseTab>
</BaseTabs>
<button v-if="!activeTabEmpty" class="btn btn-primary" style="margin-bottom: 2rem" @click="downloadAllOfType">
{{ $t('globals.download', { thing: $tc(`globals.listTabs.${activeTab}N`, getTabLength()) }) }}
</button>
<div v-show="activeTab === 'playlist'">
<div v-if="(playlists.length + spotifyPlaylists.length) === 0">
<h1>{{ $t('favorites.noPlaylists') }}</h1>
</div>
<div v-if="(playlists.length + spotifyPlaylists.length) > 0" class="release-grid">
<div v-for="release in playlists" :key="release.id" class="release">
<router-link :to="{ name: 'Playlist', params: { id: release.id } }" class="cursor-pointer" tag="div">
<CoverContainer :cover="release.picture_medium" :link="release.link" is-rounded @click.stop="addToQueue" />
<p class="primary-text">{{ release.title }}</p>
</router-link>
<p class="secondary-text">
{{
`${$t('globals.by', { artist: release.creator.name })} - ${$tc(
'globals.listTabs.trackN',
release.nb_tracks
)}`
}}
</p>
</div>
<div v-for="release in spotifyPlaylists" :key="release.id" class="release">
<router-link :to="{ name: 'Spotify Playlist', params: { id: release.id } }" class="cursor-pointer" tag="div">
<CoverContainer :cover="release.picture_medium" :link="release.link" is-rounded @click.stop="addToQueue" />
<p class="primary-text">{{ release.title }}</p>
</router-link>
<p class="secondary-text">
{{
`${$t('globals.by', { artist: release.creator.name })} - ${$tc(
'globals.listTabs.trackN',
release.nb_tracks
)}`
}}
</p>
</div>
</div>
</div>
<div v-show="activeTab === 'album'">
<div v-if="albums.length === 0">
<h1>{{ $t('favorites.noAlbums') }}</h1>
</div>
<div v-if="albums.length > 0" class="release-grid">
<router-link
v-for="release in albums"
:key="release.id"
:to="{ name: 'Album', params: { id: release.id } }"
class="release clickable"
tag="div"
>
<CoverContainer :cover="release.cover_medium" :link="release.link" is-rounded @click.stop="addToQueue" />
<p class="primary-text">{{ release.title }}</p>
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
</router-link>
</div>
</div>
<div v-show="activeTab === 'artist'">
<div v-if="artists.length == 0">
<h1>{{ $t('favorites.noArtists') }}</h1>
</div>
<div v-if="artists.length > 0" class="release-grid">
<router-link
v-for="release in artists"
:key="release.id"
:to="{ name: 'Artist', params: { id: release.id } }"
class="release clickable"
tag="div"
>
<CoverContainer :cover="release.picture_medium" :link="release.link" is-circle @click.stop="addToQueue" />
<p class="primary-text">{{ release.name }}</p>
</router-link>
</div>
</div>
<div v-show="activeTab === 'track'">
<div v-if="tracks.length == 0">
<h1>{{ $t('favorites.noTracks') }}</h1>
</div>
<table v-if="tracks.length > 0" class="table">
<tr v-for="track in tracks" class="track_row">
<td :class="{ first: track.position === 1 }" class="p-3 text-center cursor-default">
{{ track.position }}
</td>
<td>
<span
:data-preview="track.preview"
class="relative inline-block rounded cursor-pointer"
@click="playPausePreview"
>
<PreviewControls v-if="track.preview" />
<img :src="track.album.cover_small" class="rounded coverart" />
</span>
</td>
<td class="table__cell--large">
{{
track.title +
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
}}
</td>
<router-link
:to="{ name: 'Artist', params: { id: track.artist.id } }"
class="table__cell table__cell--medium table__cell--center clickable"
tag="td"
>
{{ track.artist.name }}
</router-link>
<router-link
:to="{ name: 'Album', params: { id: track.album.id } }"
class="table__cell--medium table__cell--center clickable"
tag="td"
>
{{ track.album.title }}
</router-link>
<td class="table__cell--small">
{{ convertDuration(track.duration) }}
</td>
<td
:data-link="track.link"
aria-label="download"
class="cursor-pointer group"
role="button"
@click.stop="addToQueue"
>
<div class="table__cell-content table__cell-content--vertical-center">
<i
:title="$t('globals.download_hint')"
class="transition-colors duration-150 ease-in-out material-icons group-hover:text-primary"
>
get_app
</i>
</div>
</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import { defineComponent, reactive, toRefs, watch } from '@vue/composition-api'
import PreviewControls from '@components/globals/PreviewControls.vue'
import CoverContainer from '@components/globals/CoverContainer.vue'
import { playPausePreview } from '@components/globals/TheTrackPreview.vue'
import { BaseTab, BaseTabs } from '@components/globals/BaseTabs'
import { aggregateDownloadLinks, sendAddToQueue } from '@/utils/downloads'
import { convertDuration } from '@/utils/utils'
import { toast } from '@/utils/toasts'
import { useFavorites } from '@/use/favorites'
export default defineComponent({
components: {
PreviewControls,
CoverContainer,
BaseTabs,
BaseTab
},
setup(_, ctx) {
const state = reactive({
activeTab: 'playlist',
tabs: ['playlist', 'album', 'artist', 'track']
})
const {
favoriteArtists,
favoriteAlbums,
favoriteSpotifyPlaylists,
favoritePlaylists,
favoriteTracks,
lovedTracksPlaylist,
isRefreshingFavorites,
refreshFavorites
} = useFavorites()
refreshFavorites({ isInitial: true }).catch(console.error)
watch(isRefreshingFavorites, (newVal, oldVal) => {
// If oldVal is true and newOne is false, it means that a refreshing has just terminated
// because isRefreshingFavorites represents the status of the refresh functionality
const isRefreshingTerminated = oldVal && !newVal
if (!isRefreshingTerminated) return
toast(ctx.root.$t('toasts.refreshFavs'), 'done', true)
})
return {
...toRefs(state),
tracks: favoriteTracks,
albums: favoriteAlbums,
artists: favoriteArtists,
playlists: favoritePlaylists,
spotifyPlaylists: favoriteSpotifyPlaylists,
lovedTracks: lovedTracksPlaylist,
refreshFavorites,
isRefreshingFavorites
}
},
computed: {
activeTabEmpty() {
const toCheck = this.getActiveRelease()
return toCheck?.length === 0
}
},
methods: {
playPausePreview,
convertDuration,
downloadAllOfType() {
try {
const toDownload = this.getActiveRelease()
if (this.activeTab === 'track') {
if (this.lovedTracks){
sendAddToQueue(this.lovedTracks)
} else {
const lovedTracks = this.getLovedTracksPlaylist()
sendAddToQueue(lovedTracks.link)
}
} else {
sendAddToQueue(aggregateDownloadLinks(toDownload))
}
} catch (error) {
console.error(error.message)
}
},
addToQueue(e) {
sendAddToQueue(e.currentTarget.dataset.link)
},
getActiveRelease(tab = this.activeTab) {
let toDownload
switch (tab) {
case 'playlist':
toDownload = this.playlists
toDownload += this.spotifyPlaylists
break
case 'album':
toDownload = this.albums
break
case 'artist':
toDownload = this.artists
break
case 'track':
toDownload = this.tracks
break
default:
break
}
return toDownload
},
getTabLength(tab = this.activeTab) {
let total = this[`${tab}s`]?.length
if (tab === 'playlist') {
total += this.spotifyPlaylists.length
}
return total || 0
},
getLovedTracksPlaylist() {
const lovedTracks = this.playlists.filter(playlist => {
return playlist.is_loved_track
})
if (lovedTracks.length !== 0) {
return lovedTracks[0]
} else {
toast(this.$t('toasts.noLovedPlaylist'), 'warning', true)
throw new Error('No loved tracks playlist!')
}
}
}
})
</script>