feat: notify when app comes offline (#1561)

This commit is contained in:
Phan An 2022-10-27 15:44:40 +02:00 committed by GitHub
parent cadc2d1d92
commit 260152b417
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 1 deletions

View file

@ -3,6 +3,7 @@
<DialogBox ref="dialog"/> <DialogBox ref="dialog"/>
<MessageToaster ref="toaster"/> <MessageToaster ref="toaster"/>
<GlobalEventListeners/> <GlobalEventListeners/>
<OfflineNotification v-if="offline"/>
<div v-if="authenticated" id="main" @dragend="onDragEnd" @dragover="onDragOver" @drop="onDrop"> <div v-if="authenticated" id="main" @dragend="onDragEnd" @dragover="onDragOver" @drop="onDrop">
<Hotkeys/> <Hotkeys/>
@ -29,10 +30,12 @@ import { eventBus, hideOverlay, requireInjection, showOverlay } from '@/utils'
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores' import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
import { authService, playbackService, socketListener, socketService, uploadService } from '@/services' import { authService, playbackService, socketListener, socketService, uploadService } from '@/services'
import { CurrentSongKey, DialogBoxKey, MessageToasterKey, RouterKey } from '@/symbols' import { CurrentSongKey, DialogBoxKey, MessageToasterKey, RouterKey } from '@/symbols'
import { useNetworkStatus } 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'
import Overlay from '@/components/ui/Overlay.vue' import Overlay from '@/components/ui/Overlay.vue'
import OfflineNotification from '@/components/ui/OfflineNotification.vue'
// Do not dynamic-import app footer, as it contains the <audio> element // Do not dynamic-import app footer, as it contains the <audio> element
// that is necessary to properly initialize the playService and equalizer. // that is necessary to properly initialize the playService and equalizer.
@ -59,6 +62,8 @@ const currentSong = ref<Song | null>(null)
const authenticated = ref(false) const authenticated = ref(false)
const showDropZone = ref(false) const showDropZone = ref(false)
const { offline } = useNetworkStatus()
/** /**
* Request for notification permission if it's not provided and the user is OK with notifications. * Request for notification permission if it's not provided and the user is OK with notifications.
*/ */

View file

@ -1,6 +1,6 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import { clickaway, focus, tooltip } from '@/directives' import { clickaway, focus, tooltip } from '@/directives'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import { RouterKey } from '@/symbols' import { RouterKey } from '@/symbols'
import { routes } from '@/config' import { routes } from '@/config'
import Router from '@/router' import Router from '@/router'
@ -9,6 +9,7 @@ import App from './App.vue'
createApp(App) createApp(App)
.provide(RouterKey, new Router(routes)) .provide(RouterKey, new Router(routes))
.component('icon', FontAwesomeIcon) .component('icon', FontAwesomeIcon)
.component('icon-layers', FontAwesomeLayers)
.directive('koel-focus', focus) .directive('koel-focus', focus)
.directive('koel-clickaway', clickaway) .directive('koel-clickaway', clickaway)
.directive('koel-tooltip', tooltip) .directive('koel-tooltip', tooltip)

View file

@ -0,0 +1,40 @@
<template>
<div class="offline">
<icon-layers fixed-width>
<icon :icon="faWifi" fixed-width size="xl"/>
<icon :icon="faSlash" fixed-width size="lg" transform="up-2"/>
</icon-layers>
<span class="text">Youre offline.</span>
</div>
</template>
<script lang="ts" setup>
import { faSlash, faWifi } from '@fortawesome/free-solid-svg-icons'</script>
<style lang="scss" scoped>
.offline {
color: #ed5135;
width: 144px;
height: 42px;
background: #fff;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
position: fixed;
z-index: 10000;
left: 1.6rem;
bottom: calc(var(--footer-height) + 1.2rem);
box-shadow: 0 2px 30px rgba(0, 0, 0, .3);
}
.text {
color: #222;
}
.fa-slash {
filter: drop-shadow(0 2px 0 #fff);
}
</style>

View file

@ -9,3 +9,4 @@ export * from './useDragAndDrop'
export * from './useUpload' export * from './useUpload'
export * from './useScreen' export * from './useScreen'
export * from './usePlaylistManagement' export * from './usePlaylistManagement'
export * from './useNetworkStatus'

View file

@ -0,0 +1,21 @@
import { computed, onUnmounted, ref } from 'vue'
export const useNetworkStatus = () => {
const online = ref(navigator.onLine)
const offline = computed(() => !online.value)
const updateOnlineStatus = () => (online.value = navigator.onLine)
window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)
onUnmounted(() => {
window.removeEventListener('online', updateOnlineStatus)
window.removeEventListener('offline', updateOnlineStatus)
})
return {
online,
offline
}
}