Compare commits

..

3 Commits

Author SHA1 Message Date
eb1196c841 feat: 🚧 wip on showing favorites
Some checks failed
repod / xml (push) Successful in 31s
repod / php (push) Failing after 1m8s
repod / nodejs (push) Failing after 1m20s
repod / release (push) Has been skipped
2024-08-22 17:35:05 +02:00
dd275a1f03 feat: 🧑‍💻 add vue devtools in dev 2024-08-22 17:34:27 +02:00
f205d3243f refactor: ♻️ rewrite data to arrow function 2024-08-22 13:30:52 +02:00
18 changed files with 1045 additions and 153 deletions

View File

@ -8,10 +8,15 @@ use OCA\RePod\AppInfo\Application;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\Util; use OCP\Util;
class PageController extends Controller class PageController extends Controller
{ {
public function __construct(
private IConfig $config
) {}
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired * @NoCSRFRequired
@ -23,6 +28,13 @@ class PageController extends Controller
$csp->addAllowedImageDomain('*'); $csp->addAllowedImageDomain('*');
$csp->addAllowedMediaDomain('*'); $csp->addAllowedMediaDomain('*');
if ($this->config->getSystemValueBool('debug', false)) {
/** @psalm-suppress DeprecatedInterface */
$csp->allowEvalScript();
$csp->addAllowedConnectDomain('*');
$csp->addAllowedScriptDomain('*');
}
$response = new TemplateResponse(Application::APP_ID, 'main'); $response = new TemplateResponse(Application::APP_ID, 'main');
$response->setContentSecurityPolicy($csp); $response->setContentSecurityPolicy($csp);

950
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
"@nextcloud/stylelint-config": "^3.0.1", "@nextcloud/stylelint-config": "^3.0.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-pinia": "^0.2.0", "eslint-plugin-pinia": "^0.2.0",
"eslint-plugin-prettier": "^5.2.1" "eslint-plugin-prettier": "^5.2.1",
"vite-plugin-vue-devtools": "^7.3.8"
} }
} }

View File

@ -62,12 +62,10 @@ export default {
required: true, required: true,
}, },
}, },
data() { data: () => ({
return { feeds: [],
feeds: [], loading: false,
loading: false, }),
}
},
computed: { computed: {
...mapState(useSubscriptions, ['subs']), ...mapState(useSubscriptions, ['subs']),
}, },

View File

@ -30,12 +30,10 @@ export default {
required: true, required: true,
}, },
}, },
data() { data: () => ({
return { loading: true,
loading: true, tops: [],
tops: [], }),
}
},
computed: { computed: {
title() { title() {
switch (this.type) { switch (this.type) {

View File

@ -158,14 +158,12 @@ export default {
PlaylistRemoveIcon, PlaylistRemoveIcon,
StopIcon, StopIcon,
}, },
data() { data: () => ({
return { episodes: [],
episodes: [], loading: true,
loading: true, loadingAction: false,
loadingAction: false, modalEpisode: null,
modalEpisode: null, }),
}
},
computed: { computed: {
...mapState(usePlayer, ['episode']), ...mapState(usePlayer, ['episode']),
...mapState(useSettings, ['filters']), ...mapState(useSettings, ['filters']),

View File

View File

@ -0,0 +1,33 @@
<template>
<div>
<Loading v-if="!currentFavoriteData" class="loading" />
<NcAvatar v-if="currentFavoriteData" />
</div>
</template>
<script>
import { mapState } from 'pinia';
import Loading from '../Atoms/Loading.vue'
import { NcAvatar } from '@nextcloud/vue'
import { useSubscriptions } from '../../store/subscriptions';
export default {
name: 'Item',
components: {
Loading,
NcAvatar,
},
props: {
url: {
type: String,
required: true,
},
},
computed: {
...mapState(useSubscriptions, ['favs']),
currentFavoriteData() {
return this.favs.find((fav) => fav.url === this.url)?.data
},
}
}
</script>

View File

@ -32,11 +32,9 @@ export default {
Modal, Modal,
NcModal, NcModal,
}, },
data() { data: () => ({
return { modal: false,
modal: false, }),
}
},
computed: { computed: {
...mapState(usePlayer, ['episode', 'podcastUrl']), ...mapState(usePlayer, ['episode', 'podcastUrl']),
hash() { hash() {

View File

@ -46,11 +46,9 @@ export default {
VolumeMediumIcon, VolumeMediumIcon,
VolumeMuteIcon, VolumeMuteIcon,
}, },
data() { data: () => ({
return { volumeMuted: 0,
volumeMuted: 0, }),
}
},
computed: { computed: {
...mapState(usePlayer, ['volume']), ...mapState(usePlayer, ['volume']),
}, },

View File

@ -44,12 +44,10 @@ export default {
NcAppNavigationItem, NcAppNavigationItem,
NcModal, NcModal,
}, },
data() { data: () => ({
return { loading: false,
loading: false, modal: false,
modal: false, }),
}
},
methods: { methods: {
generateUrl, generateUrl,
async importOpml(event) { async importOpml(event) {

View File

@ -69,20 +69,18 @@ export default {
required: true, required: true,
}, },
}, },
data() { data: () => ({
return { failed: false,
failed: false, loading: true,
loading: true, feed: null,
feed: null, }),
}
},
computed: { computed: {
...mapState(useSubscriptions, ['favorites']), ...mapState(useSubscriptions, ['favs']),
hash() { hash() {
return toUrl(this.url) return toUrl(this.url)
}, },
isFavorite() { isFavorite() {
return this.favorites.includes(this.url) return this.favs.map((fav) => fav.url).includes(this.url)
}, },
}, },
async mounted() { async mounted() {
@ -96,6 +94,7 @@ export default {
), ),
) )
this.feed = podcastData.data.data this.feed = podcastData.data.data
this.editFavoriteData(this.url, podcastData.data.data)
} catch (e) { } catch (e) {
this.failed = true this.failed = true
console.error(e) console.error(e)
@ -104,7 +103,7 @@ export default {
} }
}, },
methods: { methods: {
...mapActions(useSubscriptions, ['fetch', 'addFavorite', 'removeFavorite']), ...mapActions(useSubscriptions, ['fetch', 'addFavorite', 'editFavoriteData', 'removeFavorite']),
async deleteSubscription() { async deleteSubscription() {
if ( if (
confirm( confirm(
@ -129,7 +128,7 @@ export default {
}, },
switchFavorite(value) { switchFavorite(value) {
if (value) { if (value) {
if (this.favorites.length >= 10) { if (this.favs.length >= 10) {
showError(t('repod', 'You can only have 10 favorites')) showError(t('repod', 'You can only have 10 favorites'))
return return
} }

View File

@ -11,7 +11,18 @@
</router-link> </router-link>
<Loading v-if="loading" /> <Loading v-if="loading" />
<NcAppNavigationList v-if="!loading"> <NcAppNavigationList v-if="!loading">
<Item v-for="url of subs" :key="url" :url="url" /> <Item
v-for="url of favs
.sort((fav) => fav.lastPub)
.map((fav) => fav.url)"
:key="url"
:url="url" />
<Item
v-for="url of subs.filter(
(sub) => !favs.map((fav) => fav.url).includes(sub),
)"
:key="url"
:url="url" />
</NcAppNavigationList> </NcAppNavigationList>
</NcAppContentList> </NcAppContentList>
</template> </template>
@ -48,13 +59,11 @@ export default {
PlusIcon, PlusIcon,
Settings, Settings,
}, },
data() { data: () => ({
return { loading: true,
loading: true, }),
}
},
computed: { computed: {
...mapState(useSubscriptions, ['subs']), ...mapState(useSubscriptions, ['subs', 'favs']),
}, },
async mounted() { async mounted() {
try { try {

View File

@ -6,7 +6,7 @@ import { generateUrl } from '@nextcloud/router'
export const useSubscriptions = defineStore('subscriptions', { export const useSubscriptions = defineStore('subscriptions', {
state: () => ({ state: () => ({
subs: [], subs: [],
favorites: [], favs: [],
}), }),
actions: { actions: {
async fetch() { async fetch() {
@ -19,16 +19,30 @@ export const useSubscriptions = defineStore('subscriptions', {
this.subs = subs.map((sub) => sub.url) this.subs = subs.map((sub) => sub.url)
try { try {
this.favorites = JSON.parse(getCookie('repod.favorites')) || [] const favs = JSON.parse(getCookie('repod.favorites')) || []
this.favs = favs.map((url) => ({ url }))
} catch {} } catch {}
}, },
addFavorite(url) { addFavorite(url) {
this.favorites.push(url) this.favs.push({ url })
setCookie('repod.favorites', JSON.stringify(this.favorites), 365) setCookie(
'repod.favorites',
JSON.stringify(this.favs.map((fav) => fav.url)),
365,
)
},
editFavoriteData(url, data) {
this.favs = this.favs.map((fav) =>
fav.url === url ? { ...fav, ...data } : fav,
)
}, },
removeFavorite(url) { removeFavorite(url) {
this.favorites = this.favorites.filter((favorite) => favorite !== url) this.favs = this.favs.filter((fav) => fav.url !== url)
setCookie('repod.favorites', JSON.stringify(this.favorites), 365) setCookie(
'repod.favorites',
JSON.stringify(this.favs.map((fav) => fav.url)),
365,
)
}, },
}, },
}) })

View File

@ -30,11 +30,9 @@ export default {
Search, Search,
Toplist, Toplist,
}, },
data() { data: () => ({
return { search: '',
search: '', }),
}
},
} }
</script> </script>

View File

@ -41,13 +41,11 @@ export default {
Loading, Loading,
NcEmptyContent, NcEmptyContent,
}, },
data() { data: () => ({
return { failed: false,
failed: false, loading: true,
loading: true, feed: null,
feed: null, }),
}
},
computed: { computed: {
url() { url() {
return decodeUrl(this.$route.params.url) return decodeUrl(this.$route.params.url)

View File

@ -1,23 +1,50 @@
<template> <template>
<AppContent class="content"> <AppContent>
<Loading /> <NcEmptyContent
v-if="!favs.length"
class="empty"
:description="
t('repod', 'Pin some subscriptions to see their latest updates')
"
:name="t('repod', 'No favorites')">
<template #icon>
<StarOffIcon :size="20" />
</template>
</NcEmptyContent>
<ul v-if="favs.length">
<li
v-for="url in favs.sort((fav) => fav.lastPub).map((fav) => fav.url)"
:key="url">
<Item :url="url" />
</li>
</ul>
</AppContent> </AppContent>
</template> </template>
<script> <script>
import AppContent from '../components/Atoms/AppContent.vue' import AppContent from '../components/Atoms/AppContent.vue'
import Loading from '../components/Atoms/Loading.vue' import Item from '../components/Home/Item.vue'
import { NcEmptyContent } from '@nextcloud/vue'
import StarOffIcon from 'vue-material-design-icons/StarOff.vue'
import { mapState } from 'pinia'
import { useSubscriptions } from '../store/subscriptions.js'
export default { export default {
name: 'Home', name: 'Home',
components: { components: {
AppContent, AppContent,
Loading, Item,
NcEmptyContent,
StarOffIcon,
}, },
data() { computed: {
return { ...mapState(useSubscriptions, ['favs']),
loading: true,
}
}, },
} }
</script> </script>
<style scoped>
.empty {
height: 100%;
}
</style>

View File

@ -1,5 +1,6 @@
import { createAppConfig } from '@nextcloud/vite-config' import { createAppConfig } from '@nextcloud/vite-config'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vueDevTools from 'vite-plugin-vue-devtools'
const config = defineConfig(({ mode }) => ({ const config = defineConfig(({ mode }) => ({
build: { build: {
@ -10,8 +11,12 @@ const config = defineConfig(({ mode }) => ({
manualChunks: false, manualChunks: false,
}, },
}, },
sourcemap: mode === 'development', sourcemap: mode !== 'production',
}, },
define: {
__VUE_PROD_DEVTOOLS__: mode !== 'production'
},
plugins: [vueDevTools()],
})) }))
export default createAppConfig( export default createAppConfig(