mirror of
https://github.com/koel/koel
synced 2024-12-01 00:09:17 +00:00
feat: use composables for Router
This commit is contained in:
parent
246fff58d3
commit
bc5081cd0f
37 changed files with 179 additions and 205 deletions
|
@ -26,11 +26,11 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, nextTick, onMounted, provide, ref, watch } from 'vue'
|
import { defineAsyncComponent, nextTick, onMounted, provide, ref, watch } from 'vue'
|
||||||
import { hideOverlay, requireInjection, showOverlay } from '@/utils'
|
import { hideOverlay, showOverlay } from '@/utils'
|
||||||
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
|
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
|
||||||
import { authService, socketListener, socketService, uploadService } from '@/services'
|
import { authService, socketListener, socketService, uploadService } from '@/services'
|
||||||
import { CurrentSongKey, DialogBoxKey, MessageToasterKey, RouterKey } from '@/symbols'
|
import { CurrentSongKey, DialogBoxKey, MessageToasterKey } from '@/symbols'
|
||||||
import { useNetworkStatus } from '@/composables'
|
import { useNetworkStatus, useRouter } from '@/composables'
|
||||||
|
|
||||||
import DialogBox from '@/components/ui/DialogBox.vue'
|
import DialogBox from '@/components/ui/DialogBox.vue'
|
||||||
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
import MessageToaster from '@/components/ui/MessageToaster.vue'
|
||||||
|
@ -62,6 +62,7 @@ const currentSong = ref<Song | null>(null)
|
||||||
const authenticated = ref(false)
|
const authenticated = ref(false)
|
||||||
const showDropZone = ref(false)
|
const showDropZone = ref(false)
|
||||||
|
|
||||||
|
const { isCurrentScreen } = useRouter()
|
||||||
const { offline } = useNetworkStatus()
|
const { offline } = useNetworkStatus()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,10 +116,8 @@ const init = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
|
|
||||||
const onDragOver = (e: DragEvent) => {
|
const onDragOver = (e: DragEvent) => {
|
||||||
showDropZone.value = Boolean(e.dataTransfer?.types.includes('Files')) && router.$currentRoute.value.screen !== 'Upload'
|
showDropZone.value = Boolean(e.dataTransfer?.types.includes('Files')) && !isCurrentScreen('Upload')
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => queueStore.current, song => song && (currentSong.value = song))
|
watch(() => queueStore.current, song => song && (currentSong.value = song))
|
||||||
|
|
|
@ -42,16 +42,14 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, toRef, toRefs } from 'vue'
|
import { computed, toRef, toRefs } from 'vue'
|
||||||
import { eventBus, requireInjection, secondsToHumanReadable } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
||||||
import { downloadService, playbackService } from '@/services'
|
import { downloadService, playbackService } from '@/services'
|
||||||
import { useDraggable } from '@/composables'
|
import { useDraggable, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ArtistAlbumCard from '@/components/ui/ArtistAlbumCard.vue'
|
import ArtistAlbumCard from '@/components/ui/ArtistAlbumCard.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const { startDragging } = useDraggable('album')
|
const { startDragging } = useDraggable('album')
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ album: Album, layout?: ArtistAlbumCardLayout }>(), { layout: 'full' })
|
const props = withDefaults(defineProps<{ album: Album, layout?: ArtistAlbumCardLayout }>(), { layout: 'full' })
|
||||||
|
@ -59,13 +57,12 @@ const { album, layout } = toRefs(props)
|
||||||
|
|
||||||
const allowDownload = toRef(commonStore.state, 'allow_download')
|
const allowDownload = toRef(commonStore.state, 'allow_download')
|
||||||
|
|
||||||
const duration = computed(() => secondsToHumanReadable(album.value.length))
|
|
||||||
const isStandardArtist = computed(() => artistStore.isStandard(album.value.artist_id))
|
const isStandardArtist = computed(() => artistStore.isStandard(album.value.artist_id))
|
||||||
const showing = computed(() => !albumStore.isUnknown(album.value))
|
const showing = computed(() => !albumStore.isUnknown(album.value))
|
||||||
|
|
||||||
const shuffle = async () => {
|
const shuffle = async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value), true /* shuffled */)
|
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value), true /* shuffled */)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
const download = () => downloadService.fromAlbum(album.value)
|
const download = () => downloadService.fromAlbum(album.value)
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
import { computed, ref, toRef } from 'vue'
|
import { computed, ref, toRef } from 'vue'
|
||||||
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
||||||
import { downloadService, playbackService } from '@/services'
|
import { downloadService, playbackService } from '@/services'
|
||||||
import { useContextMenu } from '@/composables'
|
import { useContextMenu, useRouter } from '@/composables'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
|
const { go } = useRouter()
|
||||||
const { context, base, ContextMenuBase, open, trigger } = useContextMenu()
|
const { context, base, ContextMenuBase, open, trigger } = useContextMenu()
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
|
|
||||||
const album = ref<Album>()
|
const album = ref<Album>()
|
||||||
const allowDownload = toRef(commonStore.state, 'allow_download')
|
const allowDownload = toRef(commonStore.state, 'allow_download')
|
||||||
|
@ -36,12 +35,12 @@ const isStandardArtist = computed(() => {
|
||||||
|
|
||||||
const play = () => trigger(async () => {
|
const play = () => trigger(async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value!))
|
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value!))
|
||||||
router.go('queue')
|
go('queue')
|
||||||
})
|
})
|
||||||
|
|
||||||
const shuffle = () => trigger(async () => {
|
const shuffle = () => trigger(async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value!), true)
|
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value!), true)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
})
|
})
|
||||||
|
|
||||||
const viewAlbumDetails = () => trigger(() => router.go(`album/${album.value!.id}`))
|
const viewAlbumDetails = () => trigger(() => router.go(`album/${album.value!.id}`))
|
||||||
|
|
|
@ -34,26 +34,23 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { faCirclePlay } from '@fortawesome/free-solid-svg-icons'
|
import { faCirclePlay } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, defineAsyncComponent, ref, toRefs, watch } from 'vue'
|
import { computed, defineAsyncComponent, ref, toRefs, watch } from 'vue'
|
||||||
import { useThirdPartyServices } from '@/composables'
|
|
||||||
import { songStore } from '@/stores'
|
import { songStore } from '@/stores'
|
||||||
import { mediaInfoService, playbackService } from '@/services'
|
import { mediaInfoService, playbackService } from '@/services'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useRouter, useThirdPartyServices } from '@/composables'
|
||||||
|
|
||||||
import AlbumThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
import AlbumThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
||||||
import { requireInjection } from '@/utils'
|
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
|
|
||||||
const TrackList = defineAsyncComponent(() => import('@/components/album/AlbumTrackList.vue'))
|
const TrackList = defineAsyncComponent(() => import('@/components/album/AlbumTrackList.vue'))
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ album: Album, mode?: MediaInfoDisplayMode }>(), { mode: 'aside' })
|
const props = withDefaults(defineProps<{ album: Album, mode?: MediaInfoDisplayMode }>(), { mode: 'aside' })
|
||||||
const { album, mode } = toRefs(props)
|
const { album, mode } = toRefs(props)
|
||||||
|
|
||||||
|
const { go } = useRouter()
|
||||||
|
const { useLastfm } = useThirdPartyServices()
|
||||||
|
|
||||||
const info = ref<AlbumInfo | null>(null)
|
const info = ref<AlbumInfo | null>(null)
|
||||||
const showingFullWiki = ref(false)
|
const showingFullWiki = ref(false)
|
||||||
|
|
||||||
const { useLastfm } = useThirdPartyServices()
|
|
||||||
|
|
||||||
watch(album, async () => {
|
watch(album, async () => {
|
||||||
showingFullWiki.value = false
|
showingFullWiki.value = false
|
||||||
info.value = null
|
info.value = null
|
||||||
|
@ -65,7 +62,7 @@ const showFull = computed(() => !showSummary.value)
|
||||||
|
|
||||||
const play = async () => {
|
const play = async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value))
|
playbackService.queueAndPlay(await songStore.fetchForAlbum(album.value))
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -39,16 +39,14 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, toRef, toRefs } from 'vue'
|
import { computed, toRef, toRefs } from 'vue'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { artistStore, commonStore, songStore } from '@/stores'
|
import { artistStore, commonStore, songStore } from '@/stores'
|
||||||
import { downloadService, playbackService } from '@/services'
|
import { downloadService, playbackService } from '@/services'
|
||||||
import { useDraggable } from '@/composables'
|
import { useDraggable, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ArtistAlbumCard from '@/components/ui/ArtistAlbumCard.vue'
|
import ArtistAlbumCard from '@/components/ui/ArtistAlbumCard.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const { startDragging } = useDraggable('artist')
|
const { startDragging } = useDraggable('artist')
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ artist: Artist, layout?: ArtistAlbumCardLayout }>(), { layout: 'full' })
|
const props = withDefaults(defineProps<{ artist: Artist, layout?: ArtistAlbumCardLayout }>(), { layout: 'full' })
|
||||||
|
@ -60,7 +58,7 @@ const showing = computed(() => artistStore.isStandard(artist.value))
|
||||||
|
|
||||||
const shuffle = async () => {
|
const shuffle = async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value), true /* shuffled */)
|
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value), true /* shuffled */)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
const download = () => downloadService.fromArtist(artist.value)
|
const download = () => downloadService.fromArtist(artist.value)
|
||||||
|
|
|
@ -19,12 +19,11 @@
|
||||||
import { computed, ref, toRef } from 'vue'
|
import { computed, ref, toRef } from 'vue'
|
||||||
import { artistStore, commonStore, songStore } from '@/stores'
|
import { artistStore, commonStore, songStore } from '@/stores'
|
||||||
import { downloadService, playbackService } from '@/services'
|
import { downloadService, playbackService } from '@/services'
|
||||||
import { useContextMenu } from '@/composables'
|
import { useContextMenu, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
import { eventBus } from '@/utils'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
|
||||||
|
|
||||||
|
const { go } = useRouter()
|
||||||
const { context, base, ContextMenuBase, open, trigger } = useContextMenu()
|
const { context, base, ContextMenuBase, open, trigger } = useContextMenu()
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
|
|
||||||
const artist = ref<Artist>()
|
const artist = ref<Artist>()
|
||||||
const allowDownload = toRef(commonStore.state, 'allow_download')
|
const allowDownload = toRef(commonStore.state, 'allow_download')
|
||||||
|
@ -36,15 +35,15 @@ const isStandardArtist = computed(() =>
|
||||||
|
|
||||||
const play = () => trigger(async () => {
|
const play = () => trigger(async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value!))
|
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value!))
|
||||||
router.go('queue')
|
go('queue')
|
||||||
})
|
})
|
||||||
|
|
||||||
const shuffle = () => trigger(async () => {
|
const shuffle = () => trigger(async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value!), true)
|
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value!), true)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
})
|
})
|
||||||
|
|
||||||
const viewArtistDetails = () => trigger(() => router.go(`artist/${artist.value!.id}`))
|
const viewArtistDetails = () => trigger(() => go(`artist/${artist.value!.id}`))
|
||||||
const download = () => trigger(() => downloadService.fromArtist(artist.value!))
|
const download = () => trigger(() => downloadService.fromArtist(artist.value!))
|
||||||
|
|
||||||
eventBus.on('ARTIST_CONTEXT_MENU_REQUESTED', async (e, _artist) => {
|
eventBus.on('ARTIST_CONTEXT_MENU_REQUESTED', async (e, _artist) => {
|
||||||
|
|
|
@ -33,18 +33,15 @@
|
||||||
import { faCirclePlay } from '@fortawesome/free-solid-svg-icons'
|
import { faCirclePlay } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, ref, toRefs, watch } from 'vue'
|
import { computed, ref, toRefs, watch } from 'vue'
|
||||||
import { mediaInfoService, playbackService } from '@/services'
|
import { mediaInfoService, playbackService } from '@/services'
|
||||||
import { useThirdPartyServices } from '@/composables'
|
import { useRouter, useThirdPartyServices } from '@/composables'
|
||||||
import { songStore } from '@/stores'
|
import { songStore } from '@/stores'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
import { requireInjection } from '@/utils'
|
|
||||||
|
|
||||||
import ArtistThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
import ArtistThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ artist: Artist, mode?: MediaInfoDisplayMode }>(), { mode: 'aside' })
|
const props = withDefaults(defineProps<{ artist: Artist, mode?: MediaInfoDisplayMode }>(), { mode: 'aside' })
|
||||||
const { artist, mode } = toRefs(props)
|
const { artist, mode } = toRefs(props)
|
||||||
|
|
||||||
|
const { go } = useRouter()
|
||||||
const { useLastfm } = useThirdPartyServices()
|
const { useLastfm } = useThirdPartyServices()
|
||||||
|
|
||||||
const info = ref<ArtistInfo | null>(null)
|
const info = ref<ArtistInfo | null>(null)
|
||||||
|
@ -61,7 +58,7 @@ const showFull = computed(() => !showSummary.value)
|
||||||
|
|
||||||
const play = async () => {
|
const play = async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value))
|
playbackService.queueAndPlay(await songStore.fetchForArtist(artist.value))
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@
|
||||||
import { defineAsyncComponent, onMounted, ref, toRef } from 'vue'
|
import { defineAsyncComponent, onMounted, ref, toRef } from 'vue'
|
||||||
import { requireInjection } from '@/utils'
|
import { requireInjection } from '@/utils'
|
||||||
import { preferenceStore } from '@/stores'
|
import { preferenceStore } from '@/stores'
|
||||||
import { useThirdPartyServices } from '@/composables'
|
import { useRouter, useThirdPartyServices } from '@/composables'
|
||||||
import { CurrentSongKey, RouterKey } from '@/symbols'
|
import { CurrentSongKey } from '@/symbols'
|
||||||
|
|
||||||
import HomeScreen from '@/components/screens/HomeScreen.vue'
|
import HomeScreen from '@/components/screens/HomeScreen.vue'
|
||||||
import QueueScreen from '@/components/screens/QueueScreen.vue'
|
import QueueScreen from '@/components/screens/QueueScreen.vue'
|
||||||
|
@ -64,16 +64,16 @@ const NotFoundScreen = defineAsyncComponent(() => import('@/components/screens/N
|
||||||
const VisualizerScreen = defineAsyncComponent(() => import('@/components/screens/VisualizerScreen.vue'))
|
const VisualizerScreen = defineAsyncComponent(() => import('@/components/screens/VisualizerScreen.vue'))
|
||||||
|
|
||||||
const { useYouTube } = useThirdPartyServices()
|
const { useYouTube } = useThirdPartyServices()
|
||||||
|
const { resolveRoute, onRouteChanged } = useRouter()
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
const currentSong = requireInjection(CurrentSongKey, ref(null))
|
const currentSong = requireInjection(CurrentSongKey, ref(null))
|
||||||
|
|
||||||
const showAlbumArtOverlay = toRef(preferenceStore.state, 'showAlbumArtOverlay')
|
const showAlbumArtOverlay = toRef(preferenceStore.state, 'showAlbumArtOverlay')
|
||||||
const screen = ref<ScreenName>('Home')
|
const screen = ref<ScreenName>('Home')
|
||||||
|
|
||||||
router.onRouteChanged(route => (screen.value = route.screen))
|
onRouteChanged(route => (screen.value = route.screen))
|
||||||
|
|
||||||
onMounted(() => router.resolve())
|
onMounted(() => resolveRoute())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
@ -98,10 +98,9 @@ import {
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faYoutube } from '@fortawesome/free-brands-svg-icons'
|
import { faYoutube } from '@fortawesome/free-brands-svg-icons'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { queueStore } from '@/stores'
|
import { queueStore } from '@/stores'
|
||||||
import { useAuthorization, useDroppable, useThirdPartyServices } from '@/composables'
|
import { useAuthorization, useDroppable, useRouter, useThirdPartyServices } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import PlaylistList from '@/components/playlist/PlaylistSidebarList.vue'
|
import PlaylistList from '@/components/playlist/PlaylistSidebarList.vue'
|
||||||
import SearchForm from '@/components/ui/SearchForm.vue'
|
import SearchForm from '@/components/ui/SearchForm.vue'
|
||||||
|
@ -110,6 +109,7 @@ const mobileShowing = ref(false)
|
||||||
const activeScreen = ref<ScreenName>()
|
const activeScreen = ref<ScreenName>()
|
||||||
const droppableToQueue = ref(false)
|
const droppableToQueue = ref(false)
|
||||||
|
|
||||||
|
const { onRouteChanged } = useRouter()
|
||||||
const { acceptsDrop, resolveDroppedSongs } = useDroppable(['songs', 'album', 'artist', 'playlist'])
|
const { acceptsDrop, resolveDroppedSongs } = useDroppable(['songs', 'album', 'artist', 'playlist'])
|
||||||
const { useYouTube } = useThirdPartyServices()
|
const { useYouTube } = useThirdPartyServices()
|
||||||
const { isAdmin } = useAuthorization()
|
const { isAdmin } = useAuthorization()
|
||||||
|
@ -138,9 +138,7 @@ const onQueueDrop = async (event: DragEvent) => {
|
||||||
|
|
||||||
const closeIfMobile = () => (mobileShowing.value = false)
|
const closeIfMobile = () => (mobileShowing.value = false)
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
onRouteChanged(route => {
|
||||||
|
|
||||||
router.onRouteChanged(route => {
|
|
||||||
mobileShowing.value = false
|
mobileShowing.value = false
|
||||||
activeScreen.value = route.screen
|
activeScreen.value = route.screen
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,16 +30,15 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { playlistStore } from '@/stores'
|
import { playlistStore } from '@/stores'
|
||||||
import { logger, requireInjection } from '@/utils'
|
import { logger } from '@/utils'
|
||||||
import { useDialogBox, useMessageToaster } from '@/composables'
|
import { useDialogBox, useMessageToaster, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import SoundBars from '@/components/ui/SoundBars.vue'
|
import SoundBars from '@/components/ui/SoundBars.vue'
|
||||||
import Btn from '@/components/ui/Btn.vue'
|
import Btn from '@/components/ui/Btn.vue'
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const name = ref('')
|
const name = ref('')
|
||||||
|
@ -54,7 +53,7 @@ const submit = async () => {
|
||||||
const playlist = await playlistStore.store(name.value)
|
const playlist = await playlistStore.store(name.value)
|
||||||
close()
|
close()
|
||||||
toastSuccess(`Playlist "${playlist.name}" created.`)
|
toastSuccess(`Playlist "${playlist.name}" created.`)
|
||||||
router.go(`playlist/${playlist.id}`)
|
go(`playlist/${playlist.id}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorDialog('Something went wrong. Please try again.', 'Error')
|
showErrorDialog('Something went wrong. Please try again.', 'Error')
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
|
|
|
@ -14,15 +14,14 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useContextMenu } from '@/composables'
|
import { eventBus } from '@/utils'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
|
||||||
import { playlistStore, songStore } from '@/stores'
|
import { playlistStore, songStore } from '@/stores'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useContextMenu, useRouter } from '@/composables'
|
||||||
|
|
||||||
|
const { go } = useRouter()
|
||||||
const { context, base, ContextMenuBase, open, trigger } = useContextMenu()
|
const { context, base, ContextMenuBase, open, trigger } = useContextMenu()
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
const folder = ref<PlaylistFolder>()
|
const folder = ref<PlaylistFolder>()
|
||||||
|
|
||||||
const playlistsInFolder = computed(() => folder.value ? playlistStore.byFolder(folder.value) : [])
|
const playlistsInFolder = computed(() => folder.value ? playlistStore.byFolder(folder.value) : [])
|
||||||
|
@ -30,12 +29,12 @@ const playable = computed(() => playlistsInFolder.value.length > 0)
|
||||||
|
|
||||||
const play = () => trigger(async () => {
|
const play = () => trigger(async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForPlaylistFolder(folder.value!))
|
playbackService.queueAndPlay(await songStore.fetchForPlaylistFolder(folder.value!))
|
||||||
router.go('queue')
|
go('queue')
|
||||||
})
|
})
|
||||||
|
|
||||||
const shuffle = () => trigger(async () => {
|
const shuffle = () => trigger(async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchForPlaylistFolder(folder.value!), true)
|
playbackService.queueAndPlay(await songStore.fetchForPlaylistFolder(folder.value!), true)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
})
|
})
|
||||||
|
|
||||||
const rename = () => trigger(() => eventBus.emit('MODAL_SHOW_EDIT_PLAYLIST_FOLDER_FORM', folder.value))
|
const rename = () => trigger(() => eventBus.emit('MODAL_SHOW_EDIT_PLAYLIST_FOLDER_FORM', folder.value))
|
||||||
|
|
|
@ -30,15 +30,14 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { faBoltLightning, faClockRotateLeft, faFile, faHeart, faMusic } from '@fortawesome/free-solid-svg-icons'
|
import { faBoltLightning, faClockRotateLeft, faFile, faHeart, faMusic } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, ref, toRefs } from 'vue'
|
import { computed, ref, toRefs } from 'vue'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { favoriteStore } from '@/stores'
|
import { favoriteStore } from '@/stores'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useDraggable, useDroppable, usePlaylistManagement, useRouter } from '@/composables'
|
||||||
import { useDraggable, useDroppable, usePlaylistManagement } from '@/composables'
|
|
||||||
|
|
||||||
|
const { onRouteChanged } = useRouter()
|
||||||
const { startDragging } = useDraggable('playlist')
|
const { startDragging } = useDraggable('playlist')
|
||||||
const { acceptsDrop, resolveDroppedSongs } = useDroppable(['songs', 'album', 'artist'])
|
const { acceptsDrop, resolveDroppedSongs } = useDroppable(['songs', 'album', 'artist'])
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
const droppable = ref(false)
|
const droppable = ref(false)
|
||||||
|
|
||||||
const { addSongsToPlaylist } = usePlaylistManagement()
|
const { addSongsToPlaylist } = usePlaylistManagement()
|
||||||
|
@ -108,7 +107,7 @@ const onDrop = async (event: DragEvent) => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
router.onRouteChanged(route => {
|
onRouteChanged(route => {
|
||||||
switch (route.screen) {
|
switch (route.screen) {
|
||||||
case 'Favorites':
|
case 'Favorites':
|
||||||
active.value = isFavoriteList(list.value)
|
active.value = isFavoriteList(list.value)
|
||||||
|
|
|
@ -40,9 +40,8 @@
|
||||||
import { faPlus } from '@fortawesome/free-solid-svg-icons'
|
import { faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { playlistStore } from '@/stores'
|
import { playlistStore } from '@/stores'
|
||||||
import { logger, requireInjection } from '@/utils'
|
import { logger } from '@/utils'
|
||||||
import { useDialogBox, useMessageToaster, useSmartPlaylistForm } from '@/composables'
|
import { useDialogBox, useMessageToaster, useRouter, useSmartPlaylistForm } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Btn,
|
Btn,
|
||||||
|
@ -57,7 +56,7 @@ const {
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const name = ref('')
|
const name = ref('')
|
||||||
|
|
||||||
|
@ -80,7 +79,7 @@ const submit = async () => {
|
||||||
const playlist = await playlistStore.store(name.value, [], collectedRuleGroups.value)
|
const playlist = await playlistStore.store(name.value, [], collectedRuleGroups.value)
|
||||||
close()
|
close()
|
||||||
toastSuccess(`Playlist "${playlist.name}" created.`)
|
toastSuccess(`Playlist "${playlist.name}" created.`)
|
||||||
router.go(`playlist/${playlist.id}`)
|
go(`playlist/${playlist.id}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorDialog('Something went wrong. Please try again.')
|
showErrorDialog('Something went wrong. Please try again.')
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
|
|
|
@ -88,11 +88,10 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, onMounted, ref, toRef, watch } from 'vue'
|
import { computed, defineAsyncComponent, onMounted, ref, toRef, watch } from 'vue'
|
||||||
import { eventBus, logger, pluralize, requireInjection } from '@/utils'
|
import { eventBus, logger, pluralize } from '@/utils'
|
||||||
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
||||||
import { downloadService } from '@/services'
|
import { downloadService } from '@/services'
|
||||||
import { useDialogBox, useSongList } from '@/composables'
|
import { useDialogBox, useRouter, useSongList } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import AlbumThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
import AlbumThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
||||||
|
@ -108,7 +107,7 @@ const AlbumCard = defineAsyncComponent(() => import('@/components/album/AlbumCar
|
||||||
const AlbumCardSkeleton = defineAsyncComponent(() => import('@/components/ui/skeletons/ArtistAlbumCardSkeleton.vue'))
|
const AlbumCardSkeleton = defineAsyncComponent(() => import('@/components/ui/skeletons/ArtistAlbumCardSkeleton.vue'))
|
||||||
|
|
||||||
const { showErrorDialog } = useDialogBox()
|
const { showErrorDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { getRouteParam, go, onRouteChanged } = useRouter()
|
||||||
|
|
||||||
const albumId = ref<number>()
|
const albumId = ref<number>()
|
||||||
const album = ref<Album>()
|
const album = ref<Album>()
|
||||||
|
@ -175,12 +174,12 @@ watch(albumId, async id => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => (albumId.value = parseInt(router.$currentRoute.value.params!.id)))
|
onMounted(async () => (albumId.value = parseInt(getRouteParam('id')!)))
|
||||||
|
|
||||||
router.onRouteChanged(route => route.screen === 'Album' && (albumId.value = parseInt(route.params!.id)))
|
onRouteChanged(route => route.screen === 'Album' && (albumId.value = parseInt(getRouteParam('id')!)))
|
||||||
|
|
||||||
// if the current album has been deleted, go back to the list
|
// if the current album has been deleted, go back to the list
|
||||||
eventBus.on('SONGS_UPDATED', () => albumStore.byId(albumId.value) || router.go('albums'))
|
eventBus.on('SONGS_UPDATED', () => albumStore.byId(albumId.value) || go('albums'))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -36,11 +36,10 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, toRef } from 'vue'
|
import { computed, ref, toRef } from 'vue'
|
||||||
import { logger, pluralize, requireInjection, secondsToHumanReadable } from '@/utils'
|
import { logger, pluralize, secondsToHumanReadable } from '@/utils'
|
||||||
import { commonStore, queueStore, songStore } from '@/stores'
|
import { commonStore, queueStore, songStore } from '@/stores'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { useMessageToaster, useScreen, useSongList } from '@/composables'
|
import { useMessageToaster, useRouter, useScreen, useSongList } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
||||||
|
@ -66,7 +65,7 @@ const {
|
||||||
} = useSongList(toRef(songStore.state, 'songs'))
|
} = useSongList(toRef(songStore.state, 'songs'))
|
||||||
|
|
||||||
const { toastError } = useMessageToaster()
|
const { toastError } = useMessageToaster()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
let initialized = false
|
let initialized = false
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
@ -108,7 +107,7 @@ const playAll = async (shuffle: boolean) => {
|
||||||
await queueStore.fetchInOrder(sortField, sortOrder)
|
await queueStore.fetchInOrder(sortField, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
router.go('queue')
|
go('queue')
|
||||||
await playbackService.playFirstInQueue()
|
await playbackService.playFirstInQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,11 +85,10 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, onMounted, ref, toRef, watch } from 'vue'
|
import { computed, defineAsyncComponent, onMounted, ref, toRef, watch } from 'vue'
|
||||||
import { eventBus, logger, pluralize, requireInjection } from '@/utils'
|
import { eventBus, logger, pluralize } from '@/utils'
|
||||||
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
import { albumStore, artistStore, commonStore, songStore } from '@/stores'
|
||||||
import { downloadService } from '@/services'
|
import { downloadService } from '@/services'
|
||||||
import { useDialogBox, useSongList, useThirdPartyServices } from '@/composables'
|
import { useDialogBox, useRouter, useSongList, useThirdPartyServices } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import ArtistThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
import ArtistThumbnail from '@/components/ui/AlbumArtistThumbnail.vue'
|
||||||
|
@ -105,7 +104,7 @@ type Tab = 'Songs' | 'Albums' | 'Info'
|
||||||
const activeTab = ref<Tab>('Songs')
|
const activeTab = ref<Tab>('Songs')
|
||||||
|
|
||||||
const { showErrorDialog } = useDialogBox()
|
const { showErrorDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { getRouteParam, go } = useRouter()
|
||||||
|
|
||||||
const artistId = ref<number>()
|
const artistId = ref<number>()
|
||||||
const artist = ref<Artist>()
|
const artist = ref<Artist>()
|
||||||
|
@ -165,10 +164,10 @@ watch(artistId, async id => {
|
||||||
|
|
||||||
const download = () => downloadService.fromArtist(artist.value!)
|
const download = () => downloadService.fromArtist(artist.value!)
|
||||||
|
|
||||||
onMounted(() => (artistId.value = parseInt(router.$currentRoute.value.params!.id)))
|
onMounted(() => (artistId.value = parseInt(getRouteParam('id')!)))
|
||||||
|
|
||||||
// if the current artist has been deleted, go back to the list
|
// if the current artist has been deleted, go back to the list
|
||||||
eventBus.on('SONGS_UPDATED', () => artistStore.byId(artist.value!.id) || router.go('artists'))
|
eventBus.on('SONGS_UPDATED', () => artistStore.byId(artist.value!.id) || go('artists'))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -42,11 +42,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, watch } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { faTags } from '@fortawesome/free-solid-svg-icons'
|
import { faTags } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { eventBus, logger, pluralize, requireInjection, secondsToHumanReadable } from '@/utils'
|
import { eventBus, logger, pluralize, secondsToHumanReadable } from '@/utils'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { genreStore, songStore } from '@/stores'
|
import { genreStore, songStore } from '@/stores'
|
||||||
import { useDialogBox, useSongList } from '@/composables'
|
import { useDialogBox, useRouter, useSongList } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
||||||
|
@ -70,7 +69,7 @@ const {
|
||||||
} = useSongList(ref<Song[]>([]))
|
} = useSongList(ref<Song[]>([]))
|
||||||
|
|
||||||
const { showErrorDialog } = useDialogBox()
|
const { showErrorDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { getRouteParam, go, onRouteChanged } = useRouter()
|
||||||
|
|
||||||
let sortField: SongListSortField = 'title'
|
let sortField: SongListSortField = 'title'
|
||||||
let sortOrder: SortOrder = 'asc'
|
let sortOrder: SortOrder = 'asc'
|
||||||
|
@ -125,9 +124,9 @@ const refresh = async () => {
|
||||||
await fetch()
|
await fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getNameFromRoute = () => router.$currentRoute.value.params?.name || null
|
const getNameFromRoute = () => getRouteParam('name') ?? null
|
||||||
|
|
||||||
router.onRouteChanged(route => {
|
onRouteChanged(route => {
|
||||||
if (route.screen !== 'Genre') return
|
if (route.screen !== 'Genre') return
|
||||||
name.value = getNameFromRoute()
|
name.value = getNameFromRoute()
|
||||||
})
|
})
|
||||||
|
@ -142,7 +141,7 @@ const playAll = async () => {
|
||||||
playbackService.queueAndPlay(await songStore.fetchRandomForGenre(genre.value!, randomSongCount))
|
playbackService.queueAndPlay(await songStore.fetchRandomForGenre(genre.value!, randomSongCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => (name.value = getNameFromRoute()))
|
onMounted(() => (name.value = getNameFromRoute()))
|
||||||
|
|
|
@ -67,17 +67,16 @@
|
||||||
import { faFile } from '@fortawesome/free-regular-svg-icons'
|
import { faFile } from '@fortawesome/free-regular-svg-icons'
|
||||||
import { differenceBy } from 'lodash'
|
import { differenceBy } from 'lodash'
|
||||||
import { ref, toRef, watch } from 'vue'
|
import { ref, toRef, watch } from 'vue'
|
||||||
import { eventBus, pluralize, requireInjection } from '@/utils'
|
import { eventBus, pluralize } from '@/utils'
|
||||||
import { commonStore, playlistStore, songStore } from '@/stores'
|
import { commonStore, playlistStore, songStore } from '@/stores'
|
||||||
import { downloadService } from '@/services'
|
import { downloadService } from '@/services'
|
||||||
import { usePlaylistManagement, useSongList } from '@/composables'
|
import { usePlaylistManagement, useRouter, useSongList } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
||||||
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { onRouteChanged, triggerNotFound } = useRouter()
|
||||||
|
|
||||||
const playlistId = ref<number>()
|
const playlistId = ref<number>()
|
||||||
const playlist = ref<Playlist>()
|
const playlist = ref<Playlist>()
|
||||||
|
@ -129,10 +128,10 @@ watch(playlistId, async id => {
|
||||||
if (!id) return
|
if (!id) return
|
||||||
|
|
||||||
playlist.value = playlistStore.byId(id)
|
playlist.value = playlistStore.byId(id)
|
||||||
playlist.value ? await fetchSongs() : await router.triggerNotFound()
|
playlist.value ? await fetchSongs() : await triggerNotFound()
|
||||||
})
|
})
|
||||||
|
|
||||||
router.onRouteChanged(route => route.screen === 'Playlist' && (playlistId.value = parseInt(route.params!.id)))
|
onRouteChanged(route => route.screen === 'Playlist' && (playlistId.value = parseInt(route.params!.id)))
|
||||||
|
|
||||||
eventBus.on('PLAYLIST_UPDATED', async updated => updated.id === playlistId.value && await fetchSongs())
|
eventBus.on('PLAYLIST_UPDATED', async updated => updated.id === playlistId.value && await fetchSongs())
|
||||||
.on('PLAYLIST_SONGS_REMOVED', async (playlist, removed) => {
|
.on('PLAYLIST_SONGS_REMOVED', async (playlist, removed) => {
|
||||||
|
|
|
@ -51,17 +51,16 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { faCoffee } from '@fortawesome/free-solid-svg-icons'
|
import { faCoffee } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, ref, toRef } from 'vue'
|
import { computed, ref, toRef } from 'vue'
|
||||||
import { eventBus, logger, pluralize, requireInjection } from '@/utils'
|
import { eventBus, logger, pluralize } from '@/utils'
|
||||||
import { commonStore, queueStore, songStore } from '@/stores'
|
import { commonStore, queueStore, songStore } from '@/stores'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { useDialogBox, useSongList } from '@/composables'
|
import { useDialogBox, useRouter, useSongList } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
||||||
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
const { showErrorDialog } = useDialogBox()
|
const { showErrorDialog } = useDialogBox()
|
||||||
|
|
||||||
const controlConfig: Partial<SongListControlsConfig> = { clearQueue: true }
|
const controlConfig: Partial<SongListControlsConfig> = { clearQueue: true }
|
||||||
|
@ -88,7 +87,7 @@ const libraryNotEmpty = computed(() => commonStore.state.song_count > 0)
|
||||||
|
|
||||||
const playAll = async (shuffle = true) => {
|
const playAll = async (shuffle = true) => {
|
||||||
playbackService.queueAndPlay(songs.value, shuffle)
|
playbackService.queueAndPlay(songs.value, shuffle)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
const shuffleSome = async () => {
|
const shuffleSome = async () => {
|
||||||
|
|
|
@ -31,16 +31,15 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { settingStore } from '@/stores'
|
import { settingStore } from '@/stores'
|
||||||
import { forceReloadWindow, hideOverlay, parseValidationError, requireInjection, showOverlay } from '@/utils'
|
import { forceReloadWindow, hideOverlay, parseValidationError, showOverlay } from '@/utils'
|
||||||
import { useDialogBox, useMessageToaster } from '@/composables'
|
import { useDialogBox, useMessageToaster, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import Btn from '@/components/ui/Btn.vue'
|
import Btn from '@/components/ui/Btn.vue'
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
const { showConfirmDialog, showErrorDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const mediaPath = ref(settingStore.state.media_path)
|
const mediaPath = ref(settingStore.state.media_path)
|
||||||
const originalMediaPath = mediaPath.value
|
const originalMediaPath = mediaPath.value
|
||||||
|
@ -61,7 +60,7 @@ const save = async () => {
|
||||||
await settingStore.update({ media_path: mediaPath.value })
|
await settingStore.update({ media_path: mediaPath.value })
|
||||||
toastSuccess('Settings saved.')
|
toastSuccess('Settings saved.')
|
||||||
// Make sure we're back to home first.
|
// Make sure we're back to home first.
|
||||||
router.go('home')
|
go('home')
|
||||||
forceReloadWindow()
|
forceReloadWindow()
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const msg = err.response.status === 422 ? parseValidationError(err.response.data)[0] : 'Unknown error.'
|
const msg = err.response.status === 422 ? parseValidationError(err.response.data)[0] : 'Unknown error.'
|
||||||
|
|
|
@ -33,19 +33,18 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { toRef, toRefs } from 'vue'
|
import { toRef, toRefs } from 'vue'
|
||||||
import { overviewStore } from '@/stores'
|
import { overviewStore } from '@/stores'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useRouter } from '@/composables'
|
||||||
import { requireInjection } from '@/utils'
|
|
||||||
|
|
||||||
import Btn from '@/components/ui/Btn.vue'
|
import Btn from '@/components/ui/Btn.vue'
|
||||||
import SongCard from '@/components/song/SongCard.vue'
|
import SongCard from '@/components/song/SongCard.vue'
|
||||||
import SongCardSkeleton from '@/components/ui/skeletons/SongCardSkeleton.vue'
|
import SongCardSkeleton from '@/components/ui/skeletons/SongCardSkeleton.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ loading?: boolean }>(), { loading: false })
|
const props = withDefaults(defineProps<{ loading?: boolean }>(), { loading: false })
|
||||||
const { loading } = toRefs(props)
|
const { loading } = toRefs(props)
|
||||||
|
|
||||||
const songs = toRef(overviewStore.state, 'recentlyPlayed')
|
const songs = toRef(overviewStore.state, 'recentlyPlayed')
|
||||||
|
|
||||||
const goToRecentlyPlayedScreen = () => router.go('recently-played')
|
const goToRecentlyPlayedScreen = () => go('recently-played')
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -86,9 +86,9 @@
|
||||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { intersectionBy } from 'lodash'
|
import { intersectionBy } from 'lodash'
|
||||||
import { ref, toRef } from 'vue'
|
import { ref, toRef } from 'vue'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { searchStore } from '@/stores'
|
import { searchStore } from '@/stores'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useRouter } from '@/composables'
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
|
||||||
|
@ -99,13 +99,13 @@ import SongCard from '@/components/song/SongCard.vue'
|
||||||
import SongCardSkeleton from '@/components/ui/skeletons/SongCardSkeleton.vue'
|
import SongCardSkeleton from '@/components/ui/skeletons/SongCardSkeleton.vue'
|
||||||
import ArtistAlbumCardSkeleton from '@/components/ui/skeletons/ArtistAlbumCardSkeleton.vue'
|
import ArtistAlbumCardSkeleton from '@/components/ui/skeletons/ArtistAlbumCardSkeleton.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const excerpt = toRef(searchStore.state, 'excerpt')
|
const excerpt = toRef(searchStore.state, 'excerpt')
|
||||||
const q = ref('')
|
const q = ref('')
|
||||||
const searching = ref(false)
|
const searching = ref(false)
|
||||||
|
|
||||||
const goToSongResults = () => router.go(`search/songs/?q=${q.value}`)
|
const goToSongResults = () => go(`search/songs/?q=${q.value}`)
|
||||||
|
|
||||||
const doSearch = async () => {
|
const doSearch = async () => {
|
||||||
searching.value = true
|
searching.value = true
|
||||||
|
|
|
@ -30,14 +30,13 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, toRef } from 'vue'
|
import { computed, onMounted, ref, toRef } from 'vue'
|
||||||
import { searchStore } from '@/stores'
|
import { searchStore } from '@/stores'
|
||||||
import { useSongList } from '@/composables'
|
import { useRouter, useSongList } from '@/composables'
|
||||||
import { pluralize, requireInjection } from '@/utils'
|
import { pluralize } from '@/utils'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
|
||||||
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
import SongListSkeleton from '@/components/ui/skeletons/SongListSkeleton.vue'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { getRouteParam } = useRouter()
|
||||||
const q = ref('')
|
const q = ref('')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -65,7 +64,7 @@ const loading = ref(false)
|
||||||
searchStore.resetSongResultState()
|
searchStore.resetSongResultState()
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
q.value = router.$currentRoute.value.params?.q || ''
|
q.value = getRouteParam('q') || ''
|
||||||
if (!q.value) return
|
if (!q.value) return
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
|
@ -68,15 +68,14 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, nextTick, ref, toRef, toRefs, watch } from 'vue'
|
import { computed, nextTick, ref, toRef, toRefs, watch } from 'vue'
|
||||||
import { pluralize, requireInjection } from '@/utils'
|
import { pluralize } from '@/utils'
|
||||||
import { playlistStore, queueStore } from '@/stores'
|
import { playlistStore, queueStore } from '@/stores'
|
||||||
import { useMessageToaster, useSongMenuMethods } from '@/composables'
|
import { useMessageToaster, useRouter, useSongMenuMethods } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import Btn from '@/components/ui/Btn.vue'
|
import Btn from '@/components/ui/Btn.vue'
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const props = defineProps<{ songs: Song[], config: AddToMenuConfig }>()
|
const props = defineProps<{ songs: Song[], config: AddToMenuConfig }>()
|
||||||
const { songs, config } = toRefs(props)
|
const { songs, config } = toRefs(props)
|
||||||
|
@ -119,7 +118,7 @@ const createNewPlaylistFromSongs = async () => {
|
||||||
|
|
||||||
// Activate the new playlist right away
|
// Activate the new playlist right away
|
||||||
await nextTick()
|
await nextTick()
|
||||||
router.go(`playlist/${playlist.id}`)
|
go(`playlist/${playlist.id}`)
|
||||||
|
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, toRef } from 'vue'
|
import { computed, ref, toRef } from 'vue'
|
||||||
import { arrayify, copyText, eventBus, pluralize, requireInjection } from '@/utils'
|
import { arrayify, copyText, eventBus, pluralize } from '@/utils'
|
||||||
import { commonStore, favoriteStore, playlistStore, queueStore, songStore, userStore } from '@/stores'
|
import { commonStore, favoriteStore, playlistStore, queueStore, songStore, userStore } from '@/stores'
|
||||||
import { downloadService, playbackService } from '@/services'
|
import { downloadService, playbackService } from '@/services'
|
||||||
import {
|
import {
|
||||||
|
@ -65,13 +65,13 @@ import {
|
||||||
useDialogBox,
|
useDialogBox,
|
||||||
useMessageToaster,
|
useMessageToaster,
|
||||||
usePlaylistManagement,
|
usePlaylistManagement,
|
||||||
|
useRouter,
|
||||||
useSongMenuMethods
|
useSongMenuMethods
|
||||||
} from '@/composables'
|
} from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const { showConfirmDialog } = useDialogBox()
|
const { showConfirmDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { go, getRouteParam, isCurrentScreen } = useRouter()
|
||||||
|
|
||||||
const songs = ref<Song[]>([])
|
const songs = ref<Song[]>([])
|
||||||
|
|
||||||
|
@ -98,13 +98,13 @@ const firstSongPlaying = computed(() => songs.value.length ? songs.value[0].play
|
||||||
const normalPlaylists = computed(() => playlists.value.filter(playlist => !playlist.is_smart))
|
const normalPlaylists = computed(() => playlists.value.filter(playlist => !playlist.is_smart))
|
||||||
|
|
||||||
const canBeRemovedFromPlaylist = computed(() => {
|
const canBeRemovedFromPlaylist = computed(() => {
|
||||||
if (router.$currentRoute.value.screen !== 'Playlist') return false
|
if (!isCurrentScreen('Playlist')) return false
|
||||||
const playlist = playlistStore.byId(parseInt(router.$currentRoute.value.params!.id))
|
const playlist = playlistStore.byId(parseInt(getRouteParam('id')!))
|
||||||
return playlist && !playlist.is_smart
|
return playlist && !playlist.is_smart
|
||||||
})
|
})
|
||||||
|
|
||||||
const isQueueScreen = computed(() => router.$currentRoute.value.screen === 'Queue')
|
const isQueueScreen = computed(() => isCurrentScreen('Queue'))
|
||||||
const isFavoritesScreen = computed(() => router.$currentRoute.value.screen === 'Favorites')
|
const isFavoritesScreen = computed(() => isCurrentScreen('Favorites'))
|
||||||
|
|
||||||
const doPlayback = () => trigger(() => {
|
const doPlayback = () => trigger(() => {
|
||||||
if (!songs.value.length) return
|
if (!songs.value.length) return
|
||||||
|
@ -126,12 +126,12 @@ const doPlayback = () => trigger(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const openEditForm = () => trigger(() => songs.value.length && eventBus.emit('MODAL_SHOW_EDIT_SONG_FORM', songs.value))
|
const openEditForm = () => trigger(() => songs.value.length && eventBus.emit('MODAL_SHOW_EDIT_SONG_FORM', songs.value))
|
||||||
const viewAlbumDetails = (albumId: number) => trigger(() => router.go(`album/${albumId}`))
|
const viewAlbumDetails = (albumId: number) => trigger(() => go(`album/${albumId}`))
|
||||||
const viewArtistDetails = (artistId: number) => trigger(() => router.go(`artist/${artistId}`))
|
const viewArtistDetails = (artistId: number) => trigger(() => go(`artist/${artistId}`))
|
||||||
const download = () => trigger(() => downloadService.fromSongs(songs.value))
|
const download = () => trigger(() => downloadService.fromSongs(songs.value))
|
||||||
|
|
||||||
const removeFromPlaylist = () => trigger(async () => {
|
const removeFromPlaylist = () => trigger(async () => {
|
||||||
const playlist = playlistStore.byId(parseInt(router.$currentRoute.value.params!.id))
|
const playlist = playlistStore.byId(parseInt(getRouteParam('id')!))
|
||||||
if (!playlist) return
|
if (!playlist) return
|
||||||
|
|
||||||
await removeSongsFromPlaylist(playlist, songs.value)
|
await removeSongsFromPlaylist(playlist, songs.value)
|
||||||
|
|
|
@ -27,14 +27,13 @@ import { orderBy } from 'lodash'
|
||||||
import { computed, ref, toRef, toRefs } from 'vue'
|
import { computed, ref, toRef, toRefs } from 'vue'
|
||||||
import { albumStore, artistStore, queueStore, songStore, userStore } from '@/stores'
|
import { albumStore, artistStore, queueStore, songStore, userStore } from '@/stores'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { defaultCover, fileReader, logger, requireInjection } from '@/utils'
|
import { defaultCover, fileReader, logger } from '@/utils'
|
||||||
import { useAuthorization, useMessageToaster } from '@/composables'
|
import { useAuthorization, useMessageToaster, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
const VALID_IMAGE_TYPES = ['image/jpeg', 'image/gif', 'image/png', 'image/webp']
|
const VALID_IMAGE_TYPES = ['image/jpeg', 'image/gif', 'image/png', 'image/webp']
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const props = defineProps<{ entity: Album | Artist }>()
|
const props = defineProps<{ entity: Album | Artist }>()
|
||||||
const { entity } = toRefs(props)
|
const { entity } = toRefs(props)
|
||||||
|
@ -70,7 +69,7 @@ const playOrQueue = async (event: KeyboardEvent) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackService.queueAndPlay(songs)
|
playbackService.queueAndPlay(songs)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDragEnter = () => (droppable.value = allowsUpload.value)
|
const onDragEnter = () => (droppable.value = allowsUpload.value)
|
||||||
|
|
|
@ -11,9 +11,10 @@ import { computed, ref } from 'vue'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { commonStore, favoriteStore, queueStore, recentlyPlayedStore, songStore } from '@/stores'
|
import { commonStore, favoriteStore, queueStore, recentlyPlayedStore, songStore } from '@/stores'
|
||||||
import { requireInjection } from '@/utils'
|
import { requireInjection } from '@/utils'
|
||||||
import { CurrentSongKey, RouterKey } from '@/symbols'
|
import { useRouter } from '@/composables'
|
||||||
|
import { CurrentSongKey } from '@/symbols'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { getCurrentScreen, getRouteParam, go } = useRouter()
|
||||||
const song = requireInjection(CurrentSongKey, ref(null))
|
const song = requireInjection(CurrentSongKey, ref(null))
|
||||||
|
|
||||||
const libraryEmpty = computed(() => commonStore.state.song_count === 0)
|
const libraryEmpty = computed(() => commonStore.state.song_count === 0)
|
||||||
|
@ -26,15 +27,15 @@ const initiatePlayback = async () => {
|
||||||
|
|
||||||
let songs: Song[]
|
let songs: Song[]
|
||||||
|
|
||||||
switch (router.$currentRoute.value.screen) {
|
switch (getCurrentScreen()) {
|
||||||
case 'Album':
|
case 'Album':
|
||||||
songs = await songStore.fetchForAlbum(parseInt(router.$currentRoute.value.params!.id))
|
songs = await songStore.fetchForAlbum(parseInt(getRouteParam('id')!))
|
||||||
break
|
break
|
||||||
case 'Artist':
|
case 'Artist':
|
||||||
songs = await songStore.fetchForArtist(parseInt(router.$currentRoute.value.params!.id))
|
songs = await songStore.fetchForArtist(parseInt(getRouteParam('id')!))
|
||||||
break
|
break
|
||||||
case 'Playlist':
|
case 'Playlist':
|
||||||
songs = await songStore.fetchForPlaylist(parseInt(router.$currentRoute.value.params!.id))
|
songs = await songStore.fetchForPlaylist(parseInt(getRouteParam('id')!))
|
||||||
break
|
break
|
||||||
case 'Favorites':
|
case 'Favorites':
|
||||||
songs = await favoriteStore.fetch()
|
songs = await favoriteStore.fetch()
|
||||||
|
@ -48,7 +49,7 @@ const initiatePlayback = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
playbackService.queueAndPlay(songs)
|
playbackService.queueAndPlay(songs)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,12 @@ import isMobile from 'ismobilejs'
|
||||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useRouter } from '@/composables'
|
||||||
|
|
||||||
const placeholder = isMobile.any ? 'Search' : 'Press F to search'
|
const placeholder = isMobile.any ? 'Search' : 'Press F to search'
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const input = ref<HTMLInputElement>()
|
const input = ref<HTMLInputElement>()
|
||||||
const q = ref('')
|
const q = ref('')
|
||||||
|
@ -50,10 +50,10 @@ if (process.env.NODE_ENV !== 'test') {
|
||||||
|
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
eventBus.emit('TOGGLE_SIDEBAR')
|
eventBus.emit('TOGGLE_SIDEBAR')
|
||||||
router.go('search')
|
go('search')
|
||||||
}
|
}
|
||||||
|
|
||||||
const maybeGoToSearchScreen = () => isMobile.any || router.go('search')
|
const maybeGoToSearchScreen = () => isMobile.any || go('search')
|
||||||
|
|
||||||
eventBus.on('FOCUS_SEARCH_FIELD', () => {
|
eventBus.on('FOCUS_SEARCH_FIELD', () => {
|
||||||
input.value?.focus()
|
input.value?.focus()
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, toRefs } from 'vue'
|
import { computed, toRefs } from 'vue'
|
||||||
import { youTubeService } from '@/services'
|
import { youTubeService } from '@/services'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useRouter } from '@/composables'
|
||||||
import { requireInjection } from '@/utils'
|
|
||||||
|
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const props = defineProps<{ video: YouTubeVideo }>()
|
const props = defineProps<{ video: YouTubeVideo }>()
|
||||||
const { video } = toRefs(props)
|
const { video } = toRefs(props)
|
||||||
|
@ -23,7 +22,7 @@ const url = computed(() => `https://youtu.be/${video.value.id.videoId}`)
|
||||||
|
|
||||||
const play = () => {
|
const play = () => {
|
||||||
youTubeService.play(video.value)
|
youTubeService.play(video.value)
|
||||||
router.go('youtube')
|
go('youtube')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,8 @@
|
||||||
import { faCircleCheck, faShield } from '@fortawesome/free-solid-svg-icons'
|
import { faCircleCheck, faShield } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, toRefs } from 'vue'
|
import { computed, toRefs } from 'vue'
|
||||||
import { userStore } from '@/stores'
|
import { userStore } from '@/stores'
|
||||||
import { eventBus, requireInjection } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { useAuthorization, useDialogBox, useMessageToaster } from '@/composables'
|
import { useAuthorization, useDialogBox, useMessageToaster, useRouter } from '@/composables'
|
||||||
import { RouterKey } from '@/symbols'
|
|
||||||
|
|
||||||
import Btn from '@/components/ui/Btn.vue'
|
import Btn from '@/components/ui/Btn.vue'
|
||||||
|
|
||||||
|
@ -43,13 +42,13 @@ const { user } = toRefs(props)
|
||||||
|
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const { showConfirmDialog } = useDialogBox()
|
const { showConfirmDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
const { currentUser } = useAuthorization()
|
const { currentUser } = useAuthorization()
|
||||||
|
|
||||||
const isCurrentUser = computed(() => user.value.id === currentUser.value.id)
|
const isCurrentUser = computed(() => user.value.id === currentUser.value.id)
|
||||||
|
|
||||||
const edit = () => isCurrentUser.value ? router.go('profile') : eventBus.emit('MODAL_SHOW_EDIT_USER_FORM', user.value)
|
const edit = () => isCurrentUser.value ? go('profile') : eventBus.emit('MODAL_SHOW_EDIT_USER_FORM', user.value)
|
||||||
|
|
||||||
const confirmDelete = async () =>
|
const confirmDelete = async () =>
|
||||||
await showConfirmDialog(`You’re about to unperson ${user.value.name}. Are you sure?`) && await destroy()
|
await showConfirmDialog(`You’re about to unperson ${user.value.name}. Are you sure?`) && await destroy()
|
||||||
|
|
|
@ -5,27 +5,26 @@
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { authService } from '@/services'
|
import { authService } from '@/services'
|
||||||
import { playlistFolderStore, playlistStore, userStore } from '@/stores'
|
import { playlistFolderStore, playlistStore, userStore } from '@/stores'
|
||||||
import { eventBus, forceReloadWindow, requireInjection } from '@/utils'
|
import { eventBus, forceReloadWindow } from '@/utils'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useDialogBox, useMessageToaster, useRouter } from '@/composables'
|
||||||
import { useDialogBox, useMessageToaster } from '@/composables'
|
|
||||||
|
|
||||||
export const GlobalEventListeners = defineComponent({
|
export const GlobalEventListeners = defineComponent({
|
||||||
setup (props, { slots }) {
|
setup (props, { slots }) {
|
||||||
const { toastSuccess } = useMessageToaster()
|
const { toastSuccess } = useMessageToaster()
|
||||||
const { showConfirmDialog } = useDialogBox()
|
const { showConfirmDialog } = useDialogBox()
|
||||||
const router = requireInjection(RouterKey)
|
const { go } = useRouter()
|
||||||
|
|
||||||
eventBus.on('PLAYLIST_DELETE', async playlist => {
|
eventBus.on('PLAYLIST_DELETE', async playlist => {
|
||||||
if (await showConfirmDialog(`Delete the playlist "${playlist.name}"?`)) {
|
if (await showConfirmDialog(`Delete the playlist "${playlist.name}"?`)) {
|
||||||
await playlistStore.delete(playlist)
|
await playlistStore.delete(playlist)
|
||||||
toastSuccess(`Playlist "${playlist.name}" deleted.`)
|
toastSuccess(`Playlist "${playlist.name}" deleted.`)
|
||||||
router.go('home')
|
go('home')
|
||||||
}
|
}
|
||||||
}).on('PLAYLIST_FOLDER_DELETE', async folder => {
|
}).on('PLAYLIST_FOLDER_DELETE', async folder => {
|
||||||
if (await showConfirmDialog(`Delete the playlist folder "${folder.name}"?`)) {
|
if (await showConfirmDialog(`Delete the playlist folder "${folder.name}"?`)) {
|
||||||
await playlistFolderStore.delete(folder)
|
await playlistFolderStore.delete(folder)
|
||||||
toastSuccess(`Playlist folder "${folder.name}" deleted.`)
|
toastSuccess(`Playlist folder "${folder.name}" deleted.`)
|
||||||
router.go('home')
|
go('home')
|
||||||
}
|
}
|
||||||
}).on('LOG_OUT', async () => {
|
}).on('LOG_OUT', async () => {
|
||||||
await userStore.logout()
|
await userStore.logout()
|
||||||
|
|
|
@ -14,3 +14,4 @@ export * from './useFloatingUi'
|
||||||
export * from './useMessageToaster'
|
export * from './useMessageToaster'
|
||||||
export * from './useDialogBox'
|
export * from './useDialogBox'
|
||||||
export * from './useSmartPlaylistForm'
|
export * from './useSmartPlaylistForm'
|
||||||
|
export * from './useRouter'
|
||||||
|
|
16
resources/assets/js/composables/useRouter.ts
Normal file
16
resources/assets/js/composables/useRouter.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { RouterKey } from '@/symbols'
|
||||||
|
import { requireInjection } from '@/utils'
|
||||||
|
|
||||||
|
export const useRouter = () => {
|
||||||
|
const router = requireInjection(RouterKey)
|
||||||
|
|
||||||
|
return {
|
||||||
|
go: router.go.bind(router),
|
||||||
|
onRouteChanged: router.onRouteChanged.bind(router),
|
||||||
|
resolveRoute: router.resolve.bind(router),
|
||||||
|
triggerNotFound: router.triggerNotFound.bind(router),
|
||||||
|
getRouteParam: (name: string) => router.$currentRoute.value?.params?.[name],
|
||||||
|
getCurrentScreen: () => router.$currentRoute.value?.screen,
|
||||||
|
isCurrentScreen: (...screens: ScreenName[]) => screens.includes(router.$currentRoute.value?.screen!)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import { RouterKey } from '@/symbols'
|
import { useRouter } from '@/composables'
|
||||||
import { requireInjection } from '@/utils'
|
|
||||||
|
|
||||||
export const useScreen = (screen: ScreenName) => {
|
export const useScreen = (screen: ScreenName) => {
|
||||||
const router = requireInjection(RouterKey)
|
const { onRouteChanged } = useRouter()
|
||||||
const onScreenActivated = (cb: Closure) => router.onRouteChanged(route => route.screen === screen && cb())
|
const onScreenActivated = (cb: Closure) => onRouteChanged(route => route.screen === screen && cb())
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onScreenActivated
|
onScreenActivated
|
||||||
|
|
|
@ -3,16 +3,10 @@ import isMobile from 'ismobilejs'
|
||||||
import { computed, reactive, Ref, ref } from 'vue'
|
import { computed, reactive, Ref, ref } from 'vue'
|
||||||
import { playbackService } from '@/services'
|
import { playbackService } from '@/services'
|
||||||
import { queueStore, songStore } from '@/stores'
|
import { queueStore, songStore } from '@/stores'
|
||||||
import { eventBus, provideReadonly, requireInjection } from '@/utils'
|
import { eventBus, provideReadonly } from '@/utils'
|
||||||
|
import { useRouter } from '@/composables'
|
||||||
|
|
||||||
import {
|
import { SelectedSongsKey, SongListConfigKey, SongListSortFieldKey, SongListSortOrderKey, SongsKey } from '@/symbols'
|
||||||
RouterKey,
|
|
||||||
SelectedSongsKey,
|
|
||||||
SongListConfigKey,
|
|
||||||
SongListSortFieldKey,
|
|
||||||
SongListSortOrderKey,
|
|
||||||
SongsKey
|
|
||||||
} from '@/symbols'
|
|
||||||
|
|
||||||
import ControlsToggle from '@/components/ui/ScreenControlsToggle.vue'
|
import ControlsToggle from '@/components/ui/ScreenControlsToggle.vue'
|
||||||
import SongList from '@/components/song/SongList.vue'
|
import SongList from '@/components/song/SongList.vue'
|
||||||
|
@ -21,9 +15,9 @@ import ThumbnailStack from '@/components/ui/ThumbnailStack.vue'
|
||||||
|
|
||||||
export const useSongList = (songs: Ref<Song[]>, config: Partial<SongListConfig> = {}) => {
|
export const useSongList = (songs: Ref<Song[]>, config: Partial<SongListConfig> = {}) => {
|
||||||
config = reactive(config)
|
config = reactive(config)
|
||||||
const router = requireInjection(RouterKey)
|
const { isCurrentScreen, go, onRouteChanged } = useRouter()
|
||||||
|
|
||||||
router.onRouteChanged(route => {
|
onRouteChanged(route => {
|
||||||
config.reorderable = route.screen === 'Queue'
|
config.reorderable = route.screen === 'Queue'
|
||||||
config.sortable = !['Queue', 'RecentlyPlayed', 'Search.Songs'].includes(route.screen)
|
config.sortable = !['Queue', 'RecentlyPlayed', 'Search.Songs'].includes(route.screen)
|
||||||
})
|
})
|
||||||
|
@ -51,7 +45,7 @@ export const useSongList = (songs: Ref<Song[]>, config: Partial<SongListConfig>
|
||||||
|
|
||||||
const playAll = (shuffle: boolean) => {
|
const playAll = (shuffle: boolean) => {
|
||||||
playbackService.queueAndPlay(getSongsToPlay(), shuffle)
|
playbackService.queueAndPlay(getSongsToPlay(), shuffle)
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
const playSelected = (shuffle: boolean) => playbackService.queueAndPlay(selectedSongs.value, shuffle)
|
const playSelected = (shuffle: boolean) => playbackService.queueAndPlay(selectedSongs.value, shuffle)
|
||||||
|
@ -73,13 +67,13 @@ export const useSongList = (songs: Ref<Song[]>, config: Partial<SongListConfig>
|
||||||
await playbackService.play(selectedSongs.value[0])
|
await playbackService.play(selectedSongs.value[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
router.go('queue')
|
go('queue')
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortField = ref<SongListSortField | null>(((): SongListSortField | null => {
|
const sortField = ref<SongListSortField | null>(((): SongListSortField | null => {
|
||||||
if (!config.sortable) return null
|
if (!config.sortable) return null
|
||||||
if (router.$currentRoute.value.screen === 'Album' || router.$currentRoute.value.screen === 'Artist') return 'track'
|
if (isCurrentScreen('Artist', 'Album')) return 'track'
|
||||||
if (router.$currentRoute.value.screen === 'Search.Songs') return null
|
if (isCurrentScreen('Search.Songs', 'Queue', 'RecentlyPlayed')) return null
|
||||||
return 'title'
|
return 'title'
|
||||||
})())
|
})())
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import isMobile from 'ismobilejs'
|
import isMobile from 'ismobilejs'
|
||||||
import { computed, toRef } from 'vue'
|
import { computed, toRef } from 'vue'
|
||||||
import { useAuthorization, useMessageToaster } from '@/composables'
|
|
||||||
import { settingStore } from '@/stores'
|
import { settingStore } from '@/stores'
|
||||||
import { acceptedMediaTypes } from '@/config'
|
import { acceptedMediaTypes } from '@/config'
|
||||||
import { UploadFile, uploadService } from '@/services'
|
import { UploadFile, uploadService } from '@/services'
|
||||||
import { getAllFileEntries, pluralize, requireInjection } from '@/utils'
|
import { getAllFileEntries, pluralize } from '@/utils'
|
||||||
import { RouterKey } from '@/symbols'
|
import { useAuthorization, useMessageToaster, useRouter } from '@/composables'
|
||||||
|
|
||||||
export const useUpload = () => {
|
export const useUpload = () => {
|
||||||
const { isAdmin } = useAuthorization()
|
const { isAdmin } = useAuthorization()
|
||||||
const { toastSuccess, toastWarning } = useMessageToaster()
|
const { toastSuccess, toastWarning } = useMessageToaster()
|
||||||
|
const { go, isCurrentRoute } = useRouter()
|
||||||
const router = requireInjection(RouterKey)
|
|
||||||
|
|
||||||
const mediaPath = toRef(settingStore.state, 'media_path')
|
const mediaPath = toRef(settingStore.state, 'media_path')
|
||||||
|
|
||||||
|
@ -47,7 +45,7 @@ export const useUpload = () => {
|
||||||
|
|
||||||
if (queuedFiles.length) {
|
if (queuedFiles.length) {
|
||||||
toastSuccess(`Queued ${pluralize(queuedFiles, 'file')} for upload`)
|
toastSuccess(`Queued ${pluralize(queuedFiles, 'file')} for upload`)
|
||||||
router.$currentRoute.value.screen === 'Upload' || router.go('upload')
|
isCurrentRoute('Upload') || go('upload')
|
||||||
} else {
|
} else {
|
||||||
toastWarning('No files applicable for upload')
|
toastWarning('No files applicable for upload')
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import Router from '@/router'
|
||||||
export type ReadonlyInjectionKey<T> = InjectionKey<[Readonly<T> | DeepReadonly<T>, Closure]>
|
export type ReadonlyInjectionKey<T> = InjectionKey<[Readonly<T> | DeepReadonly<T>, Closure]>
|
||||||
|
|
||||||
export const RouterKey: InjectionKey<Router> = Symbol('Router')
|
export const RouterKey: InjectionKey<Router> = Symbol('Router')
|
||||||
|
|
||||||
export const DialogBoxKey: InjectionKey<Ref<InstanceType<typeof DialogBox>>> = Symbol('DialogBox')
|
export const DialogBoxKey: InjectionKey<Ref<InstanceType<typeof DialogBox>>> = Symbol('DialogBox')
|
||||||
export const MessageToasterKey: InjectionKey<Ref<InstanceType<typeof MessageToaster>>> = Symbol('MessageToaster')
|
export const MessageToasterKey: InjectionKey<Ref<InstanceType<typeof MessageToaster>>> = Symbol('MessageToaster')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue