Skip to content
Merged
Prev Previous commit
Next Next commit
Use store to manage user config
Signed-off-by: Louis Chemineau <[email protected]>
  • Loading branch information
artonge committed Feb 15, 2024
commit bc85b66765e86f76bf5096ceb9243e17b403bd9d
6 changes: 5 additions & 1 deletion src/components/Settings/PhotosFolder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,18 @@ export default defineComponent({
type: Boolean,
default: false,
},
rootFolderLabel: {
type: String,
required: true,
},
},

emits: ['remove-folder'],

computed: {
folderName() {
if (this.path === '/') {
return t('photos', 'All folders')
return this.rootFolderLabel
} else {
return this.path.split('/').pop()
}
Expand Down
20 changes: 11 additions & 9 deletions src/components/Settings/PhotosSourceLocationsSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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({
Expand All @@ -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) {
Expand All @@ -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,
Expand Down
15 changes: 8 additions & 7 deletions src/components/Settings/PhotosUploadLocationSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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({
Expand All @@ -50,9 +49,12 @@ export default defineComponent({
PhotosFolder,
},

mixins: [
UserConfig,
],
computed: {
/** @return {string} */
photosLocation() {
return this.$store.state.userConfig.photosLocation
},
},

methods: {
debounceSelectPhotosFolder: debounce(function() {
Expand All @@ -78,8 +80,7 @@ export default defineComponent({
},

updatePhotosFolder(path) {
this.photosLocation = path
this.updateSetting('photosLocation')
this.$store.dispatch('updateUserConfig', { key: 'photosLocation', value: path })
},

t,
Expand Down
2 changes: 2 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,5 @@ export default new Vue({
store,
render: h => h(Photos),
})

store.dispatch('initUserConfig')
2 changes: 2 additions & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -45,6 +46,7 @@ export default new Store({
systemtags,
collections,
places,
userConfig,
},

strict: process.env.NODE_ENV !== 'production',
Expand Down
97 changes: 97 additions & 0 deletions src/store/userConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* eslint-disable jsdoc/require-jsdoc */
/**
* @copyright Copyright (c) 2024 Louis Chmn <[email protected]>
*
* @author Louis Chmn <[email protected]>
*
* @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