2017-06-23 21:00:42 +00:00
|
|
|
<template>
|
2021-11-26 11:01:58 +00:00
|
|
|
<div
|
|
|
|
id="app"
|
|
|
|
:key="String($store.state.instance.instanceUrl)"
|
2022-02-21 14:07:07 +00:00
|
|
|
:class="[$store.state.ui.queueFocused ? 'queue-focused' : '',
|
2022-02-21 18:53:34 +00:00
|
|
|
{'has-bottom-player': $store.state.queue.tracks.length > 0}]"
|
2021-11-26 11:01:58 +00:00
|
|
|
>
|
2018-07-26 17:51:55 +00:00
|
|
|
<!-- here, we display custom stylesheets, if any -->
|
2018-12-04 14:13:37 +00:00
|
|
|
<link
|
|
|
|
v-for="url in customStylesheets"
|
2021-11-26 11:01:58 +00:00
|
|
|
:key="url"
|
2018-12-04 14:13:37 +00:00
|
|
|
rel="stylesheet"
|
|
|
|
property="stylesheet"
|
|
|
|
:href="url"
|
|
|
|
>
|
2021-11-26 11:01:58 +00:00
|
|
|
<sidebar
|
|
|
|
:width="width"
|
|
|
|
@show:set-instance-modal="showSetInstanceModal = !showSetInstanceModal"
|
|
|
|
@show:shortcuts-modal="showShortcutsModal = !showShortcutsModal"
|
|
|
|
/>
|
|
|
|
<set-instance-modal
|
|
|
|
:show="showSetInstanceModal"
|
|
|
|
@update:show="showSetInstanceModal = $event"
|
|
|
|
/>
|
|
|
|
<service-messages />
|
|
|
|
<transition name="queue">
|
|
|
|
<queue
|
|
|
|
v-if="$store.state.ui.queueFocused"
|
|
|
|
@touch-progress="$refs.player.setCurrentTime($event)"
|
|
|
|
/>
|
|
|
|
</transition>
|
|
|
|
<router-view
|
|
|
|
role="main"
|
|
|
|
:class="{hidden: $store.state.ui.queueFocused}"
|
|
|
|
/>
|
|
|
|
<player ref="player" />
|
|
|
|
<playlist-modal v-if="$store.state.auth.authenticated" />
|
|
|
|
<channel-upload-modal v-if="$store.state.auth.authenticated" />
|
|
|
|
<filter-modal v-if="$store.state.auth.authenticated" />
|
|
|
|
<report-modal />
|
|
|
|
<shortcuts-modal
|
|
|
|
:show="showShortcutsModal"
|
|
|
|
@update:show="showShortcutsModal = $event"
|
|
|
|
/>
|
|
|
|
<GlobalEvents @keydown.h.exact="showShortcutsModal = !showShortcutsModal" />
|
2017-06-23 21:00:42 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2018-06-03 16:01:42 +00:00
|
|
|
import axios from 'axios'
|
2022-02-21 21:49:02 +00:00
|
|
|
import _ from 'lodash'
|
2021-11-26 11:01:58 +00:00
|
|
|
import { mapState, mapGetters } from 'vuex'
|
2022-04-16 08:56:26 +00:00
|
|
|
import { useWebSocket, whenever } from '@vueuse/core'
|
2022-02-21 14:07:07 +00:00
|
|
|
import GlobalEvents from '@/components/utils/global-events.vue'
|
2018-12-19 20:45:12 +00:00
|
|
|
import locales from './locales'
|
2021-11-26 11:01:58 +00:00
|
|
|
import { getClientOnlyRadio } from '@/radios'
|
2018-03-20 18:57:34 +00:00
|
|
|
|
2022-02-21 17:00:40 +00:00
|
|
|
import Player from '@/components/audio/Player.vue'
|
|
|
|
import Queue from '@/components/Queue.vue'
|
|
|
|
import PlaylistModal from '@/components/playlists/PlaylistModal.vue'
|
2022-02-21 18:53:34 +00:00
|
|
|
import ChannelUploadModal from '@/components/channels/UploadModal.vue'
|
2022-02-21 17:00:40 +00:00
|
|
|
import Sidebar from '@/components/Sidebar.vue'
|
|
|
|
import ServiceMessages from '@/components/ServiceMessages.vue'
|
|
|
|
import SetInstanceModal from '@/components/SetInstanceModal.vue'
|
2022-02-21 18:53:34 +00:00
|
|
|
import ShortcutsModal from '@/components/ShortcutsModal.vue'
|
2022-02-21 17:00:40 +00:00
|
|
|
import FilterModal from '@/components/moderation/FilterModal.vue'
|
|
|
|
import ReportModal from '@/components/moderation/ReportModal.vue'
|
2022-04-16 08:56:26 +00:00
|
|
|
import { watch, watchEffect } from '@vue/composition-api'
|
2022-02-21 17:00:40 +00:00
|
|
|
|
2017-06-23 21:00:42 +00:00
|
|
|
export default {
|
2021-11-26 11:01:58 +00:00
|
|
|
name: 'App',
|
2018-02-17 20:23:45 +00:00
|
|
|
components: {
|
2022-02-21 17:00:40 +00:00
|
|
|
Player,
|
|
|
|
Queue,
|
|
|
|
PlaylistModal,
|
|
|
|
ChannelUploadModal,
|
|
|
|
Sidebar,
|
|
|
|
ServiceMessages,
|
|
|
|
SetInstanceModal,
|
|
|
|
ShortcutsModal,
|
|
|
|
FilterModal,
|
|
|
|
ReportModal,
|
2021-11-26 11:01:58 +00:00
|
|
|
GlobalEvents
|
2018-02-17 20:23:45 +00:00
|
|
|
},
|
2022-04-16 08:56:26 +00:00
|
|
|
setup (props, { root }) {
|
|
|
|
const store = root.$store
|
|
|
|
|
|
|
|
const url = store.getters['instance/absoluteUrl']('api/v1/activity')
|
|
|
|
.replace(/^http/, 'ws')
|
|
|
|
|
|
|
|
const { data, status, open, close } = useWebSocket(url, {
|
|
|
|
autoReconnect: true,
|
|
|
|
immediate: false
|
|
|
|
})
|
|
|
|
|
|
|
|
watch(() => store.state.auth.authenticated, (authenticated) => {
|
|
|
|
if (authenticated) return open()
|
|
|
|
close()
|
|
|
|
})
|
|
|
|
|
|
|
|
whenever(data, () => {
|
|
|
|
store.dispatch('ui/websocketEvent', JSON.parse(data.value))
|
|
|
|
})
|
|
|
|
|
|
|
|
watchEffect(() => {
|
|
|
|
console.log('Websocket status:', status.value)
|
|
|
|
})
|
|
|
|
},
|
2018-06-03 16:01:42 +00:00
|
|
|
data () {
|
|
|
|
return {
|
2018-11-16 17:22:07 +00:00
|
|
|
instanceUrl: null,
|
|
|
|
showShortcutsModal: false,
|
2020-01-08 11:16:41 +00:00
|
|
|
showSetInstanceModal: false,
|
2020-05-05 22:23:42 +00:00
|
|
|
initialTitle: document.title,
|
2021-05-20 17:59:31 +00:00
|
|
|
width: window.innerWidth
|
2018-06-03 16:01:42 +00:00
|
|
|
}
|
|
|
|
},
|
2021-11-26 11:01:58 +00:00
|
|
|
computed: {
|
|
|
|
...mapState({
|
|
|
|
messages: state => state.ui.messages,
|
|
|
|
nodeinfo: state => state.instance.nodeinfo,
|
|
|
|
playing: state => state.player.playing,
|
|
|
|
bufferProgress: state => state.player.bufferProgress,
|
|
|
|
isLoadingAudio: state => state.player.isLoadingAudio,
|
|
|
|
serviceWorker: state => state.ui.serviceWorker
|
|
|
|
}),
|
|
|
|
...mapGetters({
|
|
|
|
hasNext: 'queue/hasNext',
|
|
|
|
currentTrack: 'queue/currentTrack',
|
|
|
|
progress: 'player/progress'
|
|
|
|
}),
|
|
|
|
labels () {
|
|
|
|
const play = this.$pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Play track')
|
|
|
|
const pause = this.$pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Pause track')
|
|
|
|
const next = this.$pgettext('Sidebar/Player/Icon.Tooltip', 'Next track')
|
|
|
|
const expandQueue = this.$pgettext('Sidebar/Player/Icon.Tooltip/Verb', 'Expand queue')
|
|
|
|
return {
|
|
|
|
play,
|
|
|
|
pause,
|
|
|
|
next,
|
|
|
|
expandQueue
|
|
|
|
}
|
|
|
|
},
|
|
|
|
suggestedInstances () {
|
|
|
|
const instances = this.$store.state.instance.knownInstances.slice(0)
|
|
|
|
if (this.$store.state.instance.frontSettings.defaultServerUrl) {
|
|
|
|
let serverUrl = this.$store.state.instance.frontSettings.defaultServerUrl
|
|
|
|
if (!serverUrl.endsWith('/')) {
|
|
|
|
serverUrl = serverUrl + '/'
|
|
|
|
}
|
|
|
|
instances.push(serverUrl)
|
|
|
|
}
|
|
|
|
instances.push(this.$store.getters['instance/defaultUrl'](), 'https://demo.funkwhale.audio/')
|
|
|
|
return _.uniq(instances.filter((e) => { return e }))
|
|
|
|
},
|
|
|
|
version () {
|
|
|
|
if (!this.nodeinfo) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
return _.get(this.nodeinfo, 'software.version')
|
|
|
|
},
|
|
|
|
customStylesheets () {
|
|
|
|
if (this.$store.state.instance.frontSettings) {
|
|
|
|
return this.$store.state.instance.frontSettings.additionalStylesheets || []
|
|
|
|
}
|
|
|
|
return null
|
2022-01-04 09:14:05 +00:00
|
|
|
},
|
|
|
|
matchDarkColorScheme () {
|
|
|
|
if (window.matchMedia) {
|
|
|
|
return window.matchMedia('(prefers-color-scheme: dark)')
|
|
|
|
}
|
|
|
|
return null
|
2021-11-26 11:01:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
'$store.state.instance.instanceUrl' (v) {
|
|
|
|
this.$store.dispatch('instance/fetchSettings')
|
|
|
|
this.fetchNodeInfo()
|
|
|
|
},
|
|
|
|
'$store.state.ui.theme': {
|
|
|
|
immediate: true,
|
2022-01-04 09:14:05 +00:00
|
|
|
handler (newValue) {
|
|
|
|
const matchesDark = this.matchDarkColorScheme
|
|
|
|
if (matchesDark) {
|
|
|
|
if (newValue === 'system') {
|
|
|
|
newValue = matchesDark.matches ? 'dark' : 'light'
|
|
|
|
matchesDark.addEventListener('change', this.handleThemeChange)
|
|
|
|
} else {
|
|
|
|
matchesDark.removeEventListener('change', this.handleThemeChange)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (newValue === 'system') {
|
|
|
|
newValue = 'light'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.setTheme(newValue)
|
2021-11-26 11:01:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
'$store.state.ui.currentLanguage': {
|
|
|
|
immediate: true,
|
|
|
|
handler (newValue) {
|
|
|
|
const self = this
|
|
|
|
const htmlLocale = newValue.toLowerCase().replace('_', '-')
|
|
|
|
document.documentElement.setAttribute('lang', htmlLocale)
|
|
|
|
if (newValue === 'en_US') {
|
|
|
|
self.$language.current = 'noop'
|
|
|
|
self.$language.current = newValue
|
|
|
|
return self.$store.commit('ui/momentLocale', 'en')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
currentTrack: {
|
|
|
|
immediate: true,
|
|
|
|
handler (newValue) {
|
|
|
|
this.updateDocumentTitle()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'$store.state.ui.pageTitle': {
|
|
|
|
immediate: true,
|
|
|
|
handler (newValue) {
|
|
|
|
this.updateDocumentTitle()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'serviceWorker.updateAvailable': {
|
|
|
|
handler (v) {
|
|
|
|
if (!v) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const self = this
|
|
|
|
this.$store.commit('ui/addMessage', {
|
|
|
|
content: this.$pgettext('App/Message/Paragraph', 'A new version of the app is available.'),
|
|
|
|
date: new Date(),
|
|
|
|
key: 'refreshApp',
|
|
|
|
displayTime: 0,
|
|
|
|
classActions: 'bottom attached opaque',
|
|
|
|
actions: [
|
|
|
|
{
|
|
|
|
text: this.$pgettext('App/Message/Paragraph', 'Update'),
|
|
|
|
class: 'primary',
|
|
|
|
click: function () {
|
|
|
|
self.updateApp()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
text: this.$pgettext('App/Message/Paragraph', 'Later'),
|
|
|
|
class: 'basic'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
})
|
|
|
|
},
|
|
|
|
immediate: true
|
|
|
|
}
|
|
|
|
},
|
2019-09-23 09:14:54 +00:00
|
|
|
async created () {
|
2020-01-08 11:16:41 +00:00
|
|
|
if (navigator.serviceWorker) {
|
|
|
|
navigator.serviceWorker.addEventListener(
|
|
|
|
'controllerchange', () => {
|
2021-11-26 11:01:58 +00:00
|
|
|
if (this.serviceWorker.refreshing) return
|
2020-01-08 11:16:41 +00:00
|
|
|
this.$store.commit('ui/serviceWorker', {
|
|
|
|
refreshing: true
|
|
|
|
})
|
2021-11-26 11:01:58 +00:00
|
|
|
window.location.reload()
|
2020-01-08 11:16:41 +00:00
|
|
|
}
|
2021-11-26 11:01:58 +00:00
|
|
|
)
|
2020-01-08 11:16:41 +00:00
|
|
|
}
|
2021-11-26 11:01:58 +00:00
|
|
|
window.addEventListener('resize', this.handleResize)
|
|
|
|
this.handleResize()
|
|
|
|
const self = this
|
2019-09-11 10:30:31 +00:00
|
|
|
if (!this.$store.state.ui.selectedLanguage) {
|
|
|
|
this.autodetectLanguage()
|
|
|
|
}
|
2018-03-01 22:46:32 +00:00
|
|
|
setInterval(() => {
|
|
|
|
// used to redraw ago dates every minute
|
|
|
|
self.$store.commit('ui/computeLastDate')
|
|
|
|
}, 1000 * 60)
|
2021-11-26 11:01:58 +00:00
|
|
|
const urlParams = new URLSearchParams(window.location.search)
|
2019-09-23 09:14:54 +00:00
|
|
|
const serverUrl = urlParams.get('_server')
|
|
|
|
if (serverUrl) {
|
|
|
|
this.$store.commit('instance/instanceUrl', serverUrl)
|
|
|
|
}
|
2019-12-26 10:38:26 +00:00
|
|
|
const url = urlParams.get('_url')
|
|
|
|
if (url) {
|
2022-04-16 08:56:26 +00:00
|
|
|
await this.$router.replace(url)
|
2021-11-26 11:01:58 +00:00
|
|
|
} else if (!this.$store.state.instance.instanceUrl) {
|
2019-01-15 13:56:51 +00:00
|
|
|
// we have several way to guess the API server url. By order of precedence:
|
|
|
|
// 1. use the url provided in settings.json, if any
|
|
|
|
// 2. use the url specified when building via VUE_APP_INSTANCE_URL
|
|
|
|
// 3. use the current url
|
2022-02-21 14:07:07 +00:00
|
|
|
const defaultInstanceUrl =
|
|
|
|
this.$store.state.instance.frontSettings.defaultServerUrl ||
|
2022-02-21 22:23:13 +00:00
|
|
|
import.meta.env.VUE_APP_INSTANCE_URL || this.$store.getters['instance/defaultUrl']()
|
2018-08-21 16:22:57 +00:00
|
|
|
this.$store.commit('instance/instanceUrl', defaultInstanceUrl)
|
2018-08-21 18:24:35 +00:00
|
|
|
} else {
|
2020-01-09 11:33:24 +00:00
|
|
|
// needed to trigger initialization of axios / service worker
|
2018-08-21 18:24:35 +00:00
|
|
|
this.$store.commit('instance/instanceUrl', this.$store.state.instance.instanceUrl)
|
2018-06-23 05:24:34 +00:00
|
|
|
}
|
2019-09-23 09:14:54 +00:00
|
|
|
await this.fetchNodeInfo()
|
2018-08-21 16:22:57 +00:00
|
|
|
this.$store.dispatch('instance/fetchSettings')
|
2018-09-13 15:18:23 +00:00
|
|
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
|
|
|
eventName: 'inbox.item_added',
|
|
|
|
id: 'sidebarCount',
|
|
|
|
handler: this.incrementNotificationCountInSidebar
|
|
|
|
})
|
2019-02-28 08:31:04 +00:00
|
|
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
|
|
|
eventName: 'mutation.created',
|
|
|
|
id: 'sidebarReviewEditCount',
|
|
|
|
handler: this.incrementReviewEditCountInSidebar
|
|
|
|
})
|
|
|
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
|
|
|
eventName: 'mutation.updated',
|
|
|
|
id: 'sidebarReviewEditCount',
|
|
|
|
handler: this.incrementReviewEditCountInSidebar
|
|
|
|
})
|
2019-09-13 04:09:48 +00:00
|
|
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
|
|
|
eventName: 'report.created',
|
|
|
|
id: 'sidebarPendingReviewReportCount',
|
|
|
|
handler: this.incrementPendingReviewReportsCountInSidebar
|
|
|
|
})
|
2020-03-18 10:57:33 +00:00
|
|
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
|
|
|
eventName: 'user_request.created',
|
|
|
|
id: 'sidebarPendingReviewRequestCount',
|
|
|
|
handler: this.incrementPendingReviewRequestsCountInSidebar
|
|
|
|
})
|
2020-03-25 21:24:31 +00:00
|
|
|
this.$store.commit('ui/addWebsocketEventHandler', {
|
|
|
|
eventName: 'Listen',
|
|
|
|
id: 'handleListen',
|
|
|
|
handler: this.handleListen
|
|
|
|
})
|
2018-09-13 15:18:23 +00:00
|
|
|
},
|
2019-02-25 13:28:25 +00:00
|
|
|
mounted () {
|
2021-11-26 11:01:58 +00:00
|
|
|
const self = this
|
2019-02-25 13:28:25 +00:00
|
|
|
// slight hack to allow use to have internal links in <translate> tags
|
|
|
|
// while preserving router behaviour
|
|
|
|
document.documentElement.addEventListener('click', function (event) {
|
2021-11-26 11:01:58 +00:00
|
|
|
if (!event.target.matches('a.internal')) return
|
2019-02-25 13:28:25 +00:00
|
|
|
self.$router.push(event.target.getAttribute('href'))
|
2021-11-26 11:01:58 +00:00
|
|
|
event.preventDefault()
|
|
|
|
}, false)
|
2019-12-26 10:38:26 +00:00
|
|
|
this.$nextTick(() => {
|
|
|
|
document.getElementById('fake-content').classList.add('loaded')
|
|
|
|
})
|
2019-02-25 13:28:25 +00:00
|
|
|
},
|
2018-09-13 15:18:23 +00:00
|
|
|
destroyed () {
|
|
|
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
|
|
|
eventName: 'inbox.item_added',
|
2021-11-26 11:01:58 +00:00
|
|
|
id: 'sidebarCount'
|
2018-09-13 15:18:23 +00:00
|
|
|
})
|
2019-02-28 08:31:04 +00:00
|
|
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
|
|
|
eventName: 'mutation.created',
|
2021-11-26 11:01:58 +00:00
|
|
|
id: 'sidebarReviewEditCount'
|
2019-02-28 08:31:04 +00:00
|
|
|
})
|
|
|
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
|
|
|
eventName: 'mutation.updated',
|
2021-11-26 11:01:58 +00:00
|
|
|
id: 'sidebarReviewEditCount'
|
2019-02-28 08:31:04 +00:00
|
|
|
})
|
2019-09-13 04:09:48 +00:00
|
|
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
|
|
|
eventName: 'mutation.updated',
|
2021-11-26 11:01:58 +00:00
|
|
|
id: 'sidebarPendingReviewReportCount'
|
2019-09-13 04:09:48 +00:00
|
|
|
})
|
2020-03-18 10:57:33 +00:00
|
|
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
|
|
|
eventName: 'user_request.created',
|
2021-11-26 11:01:58 +00:00
|
|
|
id: 'sidebarPendingReviewRequestCount'
|
2020-03-18 10:57:33 +00:00
|
|
|
})
|
2020-03-25 21:24:31 +00:00
|
|
|
this.$store.commit('ui/removeWebsocketEventHandler', {
|
|
|
|
eventName: 'Listen',
|
2021-11-26 11:01:58 +00:00
|
|
|
id: 'handleListen'
|
2020-03-25 21:24:31 +00:00
|
|
|
})
|
2018-06-03 16:01:42 +00:00
|
|
|
},
|
|
|
|
methods: {
|
2018-09-13 15:18:23 +00:00
|
|
|
incrementNotificationCountInSidebar (event) {
|
2021-11-26 11:01:58 +00:00
|
|
|
this.$store.commit('ui/incrementNotifications', { type: 'inbox', count: 1 })
|
2018-09-13 15:18:23 +00:00
|
|
|
},
|
2019-02-28 08:31:04 +00:00
|
|
|
incrementReviewEditCountInSidebar (event) {
|
2021-11-26 11:01:58 +00:00
|
|
|
this.$store.commit('ui/incrementNotifications', { type: 'pendingReviewEdits', value: event.pending_review_count })
|
2019-02-28 08:31:04 +00:00
|
|
|
},
|
2019-09-13 04:09:48 +00:00
|
|
|
incrementPendingReviewReportsCountInSidebar (event) {
|
2021-11-26 11:01:58 +00:00
|
|
|
this.$store.commit('ui/incrementNotifications', { type: 'pendingReviewReports', value: event.unresolved_count })
|
2019-09-13 04:09:48 +00:00
|
|
|
},
|
2020-03-18 10:57:33 +00:00
|
|
|
incrementPendingReviewRequestsCountInSidebar (event) {
|
2021-11-26 11:01:58 +00:00
|
|
|
this.$store.commit('ui/incrementNotifications', { type: 'pendingReviewRequests', value: event.pending_count })
|
2020-03-18 10:57:33 +00:00
|
|
|
},
|
2020-03-25 21:24:31 +00:00
|
|
|
handleListen (event) {
|
|
|
|
if (this.$store.state.radios.current && this.$store.state.radios.running) {
|
2021-11-26 11:01:58 +00:00
|
|
|
const current = this.$store.state.radios.current
|
2020-03-25 21:24:31 +00:00
|
|
|
if (current.clientOnly && current.type === 'account') {
|
|
|
|
getClientOnlyRadio(current).handleListen(current, event, this.$store)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2019-09-23 09:14:54 +00:00
|
|
|
async fetchNodeInfo () {
|
2021-11-26 11:01:58 +00:00
|
|
|
const response = await axios.get('instance/nodeinfo/2.0/')
|
2019-09-23 09:14:54 +00:00
|
|
|
this.$store.commit('instance/nodeinfo', response.data)
|
2018-06-23 05:24:34 +00:00
|
|
|
},
|
2018-07-22 15:46:00 +00:00
|
|
|
autodetectLanguage () {
|
2021-11-26 11:01:58 +00:00
|
|
|
const userLanguage = navigator.language || navigator.userLanguage
|
|
|
|
const available = locales.locales.map(e => { return e.code })
|
2018-12-27 22:13:29 +00:00
|
|
|
let candidate
|
2021-11-26 11:01:58 +00:00
|
|
|
const matching = available.filter((a) => {
|
2018-07-22 15:46:00 +00:00
|
|
|
return userLanguage.replace('-', '_') === a
|
|
|
|
})
|
2021-11-26 11:01:58 +00:00
|
|
|
const almostMatching = available.filter((a) => {
|
2018-07-22 15:46:00 +00:00
|
|
|
return userLanguage.replace('-', '_').split('_')[0] === a.split('_')[0]
|
|
|
|
})
|
|
|
|
if (matching.length > 0) {
|
2018-12-27 22:13:29 +00:00
|
|
|
candidate = matching[0]
|
2018-07-22 15:46:00 +00:00
|
|
|
} else if (almostMatching.length > 0) {
|
2018-12-27 22:13:29 +00:00
|
|
|
candidate = almostMatching[0]
|
|
|
|
} else {
|
|
|
|
return
|
2018-07-22 15:46:00 +00:00
|
|
|
}
|
2019-01-25 10:34:30 +00:00
|
|
|
this.$store.commit('ui/currentLanguage', candidate)
|
2018-09-13 15:18:23 +00:00
|
|
|
},
|
2021-11-26 11:01:58 +00:00
|
|
|
getTrackInformationText (track) {
|
2019-04-08 08:01:21 +00:00
|
|
|
const trackTitle = track.title
|
2020-02-05 14:06:07 +00:00
|
|
|
const albumArtist = (track.album) ? track.album.artist.name : null
|
2019-04-08 08:01:21 +00:00
|
|
|
const artistName = (
|
2020-02-05 14:06:07 +00:00
|
|
|
(track.artist) ? track.artist.name : albumArtist)
|
2022-02-21 18:53:34 +00:00
|
|
|
const text = `♫ ${trackTitle} – ${artistName} ♫`
|
2019-04-08 08:01:21 +00:00
|
|
|
return text
|
|
|
|
},
|
2021-11-26 11:01:58 +00:00
|
|
|
updateDocumentTitle () {
|
|
|
|
const parts = []
|
2019-04-08 08:01:21 +00:00
|
|
|
const currentTrackPart = (
|
2021-11-26 11:01:58 +00:00
|
|
|
(this.currentTrack)
|
|
|
|
? this.getTrackInformationText(this.currentTrack)
|
|
|
|
: null)
|
2019-04-08 08:01:21 +00:00
|
|
|
if (currentTrackPart) {
|
|
|
|
parts.push(currentTrackPart)
|
|
|
|
}
|
|
|
|
if (this.$store.state.ui.pageTitle) {
|
|
|
|
parts.push(this.$store.state.ui.pageTitle)
|
|
|
|
}
|
2020-05-05 22:23:42 +00:00
|
|
|
parts.push(this.initialTitle || 'Funkwhale')
|
2019-04-08 08:01:21 +00:00
|
|
|
document.title = parts.join(' – ')
|
|
|
|
},
|
2020-02-25 13:43:14 +00:00
|
|
|
|
2020-01-08 11:16:41 +00:00
|
|
|
updateApp () {
|
2021-11-26 11:01:58 +00:00
|
|
|
this.$store.commit('ui/serviceWorker', { updateAvailable: false })
|
|
|
|
if (!this.serviceWorker.registration || !this.serviceWorker.registration.waiting) { return }
|
|
|
|
this.serviceWorker.registration.waiting.postMessage({ command: 'skipWaiting' })
|
2021-05-20 17:59:31 +00:00
|
|
|
},
|
2021-11-26 11:01:58 +00:00
|
|
|
handleResize () {
|
2021-05-20 17:59:31 +00:00
|
|
|
this.width = window.innerWidth
|
2022-01-04 09:14:05 +00:00
|
|
|
},
|
|
|
|
handleThemeChange (event) {
|
|
|
|
this.setTheme(event.matches ? 'dark' : 'light')
|
|
|
|
},
|
|
|
|
setTheme (theme) {
|
|
|
|
const oldTheme = (theme === 'light') ? 'dark' : 'light'
|
2022-02-21 18:53:34 +00:00
|
|
|
document.body.classList.remove(`theme-${oldTheme}`)
|
|
|
|
document.body.classList.add(`theme-${theme}`)
|
2020-01-08 11:16:41 +00:00
|
|
|
}
|
2018-02-17 20:22:52 +00:00
|
|
|
}
|
2017-06-23 21:00:42 +00:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss">
|
2018-12-19 21:04:35 +00:00
|
|
|
@import "style/_main";
|
2019-12-26 10:38:26 +00:00
|
|
|
|
2017-06-23 21:00:42 +00:00
|
|
|
</style>
|