refactor: 🏗️ rework to use pinia
Some checks failed
repod / xml (push) Successful in 1m38s
repod / php (push) Successful in 1m2s
repod / nodejs (push) Failing after 57s
repod / release (push) Has been skipped

This commit is contained in:
Michel Roux 2024-08-09 09:38:00 +00:00
parent 1530e8b294
commit 75da02e05b
19 changed files with 1101 additions and 270 deletions

1067
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -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>

View File

@ -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 {

View File

@ -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)

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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)
}, },

View File

@ -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>

View File

@ -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,

View File

@ -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)
}, },
}, },
} }

View File

@ -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() {
return this.$store.state.settings.filters
},
}, },
mounted() { methods: {
this.$store.dispatch('settings/fetch') ...mapActions(useSettings, ['setFilters']),
}, },
} }
</script> </script>

View File

@ -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,
)
}, },
}, },
} }

View File

@ -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()
} }
} }
}, },

View File

@ -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>

View File

@ -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
}, },
}, },

View File

@ -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) => {
try { this.filters = { ...this.filters, ...filters }
const filters = getCookie('repod.filters') setCookie('repod.filters', JSON.stringify(this.filters), 365)
context.commit('filters', JSON.parse(filters))
} catch (e) {
// nothing
}
}, },
}, },
} })
try {
const settings = useSettings()
const filters = getCookie('repod.filters')
settings.filters = JSON.parse(filters)
} catch {}

View File

@ -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),
)
}, },
}, },
} })