new homepage based on favorites (fixes #130 #59) #131

Merged
Xefir merged 23 commits from favorites into main 2024-09-02 09:28:09 +00:00
9 changed files with 102 additions and 29 deletions
Showing only changes of commit a30678bfd2 - Show all commits

View File

@ -19,7 +19,7 @@
</template> </template>
<template #actions> <template #actions>
<NcActionButton <NcActionButton
v-if="!subscriptions.includes(feed.link)" v-if="!subs.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')"
@ -69,7 +69,7 @@ export default {
} }
}, },
computed: { computed: {
...mapState(useSubscriptions, ['subscriptions']), ...mapState(useSubscriptions, ['subs']),
}, },
watch: { watch: {
value() { value() {

View File

@ -23,7 +23,7 @@
<SafeHtml :source="description" /> <SafeHtml :source="description" />
</div> </div>
<NcAppNavigationNew <NcAppNavigationNew
v-if="!subscriptions.includes(url)" v-if="!subs.includes(url)"
:text="t('repod', 'Subscribe')" :text="t('repod', 'Subscribe')"
@click="addSubscription"> @click="addSubscription">
<template #icon> <template #icon>
@ -79,7 +79,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(useSubscriptions, ['subscriptions']), ...mapState(useSubscriptions, ['subs']),
url() { url() {
return decodeUrl(this.$route.params.url) return decodeUrl(this.$route.params.url)
}, },

View File

@ -44,7 +44,6 @@ import { NcActionCheckbox, NcAppNavigationItem } from '@nextcloud/vue'
import { mapActions, mapState } from 'pinia' 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 { getCookie } from '../../utils/cookies.js'
import { useSettings } from '../../store/settings.js' import { useSettings } from '../../store/settings.js'
export default { export default {
@ -65,12 +64,6 @@ export default {
) )
}, },
}, },
mounted() {
try {
const filters = getCookie('repod.filters')
this.filters = JSON.parse(filters)
} catch {}
},
methods: { methods: {
...mapActions(useSettings, ['setFilters']), ...mapActions(useSettings, ['setFilters']),
}, },

View File

@ -4,6 +4,17 @@
:name="feed ? feed.title : url" :name="feed ? feed.title : url"
:to="hash"> :to="hash">
<template #actions> <template #actions>
<NcActionButton
:aria-label="t('repod', 'Favorite')"
:model-value="isFavorite"
:name="t('repod', 'Favorite')"
:title="t('repod', 'Favorite')"
@update:modelValue="switchFavorite($event)">
<template #icon>
<StarPlusIcon v-if="!isFavorite" :size="20" />
<StarRemoveIcon v-if="isFavorite" :size="20" />
</template>
</NcActionButton>
<NcActionButton <NcActionButton
:aria-label="t(`core`, 'Delete')" :aria-label="t(`core`, 'Delete')"
:name="t(`core`, 'Delete')" :name="t(`core`, 'Delete')"
@ -20,6 +31,7 @@
:display-name="feed.author || feed.title" :display-name="feed.author || feed.title"
:is-no-user="true" :is-no-user="true"
:url="feed.imageUrl" /> :url="feed.imageUrl" />
<StarIcon v-if="feed && isFavorite" class="star" :size="20" />
<AlertIcon v-if="failed" /> <AlertIcon v-if="failed" />
</template> </template>
</NcAppNavigationItem> </NcAppNavigationItem>
@ -27,11 +39,14 @@
<script> <script>
import { NcActionButton, NcAppNavigationItem, NcAvatar } from '@nextcloud/vue' import { NcActionButton, NcAppNavigationItem, NcAvatar } from '@nextcloud/vue'
import { mapActions, mapState } from 'pinia'
import AlertIcon from 'vue-material-design-icons/Alert.vue' 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 StarIcon from 'vue-material-design-icons/Star.vue'
import StarPlusIcon from 'vue-material-design-icons/StarPlus.vue'
import StarRemoveIcon from 'vue-material-design-icons/StarRemove.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' import { useSubscriptions } from '../../store/subscriptions.js'
@ -44,6 +59,9 @@ export default {
NcActionButton, NcActionButton,
NcAppNavigationItem, NcAppNavigationItem,
NcAvatar, NcAvatar,
StarIcon,
StarPlusIcon,
StarRemoveIcon,
}, },
props: { props: {
url: { url: {
@ -59,9 +77,13 @@ export default {
} }
}, },
computed: { computed: {
...mapState(useSubscriptions, ['favorites']),
hash() { hash() {
return toUrl(this.url) return toUrl(this.url)
}, },
isFavorite() {
return this.favorites.includes(this.url)
},
}, },
async mounted() { async mounted() {
try { try {
@ -82,7 +104,7 @@ export default {
} }
}, },
methods: { methods: {
...mapActions(useSubscriptions, ['fetch']), ...mapActions(useSubscriptions, ['fetch', 'addFavorite', 'removeFavorite']),
async deleteSubscription() { async deleteSubscription() {
if ( if (
confirm( confirm(
@ -99,11 +121,33 @@ export default {
console.error(e) console.error(e)
showError(t('repod', 'Error while removing the feed')) showError(t('repod', 'Error while removing the feed'))
} finally { } finally {
this.removeFavorite(this.url)
this.loading = false this.loading = false
this.fetch() this.fetch()
} }
} }
}, },
switchFavorite(value) {
if (value) {
if (this.favorites.length >= 10) {
showError(t('repod', 'You can only have 10 favorites'))
return
}
this.addFavorite(this.url)
} else {
this.removeFavorite(this.url)
}
},
}, },
} }
</script> </script>
<style scoped>
.star {
bottom: 2px;
color: yellow;
left: 22px;
position: absolute;
}
</style>

View File

@ -2,7 +2,7 @@
<AppNavigation> <AppNavigation>
<template #list> <template #list>
<NcAppContentList> <NcAppContentList>
<router-link to="/"> <router-link to="/discover">
<NcAppNavigationNew :text="t('repod', 'Add a podcast')"> <NcAppNavigationNew :text="t('repod', 'Add a podcast')">
<template #icon> <template #icon>
<PlusIcon :size="20" /> <PlusIcon :size="20" />
@ -11,10 +11,7 @@
</router-link> </router-link>
<Loading v-if="loading" /> <Loading v-if="loading" />
<NcAppNavigationList v-if="!loading"> <NcAppNavigationList v-if="!loading">
<Item <Item v-for="url of subs" :key="url" :url="url" />
v-for="subscriptionUrl of subscriptions"
:key="subscriptionUrl"
:url="subscriptionUrl" />
</NcAppNavigationList> </NcAppNavigationList>
</NcAppContentList> </NcAppContentList>
</template> </template>
@ -57,7 +54,7 @@ export default {
} }
}, },
computed: { computed: {
...mapState(useSubscriptions, ['subscriptions']), ...mapState(useSubscriptions, ['subs']),
}, },
async mounted() { async mounted() {
try { try {

View File

@ -1,6 +1,7 @@
import { createRouter, createWebHashHistory } from 'vue-router' import { createRouter, createWebHashHistory } from 'vue-router'
import Discover from './views/Discover.vue' import Discover from './views/Discover.vue'
import Feed from './views/Feed.vue' import Feed from './views/Feed.vue'
import Home from './views/Home.vue'
import { generateUrl } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
const router = createRouter({ const router = createRouter({
@ -8,6 +9,10 @@ const router = createRouter({
routes: [ routes: [
{ {
path: '/', path: '/',
component: Home,
},
{
path: '/discover',
component: Discover, component: Discover,
}, },
{ {

View File

@ -1,14 +1,27 @@
import { getCookie, setCookie } from '../utils/cookies.js'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { setCookie } from '../utils/cookies.js'
export const useSettings = defineStore('settings', { export const useSettings = defineStore('settings', {
state: () => ({ state: () => {
filters: { try {
listened: true, const filters = JSON.parse(getCookie('repod.filters'))
listening: true, return {
unlistened: true, filters: {
}, listened: filters.listened,
}), listening: filters.listening,
unlistened: filters.unlistened,
},
}
} catch {
return {
filters: {
listened: true,
listening: true,
unlistened: true,
},
}
}
},
actions: { actions: {
setFilters(filters) { setFilters(filters) {
this.filters = { ...this.filters, ...filters } this.filters = { ...this.filters, ...filters }

View File

@ -1,10 +1,12 @@
import { getCookie, setCookie } from '../utils/cookies.js'
import axios from '@nextcloud/axios' import axios from '@nextcloud/axios'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { generateUrl } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
export const useSubscriptions = defineStore('subscriptions', { export const useSubscriptions = defineStore('subscriptions', {
state: () => ({ state: () => ({
subscriptions: [], subs: [],
favorites: [],
}), }),
actions: { actions: {
async fetch() { async fetch() {
@ -14,7 +16,19 @@ export const useSubscriptions = defineStore('subscriptions', {
const subs = [...metrics.data.subscriptions].sort( const subs = [...metrics.data.subscriptions].sort(
(a, b) => b.listenedSeconds - a.listenedSeconds, (a, b) => b.listenedSeconds - a.listenedSeconds,
) )
this.subscriptions = subs.map((sub) => sub.url) this.subs = subs.map((sub) => sub.url)
try {
this.favorites = JSON.parse(getCookie('repod.favorites')) || []
} catch {}
},
addFavorite(url) {
this.favorites.push(url)
setCookie('repod.favorites', JSON.stringify(this.favorites), 365)
},
removeFavorite(url) {
this.favorites = this.favorites.filter((favorite) => favorite !== url)
setCookie('repod.favorites', JSON.stringify(this.favorites), 365)
}, },
}, },
}) })

7
src/views/Home.vue Normal file
View File

@ -0,0 +1,7 @@
<template><div /></template>
<script>
export default {
name: 'Home',
}
</script>