Migrate to vue3 (fix #126) #127
1067
package-lock.json
generated
1067
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppContent } from '@nextcloud/vue'
|
import { NcAppContent } from '@nextcloud/vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppContent',
|
name: 'AppContent',
|
||||||
@ -13,9 +15,7 @@ export default {
|
|||||||
NcAppContent,
|
NcAppContent,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
episode() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player.episode
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppNavigation } from '@nextcloud/vue'
|
import { NcAppNavigation } from '@nextcloud/vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigation',
|
name: 'AppNavigation',
|
||||||
@ -19,9 +21,7 @@ export default {
|
|||||||
NcAppNavigation,
|
NcAppNavigation,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
episode() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player.episode
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<NcActionButton
|
<NcActionButton
|
||||||
v-if="!isSubscribed(feed.link)"
|
v-if="!subscriptions.includes(feed.link)"
|
||||||
:aria-label="t('repod', 'Subscribe')"
|
:aria-label="t('repod', 'Subscribe')"
|
||||||
:name="t('repod', 'Subscribe')"
|
:name="t('repod', 'Subscribe')"
|
||||||
:title="t('repod', 'Subscribe')"
|
:title="t('repod', 'Subscribe')"
|
||||||
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcActionButton, NcAvatar, NcListItem } from '@nextcloud/vue'
|
import { NcActionButton, NcAvatar, NcListItem } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
@ -44,6 +45,7 @@ import { formatLocaleDate } from '../../utils/time.js'
|
|||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { showError } from '../../utils/toast.js'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
@ -66,12 +68,16 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useSubscriptions, ['subscriptions']),
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value() {
|
value() {
|
||||||
this.search()
|
this.search()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
toUrl,
|
toUrl,
|
||||||
async addSubscription(url) {
|
async addSubscription(url) {
|
||||||
@ -88,10 +94,7 @@ export default {
|
|||||||
showError(t('repod', 'Error while adding the feed'))
|
showError(t('repod', 'Error while adding the feed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('subscriptions/fetch')
|
this.fetch()
|
||||||
},
|
|
||||||
isSubscribed(url) {
|
|
||||||
return this.$store.state.subscriptions.subscriptions.includes(url)
|
|
||||||
},
|
},
|
||||||
search: debounce(async function value() {
|
search: debounce(async function value() {
|
||||||
try {
|
try {
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<SafeHtml :source="description" />
|
<SafeHtml :source="description" />
|
||||||
</div>
|
</div>
|
||||||
<NcAppNavigationNew
|
<NcAppNavigationNew
|
||||||
v-if="!isSubscribed"
|
v-if="!subscriptions.includes(url)"
|
||||||
:text="t('repod', 'Subscribe')"
|
:text="t('repod', 'Subscribe')"
|
||||||
@click="addSubscription">
|
@click="addSubscription">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppNavigationNew, NcAvatar } from '@nextcloud/vue'
|
import { NcAppNavigationNew, NcAvatar } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import { showError, showSuccess } from '../../utils/toast.js'
|
import { showError, showSuccess } from '../../utils/toast.js'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import RssIcon from 'vue-material-design-icons/Rss.vue'
|
import RssIcon from 'vue-material-design-icons/Rss.vue'
|
||||||
@ -44,6 +45,7 @@ import SafeHtml from '../Atoms/SafeHtml.vue'
|
|||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { decodeUrl } from '../../utils/url.js'
|
import { decodeUrl } from '../../utils/url.js'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Banner',
|
name: 'Banner',
|
||||||
@ -77,14 +79,13 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(useSubscriptions, ['subscriptions']),
|
||||||
url() {
|
url() {
|
||||||
return decodeUrl(this.$route.params.url)
|
return decodeUrl(this.$route.params.url)
|
||||||
},
|
},
|
||||||
isSubscribed() {
|
|
||||||
return this.$store.state.subscriptions.subscriptions.includes(this.url)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
async addSubscription() {
|
async addSubscription() {
|
||||||
try {
|
try {
|
||||||
await axios.post(
|
await axios.post(
|
||||||
@ -99,7 +100,7 @@ export default {
|
|||||||
showError(t('repod', 'Error while adding the feed'))
|
showError(t('repod', 'Error while adding the feed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('subscriptions/fetch')
|
this.fetch()
|
||||||
},
|
},
|
||||||
copyFeed() {
|
copyFeed() {
|
||||||
window.navigator.clipboard.writeText(this.url)
|
window.navigator.clipboard.writeText(this.url)
|
||||||
|
@ -122,8 +122,8 @@ import {
|
|||||||
formatEpisodeTimestamp,
|
formatEpisodeTimestamp,
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
} from '../../utils/time.js'
|
} from '../../utils/time.js'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
import DownloadIcon from 'vue-material-design-icons/Download.vue'
|
||||||
import { EventBus } from '../../store/bus.js'
|
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import Modal from '../Atoms/Modal.vue'
|
import Modal from '../Atoms/Modal.vue'
|
||||||
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
|
||||||
@ -135,6 +135,8 @@ import axios from '@nextcloud/axios'
|
|||||||
import { decodeUrl } from '../../utils/url.js'
|
import { decodeUrl } from '../../utils/url.js'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { showError } from '../../utils/toast.js'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
import { useSettings } from '../../store/settings.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Episodes',
|
name: 'Episodes',
|
||||||
@ -163,12 +165,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentEpisode() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player.episode
|
...mapState(useSettings, ['filters']),
|
||||||
},
|
|
||||||
filters() {
|
|
||||||
return this.$store.state.settings.filters
|
|
||||||
},
|
|
||||||
filteredEpisodes() {
|
filteredEpisodes() {
|
||||||
return this.episodes.filter((episode) => {
|
return this.episodes.filter((episode) => {
|
||||||
if (!this.filters.listened && this.hasEnded(episode)) {
|
if (!this.filters.listened && this.hasEnded(episode)) {
|
||||||
@ -201,7 +199,6 @@ export default {
|
|||||||
this.episodes = [...episodes.data].sort(
|
this.episodes = [...episodes.data].sort(
|
||||||
(a, b) => new Date(b.pubDate?.date) - new Date(a.pubDate?.date),
|
(a, b) => new Date(b.pubDate?.date) - new Date(a.pubDate?.date),
|
||||||
)
|
)
|
||||||
EventBus.$on('updateEpisodesList', this.updateList)
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Could not fetch episodes'))
|
showError(t('repod', 'Could not fetch episodes'))
|
||||||
@ -209,10 +206,8 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
EventBus.$off('updateEpisodesList')
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['load']),
|
||||||
formatLocaleDate,
|
formatLocaleDate,
|
||||||
hasEnded(episode) {
|
hasEnded(episode) {
|
||||||
return (
|
return (
|
||||||
@ -233,9 +228,6 @@ export default {
|
|||||||
!this.hasEnded(episode)
|
!this.hasEnded(episode)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
load(episode) {
|
|
||||||
this.$store.dispatch('player/load', episode)
|
|
||||||
},
|
|
||||||
async markAs(episode, read) {
|
async markAs(episode, read) {
|
||||||
try {
|
try {
|
||||||
this.loadingAction = true
|
this.loadingAction = true
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="player.episode" class="footer">
|
<div v-if="episode" class="footer">
|
||||||
<img class="background" :src="player.episode.image" />
|
<img class="background" :src="episode.image" />
|
||||||
<Loading v-if="!player.loaded" />
|
<Loading v-if="!loaded" />
|
||||||
<ProgressBar v-if="player.loaded" />
|
<ProgressBar v-if="loaded" />
|
||||||
<div v-if="player.loaded" class="player">
|
<div v-if="loaded" class="player">
|
||||||
<img :src="player.episode.image" />
|
<img :src="episode.image" />
|
||||||
<Infos class="infos" />
|
<Infos class="infos" />
|
||||||
<Controls class="controls" />
|
<Controls class="controls" />
|
||||||
<Timer class="timer" />
|
<Timer class="timer" />
|
||||||
@ -20,6 +20,8 @@ import Loading from '../Atoms/Loading.vue'
|
|||||||
import ProgressBar from './ProgressBar.vue'
|
import ProgressBar from './ProgressBar.vue'
|
||||||
import Timer from './Timer.vue'
|
import Timer from './Timer.vue'
|
||||||
import Volume from './Volume.vue'
|
import Volume from './Volume.vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Bar',
|
name: 'Bar',
|
||||||
@ -32,9 +34,7 @@ export default {
|
|||||||
Volume,
|
Volume,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['episode', 'loaded']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<PauseIcon
|
<PauseIcon v-if="!paused" class="pointer" :size="50" @click="pause" />
|
||||||
v-if="!player.paused"
|
<PlayIcon v-if="paused" class="pointer" :size="50" @click="play" />
|
||||||
class="pointer"
|
|
||||||
:size="50"
|
|
||||||
@click="$store.dispatch('player/pause')" />
|
|
||||||
<PlayIcon
|
|
||||||
v-if="player.paused"
|
|
||||||
class="pointer"
|
|
||||||
:size="50"
|
|
||||||
@click="$store.dispatch('player/play')" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import PauseIcon from 'vue-material-design-icons/Pause.vue'
|
import PauseIcon from 'vue-material-design-icons/Pause.vue'
|
||||||
import PlayIcon from 'vue-material-design-icons/Play.vue'
|
import PlayIcon from 'vue-material-design-icons/Play.vue'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Controls',
|
name: 'Controls',
|
||||||
@ -24,9 +18,10 @@ export default {
|
|||||||
PlayIcon,
|
PlayIcon,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['paused']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['play', 'pause']),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<strong class="pointer" @click="modal = true">
|
<strong class="pointer" @click="modal = true">
|
||||||
{{ player.episode.name }}
|
{{ episode.name }}
|
||||||
</strong>
|
</strong>
|
||||||
<router-link :to="hash">
|
<router-link :to="hash">
|
||||||
<i>{{ player.episode.title }}</i>
|
<i>{{ episode.title }}</i>
|
||||||
</router-link>
|
</router-link>
|
||||||
<NcModal v-if="modal" @close="modal = false">
|
<NcModal v-if="modal" @close="modal = false">
|
||||||
<Modal
|
<Modal
|
||||||
:description="player.episode.description"
|
:description="episode.description"
|
||||||
:image="player.episode.image"
|
:image="episode.image"
|
||||||
:link="player.episode.link"
|
:link="episode.link"
|
||||||
:name="player.episode.name"
|
:name="episode.name"
|
||||||
:size="player.episode.size"
|
:size="episode.size"
|
||||||
:title="player.episode.title"
|
:title="episode.title"
|
||||||
:url="player.episode.url" />
|
:url="episode.url" />
|
||||||
</NcModal>
|
</NcModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -22,7 +22,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import Modal from '../Atoms/Modal.vue'
|
import Modal from '../Atoms/Modal.vue'
|
||||||
import { NcModal } from '@nextcloud/vue'
|
import { NcModal } from '@nextcloud/vue'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Infos',
|
name: 'Infos',
|
||||||
@ -36,9 +38,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['episode']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
hash() {
|
hash() {
|
||||||
return toUrl(this.player.podcastUrl)
|
return toUrl(this.player.podcastUrl)
|
||||||
},
|
},
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<input
|
<input
|
||||||
class="progress"
|
class="progress"
|
||||||
:max="player.duration"
|
:max="duration"
|
||||||
min="0"
|
min="0"
|
||||||
type="range"
|
type="range"
|
||||||
:value="player.currentTime"
|
:value="currentTime"
|
||||||
@change="(event) => $store.dispatch('player/seek', event.target.value)" />
|
@change="(event) => seek(event.target.value)" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProgressBar',
|
name: 'ProgressBar',
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['duration', 'currentTime']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['seek']),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<span>{{ formatTimer(new Date(player.currentTime * 1000)) }}</span>
|
<span>{{ formatTimer(new Date(currentTime * 1000)) }}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>{{ formatTimer(new Date(player.duration * 1000)) }}</span>
|
<span>{{ formatTimer(new Date(duration * 1000)) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { formatTimer } from '../../utils/time.js'
|
import { formatTimer } from '../../utils/time.js'
|
||||||
|
import { mapState } from 'pinia'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Timer',
|
name: 'Timer',
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['duration', 'currentTime']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatTimer,
|
formatTimer,
|
||||||
|
@ -1,42 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VolumeHighIcon
|
<VolumeHighIcon
|
||||||
v-if="player.volume > 0.7"
|
v-if="volume > 0.7"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="mute" />
|
@click="mute" />
|
||||||
<VolumeLowIcon
|
<VolumeLowIcon
|
||||||
v-if="player.volume > 0 && player.volume <= 0.3"
|
v-if="volume > 0 && volume <= 0.3"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="mute" />
|
@click="mute" />
|
||||||
<VolumeMediumIcon
|
<VolumeMediumIcon
|
||||||
v-if="player.volume > 0.3 && player.volume <= 0.7"
|
v-if="volume > 0.3 && volume <= 0.7"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="mute" />
|
@click="mute" />
|
||||||
<VolumeMuteIcon
|
<VolumeMuteIcon
|
||||||
v-if="player.volume === 0"
|
v-if="volume === 0"
|
||||||
class="pointer"
|
class="pointer"
|
||||||
:size="30"
|
:size="30"
|
||||||
@click="$store.dispatch('player/volume', volumeMuted)" />
|
@click="setVolume(volumeMuted)" />
|
||||||
<input
|
<input
|
||||||
max="1"
|
max="1"
|
||||||
min="0"
|
min="0"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
type="range"
|
type="range"
|
||||||
:value="player.volume"
|
:value="volume"
|
||||||
@change="
|
@change="(event) => setVolume(event.target.value)" />
|
||||||
(event) => $store.dispatch('player/volume', event.target.value)
|
|
||||||
" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import VolumeHighIcon from 'vue-material-design-icons/VolumeHigh.vue'
|
import VolumeHighIcon from 'vue-material-design-icons/VolumeHigh.vue'
|
||||||
import VolumeLowIcon from 'vue-material-design-icons/VolumeLow.vue'
|
import VolumeLowIcon from 'vue-material-design-icons/VolumeLow.vue'
|
||||||
import VolumeMediumIcon from 'vue-material-design-icons/VolumeMedium.vue'
|
import VolumeMediumIcon from 'vue-material-design-icons/VolumeMedium.vue'
|
||||||
import VolumeMuteIcon from 'vue-material-design-icons/VolumeMute.vue'
|
import VolumeMuteIcon from 'vue-material-design-icons/VolumeMute.vue'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Volume',
|
name: 'Volume',
|
||||||
@ -52,14 +52,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['volume']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['setVolume']),
|
||||||
mute() {
|
mute() {
|
||||||
this.volumeMuted = this.player.volume
|
this.volumeMuted = this.volume
|
||||||
this.$store.dispatch('player/volume', 0)
|
this.setVolume(0)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
:disabled="all"
|
:disabled="all"
|
||||||
@update:checked="
|
@update:checked="
|
||||||
(checked) =>
|
(checked) =>
|
||||||
$store.commit('settings/filters', {
|
setFilters({
|
||||||
listened: checked,
|
listened: checked,
|
||||||
listening: checked,
|
listening: checked,
|
||||||
unlistened: checked,
|
unlistened: checked,
|
||||||
@ -19,26 +19,17 @@
|
|||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="filters.listened"
|
:checked="filters.listened"
|
||||||
@update:checked="
|
@update:checked="(checked) => setFilters({ listened: checked })">
|
||||||
(checked) =>
|
|
||||||
$store.commit('settings/filters', { listened: checked })
|
|
||||||
">
|
|
||||||
{{ t('repod', 'Listened') }}
|
{{ t('repod', 'Listened') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="filters.listening"
|
:checked="filters.listening"
|
||||||
@update:checked="
|
@update:checked="(checked) => setFilters({ listening: checked })">
|
||||||
(checked) =>
|
|
||||||
$store.commit('settings/filters', { listening: checked })
|
|
||||||
">
|
|
||||||
{{ t('repod', 'Listening') }}
|
{{ t('repod', 'Listening') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
<NcActionCheckbox
|
<NcActionCheckbox
|
||||||
:checked="filters.unlistened"
|
:checked="filters.unlistened"
|
||||||
@update:checked="
|
@update:checked="(checked) => setFilters({ unlistened: checked })">
|
||||||
(checked) =>
|
|
||||||
$store.commit('settings/filters', { unlistened: checked })
|
|
||||||
">
|
|
||||||
{{ t('repod', 'Unlistened') }}
|
{{ t('repod', 'Unlistened') }}
|
||||||
</NcActionCheckbox>
|
</NcActionCheckbox>
|
||||||
</template>
|
</template>
|
||||||
@ -51,8 +42,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
|
import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import FilterIcon from 'vue-material-design-icons/Filter.vue'
|
import FilterIcon from 'vue-material-design-icons/Filter.vue'
|
||||||
import FilterSettingsIcon from 'vue-material-design-icons/FilterSettings.vue'
|
import FilterSettingsIcon from 'vue-material-design-icons/FilterSettings.vue'
|
||||||
|
import { useSettings } from '../../store/settings.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Filters',
|
name: 'Filters',
|
||||||
@ -63,19 +56,10 @@ export default {
|
|||||||
NcActionCheckbox,
|
NcActionCheckbox,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
all() {
|
...mapState(useSettings, ['filters']),
|
||||||
return (
|
|
||||||
this.filters.listened &&
|
|
||||||
this.filters.listening &&
|
|
||||||
this.filters.unlistened
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
filters() {
|
methods: {
|
||||||
return this.$store.state.settings.filters
|
...mapActions(useSettings, ['setFilters']),
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.$store.dispatch('settings/fetch')
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,27 +3,27 @@
|
|||||||
<template #extra>
|
<template #extra>
|
||||||
<div class="extra">
|
<div class="extra">
|
||||||
<MinusIcon class="pointer" :size="20" @click="changeRate(-0.1)" />
|
<MinusIcon class="pointer" :size="20" @click="changeRate(-0.1)" />
|
||||||
<NcCounterBubble class="counter">
|
<NcCounterBubble class="counter">x{{ rate }}</NcCounterBubble>
|
||||||
x{{ player.rate }}
|
|
||||||
</NcCounterBubble>
|
|
||||||
<PlusIcon class="pointer" :size="20" @click="changeRate(0.1)" />
|
<PlusIcon class="pointer" :size="20" @click="changeRate(0.1)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SpeedometerSlowIcon v-if="player.rate < 1" :size="20" />
|
<SpeedometerSlowIcon v-if="rate < 1" :size="20" />
|
||||||
<SpeedometerMediumIcon v-if="player.rate === 1" :size="20" />
|
<SpeedometerMediumIcon v-if="rate === 1" :size="20" />
|
||||||
<SpeedometerIcon v-if="player.rate > 1" :size="20" />
|
<SpeedometerIcon v-if="rate > 1" :size="20" />
|
||||||
</template>
|
</template>
|
||||||
</NcAppNavigationItem>
|
</NcAppNavigationItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NcAppNavigationItem, NcCounterBubble } from '@nextcloud/vue'
|
import { NcAppNavigationItem, NcCounterBubble } from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import MinusIcon from 'vue-material-design-icons/Minus.vue'
|
import MinusIcon from 'vue-material-design-icons/Minus.vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import SpeedometerIcon from 'vue-material-design-icons/Speedometer.vue'
|
import SpeedometerIcon from 'vue-material-design-icons/Speedometer.vue'
|
||||||
import SpeedometerMediumIcon from 'vue-material-design-icons/SpeedometerMedium.vue'
|
import SpeedometerMediumIcon from 'vue-material-design-icons/SpeedometerMedium.vue'
|
||||||
import SpeedometerSlowIcon from 'vue-material-design-icons/SpeedometerSlow.vue'
|
import SpeedometerSlowIcon from 'vue-material-design-icons/SpeedometerSlow.vue'
|
||||||
|
import { usePlayer } from '../../store/player.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Speed',
|
name: 'Speed',
|
||||||
@ -37,17 +37,13 @@ export default {
|
|||||||
SpeedometerSlowIcon,
|
SpeedometerSlowIcon,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
player() {
|
...mapState(usePlayer, ['rate']),
|
||||||
return this.$store.state.player
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(usePlayer, ['seRate']),
|
||||||
changeRate(diff) {
|
changeRate(diff) {
|
||||||
const newRate = (this.player.rate + diff).toPrecision(2)
|
const newRate = (this.rate + diff).toPrecision(2)
|
||||||
this.$store.dispatch(
|
this.setRate(newRate > 0 ? newRate : this.rate)
|
||||||
'player/rate',
|
|
||||||
newRate > 0 ? newRate : this.player.rate,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ import AlertIcon from 'vue-material-design-icons/Alert.vue'
|
|||||||
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
|
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
|
||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
import { mapActions } from 'pinia'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { showError } from '../../utils/toast.js'
|
||||||
import { toUrl } from '../../utils/url.js'
|
import { toUrl } from '../../utils/url.js'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Item',
|
name: 'Item',
|
||||||
@ -80,6 +82,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
async deleteSubscription() {
|
async deleteSubscription() {
|
||||||
if (
|
if (
|
||||||
confirm(
|
confirm(
|
||||||
@ -97,7 +100,7 @@ export default {
|
|||||||
showError(t('repod', 'Error while removing the feed'))
|
showError(t('repod', 'Error while removing the feed'))
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.$store.dispatch('subscriptions/fetch')
|
this.fetch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -30,12 +30,14 @@ import {
|
|||||||
NcAppNavigationList,
|
NcAppNavigationList,
|
||||||
NcAppNavigationNew,
|
NcAppNavigationNew,
|
||||||
} from '@nextcloud/vue'
|
} from '@nextcloud/vue'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
import AppNavigation from '../Atoms/AppNavigation.vue'
|
import AppNavigation from '../Atoms/AppNavigation.vue'
|
||||||
import Item from './Item.vue'
|
import Item from './Item.vue'
|
||||||
import Loading from '../Atoms/Loading.vue'
|
import Loading from '../Atoms/Loading.vue'
|
||||||
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
||||||
import Settings from '../Settings/Settings.vue'
|
import Settings from '../Settings/Settings.vue'
|
||||||
import { showError } from '../../utils/toast.js'
|
import { showError } from '../../utils/toast.js'
|
||||||
|
import { useSubscriptions } from '../../store/subscriptions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Subscriptions',
|
name: 'Subscriptions',
|
||||||
@ -55,13 +57,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
subscriptions() {
|
...mapState(useSubscriptions, ['subscriptions']),
|
||||||
return this.$store.state.subscriptions.subscriptions
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
await this.$store.dispatch('subscriptions/fetch')
|
await this.fetch()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
showError(t('repod', 'Could not fetch subscriptions'))
|
showError(t('repod', 'Could not fetch subscriptions'))
|
||||||
@ -69,5 +69,8 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useSubscriptions, ['fetch']),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -86,10 +86,10 @@ export const usePlayer = defineStore('player', {
|
|||||||
this.episode.action,
|
this.episode.action,
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
volume: (volume) => {
|
setVolume: (volume) => {
|
||||||
audio.volume = volume
|
audio.volume = volume
|
||||||
},
|
},
|
||||||
rate: (rate) => {
|
setRate: (rate) => {
|
||||||
audio.playbackRate = rate
|
audio.playbackRate = rate
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,28 +1,24 @@
|
|||||||
import { getCookie, setCookie } from '../utils/cookies.js'
|
import { getCookie, setCookie } from '../utils/cookies.js'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
export const settings = {
|
export const useSettings = defineStore('settings', {
|
||||||
namespaced: true,
|
state: () => ({
|
||||||
state: {
|
|
||||||
filters: {
|
filters: {
|
||||||
listened: true,
|
listened: true,
|
||||||
listening: true,
|
listening: true,
|
||||||
unlistened: true,
|
unlistened: true,
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
mutations: {
|
|
||||||
filters: (state, filters) => {
|
|
||||||
state.filters = { ...state.filters, ...filters }
|
|
||||||
setCookie('repod.filters', JSON.stringify(state.filters), 365)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
fetch: (context) => {
|
setFilters: (filters) => {
|
||||||
|
this.filters = { ...this.filters, ...filters }
|
||||||
|
setCookie('repod.filters', JSON.stringify(this.filters), 365)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const settings = useSettings()
|
||||||
const filters = getCookie('repod.filters')
|
const filters = getCookie('repod.filters')
|
||||||
context.commit('filters', JSON.parse(filters))
|
settings.filters = JSON.parse(filters)
|
||||||
} catch (e) {
|
} catch {}
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
@ -1,28 +1,20 @@
|
|||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
import { generateUrl } from '@nextcloud/router'
|
import { generateUrl } from '@nextcloud/router'
|
||||||
|
|
||||||
export const subscriptions = {
|
export const useSubscriptions = defineStore('subscriptions', {
|
||||||
namespaced: true,
|
state: () => ({
|
||||||
state: {
|
|
||||||
subscriptions: [],
|
subscriptions: [],
|
||||||
},
|
}),
|
||||||
mutations: {
|
|
||||||
set: (state, subscriptions) => {
|
|
||||||
state.subscriptions = subscriptions
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
fetch: async (context) => {
|
fetch: async () => {
|
||||||
const metrics = await axios.get(
|
const metrics = await axios.get(
|
||||||
generateUrl('/apps/gpoddersync/personal_settings/metrics'),
|
generateUrl('/apps/gpoddersync/personal_settings/metrics'),
|
||||||
)
|
)
|
||||||
const subs = [...metrics.data.subscriptions].sort(
|
const subs = [...metrics.data.subscriptions].sort(
|
||||||
(a, b) => b.listenedSeconds - a.listenedSeconds,
|
(a, b) => b.listenedSeconds - a.listenedSeconds,
|
||||||
)
|
)
|
||||||
context.commit(
|
this.subscriptions = subs.map((sub) => sub.url)
|
||||||
'set',
|
|
||||||
subs.map((sub) => sub.url),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user