2022-04-15 14:24:30 +00:00
|
|
|
<template>
|
2024-04-04 22:20:42 +00:00
|
|
|
<div :class="{ 'standalone' : inStandaloneMode }" class="h-screen bg-k-bg-primary">
|
2022-04-15 14:24:30 +00:00
|
|
|
<template v-if="authenticated">
|
2024-06-02 17:15:31 +00:00
|
|
|
<AlbumArtOverlay v-if="showAlbumArtOverlay && state.song && isSong(state.song)" :album="state.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">
|
2024-04-04 22:20:42 +00:00
|
|
|
<template v-if="state.song">
|
|
|
|
<SongDetails :song="state.song" />
|
|
|
|
<RemoteFooter :song="state.song" />
|
|
|
|
</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'
|
2024-04-04 22:20:42 +00:00
|
|
|
import { defineAsyncComponent, onMounted, provide, reactive, ref, toRef } from 'vue'
|
2024-06-02 17:15:31 +00:00
|
|
|
import { isSong, logger } from '@/utils'
|
2024-04-04 22:20:42 +00:00
|
|
|
import { RemoteState } from '@/remote/types'
|
2022-04-15 14:24:30 +00:00
|
|
|
|
2024-04-04 22:20:42 +00:00
|
|
|
const SongDetails = defineAsyncComponent(() => import('@/remote/components/SongDetails.vue'))
|
|
|
|
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'))
|
2022-07-07 18:05:46 +00:00
|
|
|
const LoginForm = defineAsyncComponent(() => import('@/components/auth/LoginForm.vue'))
|
2022-04-25 13:07:38 +00:00
|
|
|
|
|
|
|
const authenticated = ref(false)
|
|
|
|
const connected = ref(false)
|
2024-01-23 22:50:50 +00:00
|
|
|
const showAlbumArtOverlay = toRef(preferenceStore.state, 'show_album_art_overlay')
|
2022-04-25 13:07:38 +00:00
|
|
|
|
|
|
|
const inStandaloneMode = ref(
|
|
|
|
(window.navigator as any).standalone || window.matchMedia('(display-mode: standalone)').matches
|
|
|
|
)
|
|
|
|
|
2022-07-24 10:53:49 +00:00
|
|
|
const onUserLoggedIn = async () => {
|
2022-04-25 13:07:38 +00:00
|
|
|
authenticated.value = true
|
2022-07-24 10:53:49 +00:00
|
|
|
await init()
|
2022-04-25 13:07:38 +00:00
|
|
|
}
|
2022-04-15 14:24:30 +00:00
|
|
|
|
2024-04-04 22:20:42 +00:00
|
|
|
const state = reactive<RemoteState>({
|
|
|
|
volume: 0,
|
2024-06-02 17:15:31 +00:00
|
|
|
song: null as Playable | null
|
2024-04-04 22:20:42 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
provide('state', state)
|
|
|
|
|
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
|
2024-04-04 22:20:42 +00:00
|
|
|
.listen('SOCKET_SONG', song => (state.song = song))
|
|
|
|
.listen('SOCKET_PLAYBACK_STOPPED', () => state.song && (state.song.playback_state = 'Stopped'))
|
|
|
|
.listen('SOCKET_VOLUME_CHANGED', (volume: number) => state.volume = volume)
|
2024-06-02 17:15:31 +00:00
|
|
|
.listen('SOCKET_STATUS', (data: { song?: Playable, volume: number }) => {
|
2024-04-04 22:20:42 +00:00
|
|
|
state.volume = data.volume || 0
|
|
|
|
state.song = data.song || null
|
2022-04-25 13:07:38 +00:00
|
|
|
connected.value = true
|
|
|
|
})
|
2024-04-23 11:24:29 +00:00
|
|
|
} 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
|
|
|
|
2022-07-24 10:53:49 +00:00
|
|
|
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
|
2022-07-24 10:53:49 +00:00
|
|
|
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>
|