Use store to manage user config

Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
Louis Chemineau 2024-02-06 19:29:26 +01:00
parent e038644eb1
commit bc85b66765
No known key found for this signature in database
6 changed files with 125 additions and 17 deletions

View File

@ -48,6 +48,10 @@ export default defineComponent({
type: Boolean,
default: false,
},
rootFolderLabel: {
type: String,
required: true,
},
},
emits: ['remove-folder'],
@ -55,7 +59,7 @@ export default defineComponent({
computed: {
folderName() {
if (this.path === '/') {
return t('photos', 'All folders')
return this.rootFolderLabel
} else {
return this.path.split('/').pop()
}

View File

@ -25,7 +25,7 @@
<ul>
<li v-for="(source, index) in photosSourceFolders"
:key="index">
<PhotosFolder :path="source" :can-delete="photosSourceFolders.length !== 1" @remove-folder="removeSourceFolder(index)" />
<PhotosFolder :path="source" :can-delete="photosSourceFolders.length !== 1" @remove-folder="removeSourceFolder(index)" :root-folder-label="t('photos', 'All folders')"/>
</li>
</ul>
@ -49,7 +49,6 @@ import { NcButton } from '@nextcloud/vue'
import { getFilePickerBuilder } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import UserConfig from '../../mixins/UserConfig.js'
import PhotosFolder from './PhotosFolder.vue'
export default defineComponent({
@ -61,9 +60,12 @@ export default defineComponent({
PhotosFolder,
},
mixins: [
UserConfig,
],
computed: {
/** @return {string[]} */
photosSourceFolders() {
return this.$store.state.userConfig.photosSourceFolders
},
},
methods: {
debounceAddSourceFolder: debounce(function(...args) {
@ -87,13 +89,13 @@ export default defineComponent({
if (this.photosSourceFolders.includes(pickedFolder)) {
return
}
this.photosSourceFolders.push(pickedFolder)
this.updateSetting('photosSourceFolders')
this.$store.dispatch('updateUserConfig', { key: 'photosSourceFolders', value: [...this.photosSourceFolders, pickedFolder] })
},
removeSourceFolder(index) {
this.photosSourceFolders.splice(index, 1)
this.updateSetting('photosSourceFolders')
const folders = [...this.photosSourceFolders]
folders.splice(index, 1)
this.$store.dispatch('updateUserConfig', { key: 'photosSourceFolders', value: folders })
},
t,

View File

@ -22,7 +22,7 @@
<template>
<div class="photos-location">
<PhotosFolder :path="photosLocation" />
<PhotosFolder :path="photosLocation" :root-folder-label="t('photos', 'Root folder')" />
<NcButton :aria-label="t('photos', 'Choose default Photos upload and Albums location')"
@click="debounceSelectPhotosFolder">
@ -39,7 +39,6 @@ import { NcButton } from '@nextcloud/vue'
import { getFilePickerBuilder } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import UserConfig from '../../mixins/UserConfig.js'
import PhotosFolder from './PhotosFolder.vue'
export default defineComponent({
@ -50,9 +49,12 @@ export default defineComponent({
PhotosFolder,
},
mixins: [
UserConfig,
],
computed: {
/** @return {string} */
photosLocation() {
return this.$store.state.userConfig.photosLocation
},
},
methods: {
debounceSelectPhotosFolder: debounce(function() {
@ -78,8 +80,7 @@ export default defineComponent({
},
updatePhotosFolder(path) {
this.photosLocation = path
this.updateSetting('photosLocation')
this.$store.dispatch('updateUserConfig', { key: 'photosLocation', value: path })
},
t,

View File

@ -65,3 +65,5 @@ export default new Vue({
store,
render: h => h(Photos),
})
store.dispatch('initUserConfig')

View File

@ -32,6 +32,7 @@ import places from './places.js'
import faces from './faces.js'
import folders from './folders.js'
import systemtags from './systemtags.js'
import userConfig from './userConfig.js'
Vue.use(Vuex)
export default new Store({
@ -45,6 +46,7 @@ export default new Store({
systemtags,
collections,
places,
userConfig,
},
strict: process.env.NODE_ENV !== 'production',

97
src/store/userConfig.js Normal file
View File

@ -0,0 +1,97 @@
/* eslint-disable jsdoc/require-jsdoc */
/**
* @copyright Copyright (c) 2024 Louis Chmn <louis@chmn.me>
*
* @author Louis Chmn <louis@chmn.me>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { Folder, davGetClient, davGetDefaultPropfind, davResultToNode, davRootPath } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state'
import { joinPaths } from '@nextcloud/paths'
import { showError } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import axios from '@nextcloud/axios'
import logger from '../services/logger.js'
export const configChangedEvent = 'photos:user-config-changed'
export async function getFolder(path) {
const davClient = davGetClient()
const location = joinPaths(davRootPath, path) + '/'
try {
const stat = await davClient.stat(location, { details: true, data: davGetDefaultPropfind() })
return davResultToNode(stat.data)
} catch (error) {
if (error.response?.status === 404) {
logger.debug('Photo location does not exist, creating it.')
await davClient.createDirectory(location)
const stat = await davClient.stat(location, { details: true, data: davGetDefaultPropfind() })
return davResultToNode(stat.data)
} else {
logger.fatal(error)
showError(t('photos', 'Could not load photos folder'))
}
}
throw new Error("Couldn't fetch photos upload folder")
}
/**
* @typedef {object} UserConfigState
* @property {boolean} croppedLayout
* @property {string} photosSourceFolder
* @property {string} photosLocation
* @property {Folder} [photosLocationFolder]
*/
/** @type {import('vuex').Module<UserConfigState, object>} */
const module = {
state() {
return {
croppedLayout: loadState('photos', 'croppedLayout', 'false') === 'true',
photosSourceFolder: loadState('photos', 'photosSourceFolder', ''),
photosLocation: loadState('photos', 'photosLocation', ''),
photosLocationFolder: undefined,
}
},
mutations: {
updateUserConfig(state, { key, value }) {
state[key] = value
},
},
actions: {
async initUserConfig({ commit }) {
const photosLocationFolder = await getFolder(loadState('photos', 'photosLocation', ''))
commit('updateUserConfig', { key: 'photosLocationFolder', value: photosLocationFolder })
},
async updateUserConfig({ commit }, { key, value }) {
commit('updateUserConfig', { key, value })
// Long time save setting
await axios.put(generateUrl('apps/photos/api/v1/config/' + key), {
// Stringify non string values.
value: (typeof value === 'string') ? value : JSON.stringify(value),
})
},
},
}
export default module