build: v1.5.2; fix: spotify favorites playlist not showing in Favorites page until the refresh button is clicked (closes #21); refactor: favorites logic
This commit is contained in:
		
							parent
							
								
									835b0e9f8d
								
							
						
					
					
						commit
						d752efa30f
					
				
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -3,13 +3,13 @@ | |||||||
| 		<h1 class="mb-8 text-5xl"> | 		<h1 class="mb-8 text-5xl"> | ||||||
| 			{{ $t('favorites.title') }} | 			{{ $t('favorites.title') }} | ||||||
| 			<div | 			<div | ||||||
| 				@click="reloadTabs" | 				@click="refreshFavorites" | ||||||
| 				class="inline-block clickable reload-button" | 				class="inline-block clickable" | ||||||
| 				ref="reloadButton" | 				ref="reloadButton" | ||||||
| 				role="button" | 				role="button" | ||||||
| 				aria-label="reload" | 				aria-label="reload" | ||||||
| 			> | 			> | ||||||
| 				<i class="material-icons">sync</i> | 				<i class="material-icons" :class="{ spin: isRefreshingFavorites }">sync</i> | ||||||
| 			</div> | 			</div> | ||||||
| 		</h1> | 		</h1> | ||||||
| 
 | 
 | ||||||
| @ -20,10 +20,10 @@ | |||||||
| 		</BaseTabs> | 		</BaseTabs> | ||||||
| 
 | 
 | ||||||
| 		<button class="btn btn-primary" v-if="!activeTabEmpty" style="margin-bottom: 2rem" @click="downloadAllOfType"> | 		<button class="btn btn-primary" v-if="!activeTabEmpty" style="margin-bottom: 2rem" @click="downloadAllOfType"> | ||||||
| 			{{ $t('globals.download', { thing: $tc(`globals.listTabs.${activeTab}N`, getTabLenght()) }) }} | 			{{ $t('globals.download', { thing: $tc(`globals.listTabs.${activeTab}N`, getTabLength()) }) }} | ||||||
| 		</button> | 		</button> | ||||||
| 
 | 
 | ||||||
| 		<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'playlist' }"> | 		<div v-show="activeTab === 'playlist'"> | ||||||
| 			<div v-if="playlists.length == 0"> | 			<div v-if="playlists.length == 0"> | ||||||
| 				<h1>{{ $t('favorites.noPlaylists') }}</h1> | 				<h1>{{ $t('favorites.noPlaylists') }}</h1> | ||||||
| 			</div> | 			</div> | ||||||
| @ -62,7 +62,7 @@ | |||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 
 | 
 | ||||||
| 		<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'album' }"> | 		<div v-show="activeTab === 'album'"> | ||||||
| 			<div v-if="albums.length == 0"> | 			<div v-if="albums.length == 0"> | ||||||
| 				<h1>{{ $t('favorites.noAlbums') }}</h1> | 				<h1>{{ $t('favorites.noAlbums') }}</h1> | ||||||
| 			</div> | 			</div> | ||||||
| @ -81,7 +81,7 @@ | |||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 
 | 
 | ||||||
| 		<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'artist' }"> | 		<div v-show="activeTab === 'artist'"> | ||||||
| 			<div v-if="artists.length == 0"> | 			<div v-if="artists.length == 0"> | ||||||
| 				<h1>{{ $t('favorites.noArtists') }}</h1> | 				<h1>{{ $t('favorites.noArtists') }}</h1> | ||||||
| 			</div> | 			</div> | ||||||
| @ -99,7 +99,7 @@ | |||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 
 | 
 | ||||||
| 		<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'track' }"> | 		<div v-show="activeTab === 'track'"> | ||||||
| 			<div v-if="tracks.length == 0"> | 			<div v-if="tracks.length == 0"> | ||||||
| 				<h1>{{ $t('favorites.noTracks') }}</h1> | 				<h1>{{ $t('favorites.noTracks') }}</h1> | ||||||
| 			</div> | 			</div> | ||||||
| @ -163,86 +163,70 @@ | |||||||
| 	</div> | 	</div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> |  | ||||||
| .favorites_tabcontent { |  | ||||||
| 	display: none; |  | ||||||
| 
 |  | ||||||
| 	&--active { |  | ||||||
| 		display: block; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .reload-button { |  | ||||||
| 	&.spin { |  | ||||||
| 		i { |  | ||||||
| 			animation: spin 500ms infinite ease-out reverse; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| 
 |  | ||||||
| <script> | <script> | ||||||
| import { socket } from '@/utils/socket' | import { defineComponent, onMounted, reactive, toRefs, watchEffect, ref, computed, watch } from '@vue/composition-api' | ||||||
| import { sendAddToQueue, aggregateDownloadLinks } from '@/utils/downloads' |  | ||||||
| import { convertDuration } from '@/utils/utils' |  | ||||||
| import { toast } from '@/utils/toasts' |  | ||||||
| import { getFavoritesData } from '@/data/favorites' |  | ||||||
| 
 | 
 | ||||||
| import PreviewControls from '@components/globals/PreviewControls.vue' | import PreviewControls from '@components/globals/PreviewControls.vue' | ||||||
| import CoverContainer from '@components/globals/CoverContainer.vue' | import CoverContainer from '@components/globals/CoverContainer.vue' | ||||||
| import { playPausePreview } from '@components/globals/TheTrackPreview.vue' | import { playPausePreview } from '@components/globals/TheTrackPreview.vue' | ||||||
| import { BaseTabs, BaseTab } from '@components/globals/BaseTabs' | import { BaseTabs, BaseTab } from '@components/globals/BaseTabs' | ||||||
| 
 | 
 | ||||||
| export default { | import { sendAddToQueue, aggregateDownloadLinks } from '@/utils/downloads' | ||||||
|  | import { convertDuration } from '@/utils/utils' | ||||||
|  | import { toast } from '@/utils/toasts' | ||||||
|  | import { useFavorites } from '@/use/favorites' | ||||||
|  | 
 | ||||||
|  | export default defineComponent({ | ||||||
| 	components: { | 	components: { | ||||||
| 		PreviewControls, | 		PreviewControls, | ||||||
| 		CoverContainer, | 		CoverContainer, | ||||||
| 		BaseTabs, | 		BaseTabs, | ||||||
| 		BaseTab | 		BaseTab | ||||||
| 	}, | 	}, | ||||||
| 	data() { | 	setup(props, ctx) { | ||||||
| 		return { | 		const state = reactive({ | ||||||
| 			tracks: [], |  | ||||||
| 			albums: [], |  | ||||||
| 			artists: [], |  | ||||||
| 			playlists: [], |  | ||||||
| 			spotifyPlaylists: [], |  | ||||||
| 			activeTab: 'playlist', | 			activeTab: 'playlist', | ||||||
| 			tabs: ['playlist', 'album', 'artist', 'track'] | 			tabs: ['playlist', 'album', 'artist', 'track'] | ||||||
|  | 		}) | ||||||
|  | 		const { | ||||||
|  | 			favoriteArtists, | ||||||
|  | 			favoriteAlbums, | ||||||
|  | 			favoriteSpotifyPlaylists, | ||||||
|  | 			favoritePlaylists, | ||||||
|  | 			favoriteTracks, | ||||||
|  | 			isRefreshingFavorites, | ||||||
|  | 			refreshFavorites | ||||||
|  | 		} = useFavorites() | ||||||
|  | 		const reloadButton = computed(() => ctx.refs.reloadButton) | ||||||
|  | 
 | ||||||
|  | 		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, | ||||||
|  | 			refreshFavorites, | ||||||
|  | 			isRefreshingFavorites | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	computed: { | 	computed: { | ||||||
| 		activeTabEmpty() { | 		activeTabEmpty() { | ||||||
| 			let toCheck = this.getActiveRelease() | 			let toCheck = this.getActiveRelease() | ||||||
| 
 | 
 | ||||||
| 			return toCheck.length === 0 | 			return toCheck?.length === 0 | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	async created() { |  | ||||||
| 		const favoritesData = await getFavoritesData() |  | ||||||
| 
 |  | ||||||
| 		// TODO Change with isLoggedIn vuex getter |  | ||||||
| 		if (Object.entries(favoritesData).length === 0) return |  | ||||||
| 
 |  | ||||||
| 		this.setFavorites(favoritesData) |  | ||||||
| 	}, |  | ||||||
| 	mounted() { |  | ||||||
| 		socket.on('updated_userFavorites', this.updated_userFavorites) |  | ||||||
| 		socket.on('updated_userSpotifyPlaylists', this.updated_userSpotifyPlaylists) |  | ||||||
| 		socket.on('updated_userPlaylists', this.updated_userPlaylists) |  | ||||||
| 		socket.on('updated_userAlbums', this.updated_userAlbums) |  | ||||||
| 		socket.on('updated_userArtist', this.updated_userArtist) |  | ||||||
| 		socket.on('updated_userTracks', this.updated_userTracks) |  | ||||||
| 
 |  | ||||||
| 		this.$on('hook:destroyed', () => { |  | ||||||
| 			socket.off('updated_userFavorites') |  | ||||||
| 			socket.off('updated_userSpotifyPlaylists') |  | ||||||
| 			socket.off('updated_userPlaylists') |  | ||||||
| 			socket.off('updated_userAlbums') |  | ||||||
| 			socket.off('updated_userArtist') |  | ||||||
| 			socket.off('updated_userTracks') |  | ||||||
| 		}) |  | ||||||
| 	}, |  | ||||||
| 	methods: { | 	methods: { | ||||||
| 		playPausePreview, | 		playPausePreview, | ||||||
| 		convertDuration, | 		convertDuration, | ||||||
| @ -264,54 +248,9 @@ export default { | |||||||
| 		addToQueue(e) { | 		addToQueue(e) { | ||||||
| 			sendAddToQueue(e.currentTarget.dataset.link) | 			sendAddToQueue(e.currentTarget.dataset.link) | ||||||
| 		}, | 		}, | ||||||
| 		updated_userSpotifyPlaylists(data) { |  | ||||||
| 			this.spotifyPlaylists = data |  | ||||||
| 		}, |  | ||||||
| 		updated_userPlaylists(data) { |  | ||||||
| 			this.playlists = data |  | ||||||
| 		}, |  | ||||||
| 		updated_userAlbums(data) { |  | ||||||
| 			this.albums = data |  | ||||||
| 		}, |  | ||||||
| 		updated_userArtist(data) { |  | ||||||
| 			this.artists = data |  | ||||||
| 		}, |  | ||||||
| 		updated_userTracks(data) { |  | ||||||
| 			this.tracks = data |  | ||||||
| 		}, |  | ||||||
| 		reloadTabs() { |  | ||||||
| 			this.$refs.reloadButton.classList.add('spin') |  | ||||||
| 
 |  | ||||||
| 			socket.emit('update_userFavorites') |  | ||||||
| 
 |  | ||||||
| 			if (localStorage.getItem('spotifyUser')) { |  | ||||||
| 				socket.emit('update_userSpotifyPlaylists', localStorage.getItem('spotifyUser')) |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		updated_userFavorites(data) { |  | ||||||
| 			this.setFavorites(data) |  | ||||||
| 
 |  | ||||||
| 			// Removing animation class only when the animation has completed an iteration |  | ||||||
| 			// Prevents animation ugly stutter |  | ||||||
| 			this.$refs.reloadButton.addEventListener( |  | ||||||
| 				'animationiteration', |  | ||||||
| 				() => { |  | ||||||
| 					this.$refs.reloadButton.classList.remove('spin') |  | ||||||
| 					toast(this.$t('toasts.refreshFavs'), 'done', true) |  | ||||||
| 				}, |  | ||||||
| 				{ once: true } |  | ||||||
| 			) |  | ||||||
| 		}, |  | ||||||
| 		setFavorites(data) { |  | ||||||
| 			const { tracks, albums, artists, playlists } = data |  | ||||||
| 
 |  | ||||||
| 			this.tracks = tracks |  | ||||||
| 			this.albums = albums |  | ||||||
| 			this.artists = artists |  | ||||||
| 			this.playlists = playlists |  | ||||||
| 		}, |  | ||||||
| 		getActiveRelease(tab = this.activeTab) { | 		getActiveRelease(tab = this.activeTab) { | ||||||
| 			let toDownload | 			let toDownload | ||||||
|  | 			// console.log({ tab, play: this.playlists }) | ||||||
| 
 | 
 | ||||||
| 			switch (tab) { | 			switch (tab) { | ||||||
| 				case 'playlist': | 				case 'playlist': | ||||||
| @ -333,11 +272,11 @@ export default { | |||||||
| 
 | 
 | ||||||
| 			return toDownload | 			return toDownload | ||||||
| 		}, | 		}, | ||||||
| 		getTabLenght(tab = this.activeTab) { | 		getTabLength(tab = this.activeTab) { | ||||||
| 			let total = this[`${tab}s`].length | 			let total = this[`${tab}s`]?.length | ||||||
| 			// TODO: Add Spotify playlists to downlaod queue as well | 			// TODO: Add Spotify playlists to downlaod queue as well | ||||||
| 			//if (tab === "playlist") total += this.spotifyPlaylists.length | 			//if (tab === "playlist") total += this.spotifyPlaylists.length | ||||||
| 			return total | 			return total || 0 | ||||||
| 		}, | 		}, | ||||||
| 		getLovedTracksPlaylist() { | 		getLovedTracksPlaylist() { | ||||||
| 			let lovedTracks = this.playlists.filter(playlist => { | 			let lovedTracks = this.playlists.filter(playlist => { | ||||||
| @ -351,5 +290,5 @@ export default { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | }) | ||||||
| </script> | </script> | ||||||
|  | |||||||
| @ -1,22 +0,0 @@ | |||||||
| import { socket } from '@/utils/socket' |  | ||||||
| 
 |  | ||||||
| let favoritesData = {} |  | ||||||
| let cached = false |  | ||||||
| 
 |  | ||||||
| export function getFavoritesData() { |  | ||||||
| 	if (cached) { |  | ||||||
| 		return favoritesData |  | ||||||
| 	} else { |  | ||||||
| 		socket.emit('get_favorites_data') |  | ||||||
| 
 |  | ||||||
| 		return new Promise((resolve, reject) => { |  | ||||||
| 			socket.on('init_favorites', data => { |  | ||||||
| 				favoritesData = data |  | ||||||
| 				cached = true |  | ||||||
| 
 |  | ||||||
| 				socket.off('init_favorites') |  | ||||||
| 				resolve(data) |  | ||||||
| 			}) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -6,10 +6,17 @@ const getDefaultState = () => ({ | |||||||
| 		name: '', | 		name: '', | ||||||
| 		picture: '' | 		picture: '' | ||||||
| 	}, | 	}, | ||||||
|  | 	spotifyUser: { | ||||||
|  | 		id: localStorage.getItem('spotifyUser'), | ||||||
|  | 		name: null, | ||||||
|  | 		picture: null | ||||||
|  | 	}, | ||||||
| 	clientMode: false | 	clientMode: false | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| const state = getDefaultState() | const state = () => { | ||||||
|  | 	return getDefaultState() | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| const actions = { | const actions = { | ||||||
| 	login({ commit, dispatch }, payload) { | 	login({ commit, dispatch }, payload) { | ||||||
| @ -51,8 +58,11 @@ const actions = { | |||||||
| const getters = { | const getters = { | ||||||
| 	getARL: state => state.arl, | 	getARL: state => state.arl, | ||||||
| 	getUser: state => state.user, | 	getUser: state => state.user, | ||||||
|  | 	getSpotifyUser: state => state.spotifyUser, | ||||||
| 	getClientMode: state => state.clientMode, | 	getClientMode: state => state.clientMode, | ||||||
| 	isLoggedIn: state => !!state.arl | 
 | ||||||
|  | 	isLoggedIn: state => !!state.arl, | ||||||
|  | 	isLoggedWithSpotify: state => !!state.spotifyUser.id | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const mutations = { | const mutations = { | ||||||
|  | |||||||
| @ -22,6 +22,10 @@ | |||||||
| 	width: 156px; | 	width: 156px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .spin { | ||||||
|  | 	animation: spin 500ms infinite ease-out reverse; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @keyframes spin { | @keyframes spin { | ||||||
| 	0% { | 	0% { | ||||||
| 		transform: rotate(0deg); | 		transform: rotate(0deg); | ||||||
|  | |||||||
							
								
								
									
										79
									
								
								src/use/favorites.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/use/favorites.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | |||||||
|  | import { ref } from '@vue/composition-api' | ||||||
|  | 
 | ||||||
|  | import store from '@/store' | ||||||
|  | import { socket } from '@/utils/socket' | ||||||
|  | 
 | ||||||
|  | const favoriteArtists = ref([]) | ||||||
|  | const favoriteAlbums = ref([]) | ||||||
|  | const favoriteSpotifyPlaylists = ref([]) | ||||||
|  | const favoritePlaylists = ref([]) | ||||||
|  | const favoriteTracks = ref([]) | ||||||
|  | 
 | ||||||
|  | const isRefreshingFavorites = ref(false) | ||||||
|  | 
 | ||||||
|  | if (store.getters.isLoggedIn) { | ||||||
|  | 	refreshFavorites({ isInitial: true }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function refreshFavorites({ isInitial = false }) { | ||||||
|  | 	if (!isInitial) { | ||||||
|  | 		isRefreshingFavorites.value = true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	socket.emit('get_favorites_data') | ||||||
|  | 
 | ||||||
|  | 	if (store.getters.isLoggedWithSpotify) { | ||||||
|  | 		socket.emit('update_userSpotifyPlaylists', store.getters.getSpotifyUser.id) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function useFavorites() { | ||||||
|  | 	return { | ||||||
|  | 		favoriteArtists, | ||||||
|  | 		favoriteAlbums, | ||||||
|  | 		favoriteSpotifyPlaylists, | ||||||
|  | 		favoritePlaylists, | ||||||
|  | 		favoriteTracks, | ||||||
|  | 		isRefreshingFavorites, | ||||||
|  | 		refreshFavorites | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function setAllFavorites(data) { | ||||||
|  | 	const { tracks, albums, artists, playlists } = data | ||||||
|  | 
 | ||||||
|  | 	favoriteArtists.value = artists | ||||||
|  | 	favoriteAlbums.value = albums | ||||||
|  | 	favoritePlaylists.value = playlists | ||||||
|  | 	favoriteTracks.value = tracks | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | socket.on('updated_userFavorites', data => { | ||||||
|  | 	setAllFavorites(data) | ||||||
|  | 	// Commented out because the corresponding emit function is never called at the moment
 | ||||||
|  | 	// therefore isRefreshingFavorites is never set to true
 | ||||||
|  | 	// isRefreshingFavorites.value = false
 | ||||||
|  | }) | ||||||
|  | socket.on('init_favorites', data => { | ||||||
|  | 	setAllFavorites(data) | ||||||
|  | 	isRefreshingFavorites.value = false | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | socket.on('updated_userSpotifyPlaylists', data => { | ||||||
|  | 	favoriteSpotifyPlaylists.value = data | ||||||
|  | }) | ||||||
|  | socket.on('updated_userSpotifyPlaylists', data => { | ||||||
|  | 	favoriteSpotifyPlaylists.value = data | ||||||
|  | }) | ||||||
|  | socket.on('updated_userPlaylists', data => { | ||||||
|  | 	favoritePlaylists.value = data | ||||||
|  | }) | ||||||
|  | socket.on('updated_userAlbums', data => { | ||||||
|  | 	favoriteAlbums.value = data | ||||||
|  | }) | ||||||
|  | socket.on('updated_userArtist', data => { | ||||||
|  | 	favoriteArtists.value = data | ||||||
|  | }) | ||||||
|  | socket.on('updated_userTracks', data => { | ||||||
|  | 	favoriteTracks.value = data | ||||||
|  | }) | ||||||
| @ -19,7 +19,3 @@ export function aggregateDownloadLinks(releases) { | |||||||
| 
 | 
 | ||||||
| 	return links.join(';') | 	return links.join(';') | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // export default {
 |  | ||||||
| // 	sendAddToQueue
 |  | ||||||
| // }
 |  | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user