koel/resources/assets/js/remote/App.vue

102 lines
3.2 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
<div :class="{ standalone: inStandaloneMode }" class="h-screen bg-k-bg-primary">
2022-04-15 14:24:30 +00:00
<template v-if="authenticated">
<AlbumArtOverlay v-if="showAlbumArtOverlay" :album="(state.playable as Song).album_id" />
2022-04-15 14:24:30 +00:00
2024-04-04 22:20:42 +00:00
<main class="h-screen flex flex-col items-center justify-between text-center relative z-[1]">
2022-04-15 14:24:30 +00:00
<template v-if="connected">
<template v-if="state.playable">
<PlayableDetails :playable="state.playable" />
<RemoteFooter :playable="state.playable" />
2024-04-04 22:20:42 +00:00
</template>
<p v-else class="text-k-text-secondary">No song is playing.</p>
2022-04-15 14:24:30 +00:00
</template>
2024-04-04 22:20:42 +00:00
<Scanner v-else />
2022-04-15 14:24:30 +00:00
</main>
</template>
2024-04-04 22:20:42 +00:00
<div v-else class="h-screen flex flex-col items-center justify-center">
2022-12-02 16:17:37 +00:00
<LoginForm @loggedin="onUserLoggedIn" />
2022-04-15 14:24:30 +00:00
</div>
</div>
</template>
2022-04-25 13:07:38 +00:00
<script lang="ts" setup>
import { authService, socketService } from '@/services'
import { preferenceStore, userStore } from '@/stores'
import { computed, defineAsyncComponent, onMounted, provide, reactive, ref } from 'vue'
import { isSong, logger } from '@/utils'
import type { RemoteState } from '@/remote/types'
2022-04-15 14:24:30 +00:00
const PlayableDetails = defineAsyncComponent(() => import('@/remote/components/PlayableDetails.vue'))
2024-04-04 22:20:42 +00:00
const Scanner = defineAsyncComponent(() => import('@/remote/components/Scanner.vue'))
const RemoteFooter = defineAsyncComponent(() => import('@/remote/components/RemoteFooter.vue'))
2022-04-25 13:07:38 +00:00
const AlbumArtOverlay = defineAsyncComponent(() => import('@/components/ui/AlbumArtOverlay.vue'))
const LoginForm = defineAsyncComponent(() => import('@/components/auth/LoginForm.vue'))
2022-04-25 13:07:38 +00:00
const authenticated = ref(false)
const connected = ref(false)
const state = reactive<RemoteState>({
playable: null,
volume: 0,
})
provide('state', state)
const showAlbumArtOverlay = computed(() => {
return preferenceStore.show_album_art_overlay
&& state.playable
&& isSong(state.playable)
})
2022-04-25 13:07:38 +00:00
const inStandaloneMode = ref(
(window.navigator as any).standalone || window.matchMedia('(display-mode: standalone)').matches,
2022-04-25 13:07:38 +00:00
)
const init = async () => {
try {
2024-01-18 11:13:05 +00:00
userStore.init(await authService.getProfile())
2022-04-25 13:07:38 +00:00
await socketService.init()
socketService
.listen('SOCKET_PLAYABLE', playable => (state.playable = playable))
.listen('SOCKET_PLAYBACK_STOPPED', () => state.playable && (state.playable.playback_state = 'Stopped'))
2024-04-04 22:20:42 +00:00
.listen('SOCKET_VOLUME_CHANGED', (volume: number) => state.volume = volume)
.listen('SOCKET_STATUS', (data: { playable?: Playable, volume: number }) => {
2024-04-04 22:20:42 +00:00
state.volume = data.volume || 0
state.playable = data.playable || null
2022-04-25 13:07:38 +00:00
connected.value = true
})
} catch (error: unknown) {
logger.error(error)
2022-04-25 13:07:38 +00:00
authenticated.value = false
}
}
2022-04-15 14:24:30 +00:00
const onUserLoggedIn = async () => {
authenticated.value = true
await init()
}
onMounted(async () => {
2022-04-25 13:07:38 +00:00
// The app has just been initialized, check if we can get the user data with an already existing token
2022-11-16 17:57:38 +00:00
if (authService.hasApiToken()) {
2022-04-25 13:07:38 +00:00
authenticated.value = true
await init()
2022-04-15 14:24:30 +00:00
}
})
</script>
2024-04-04 22:20:42 +00:00
<style lang="postcss" scoped>
.standalone {
@apply pt-[20px];
2022-04-15 14:24:30 +00:00
2024-04-04 22:20:42 +00:00
:deep(.cover) {
width: calc(80vw - 4px);
height: calc(80vw - 4px);
2022-04-15 14:24:30 +00:00
}
}
</style>