From e6394bdb18ec4a4671018ac0a2cdbb43ed3aea47 Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Mon, 8 Apr 2024 17:32:03 +0200 Subject: [PATCH] feat: Allow multiple source folders Signed-off-by: Louis Chemineau --- lib/Service/UserConfigService.php | 3 +- .../PhotosSourceLocationsSettings.vue | 37 +++++++++---------- src/components/Settings/SettingsDialog.vue | 2 +- src/mixins/FetchFilesMixin.js | 3 +- src/services/PhotoSearch.js | 23 +++++------- src/store/userConfig.js | 4 +- src/views/Timeline.vue | 2 +- 7 files changed, 35 insertions(+), 39 deletions(-) diff --git a/lib/Service/UserConfigService.php b/lib/Service/UserConfigService.php index d2362fe94..570942ac9 100644 --- a/lib/Service/UserConfigService.php +++ b/lib/Service/UserConfigService.php @@ -34,7 +34,8 @@ class UserConfigService { public const DEFAULT_CONFIGS = [ 'croppedLayout' => 'false', 'photosLocation' => '/Photos', - 'photosSourceFolder' => '/Photos', + // TODO: add migration to retrieve value in photosSourceFolders + 'photosSourceFolders' => '["/Photos"]', ]; private IConfig $config; diff --git a/src/components/Settings/PhotosSourceLocationsSettings.vue b/src/components/Settings/PhotosSourceLocationsSettings.vue index 338087ebe..fe63c72d7 100644 --- a/src/components/Settings/PhotosSourceLocationsSettings.vue +++ b/src/components/Settings/PhotosSourceLocationsSettings.vue @@ -23,24 +23,22 @@ + {{ t('photos', 'Add folder') }} @@ -72,9 +70,9 @@ export default defineComponent({ }, computed: { - /** @return {string} */ - photosSourceFolder() { - return this.$store.state.userConfig.photosSourceFolder + /** @return {string[]} */ + photosSourceFolders() { + return this.$store.state.userConfig.photosSourceFolders }, }, @@ -97,17 +95,16 @@ export default defineComponent({ async addSourceFolder() { const pickedFolder = await this.openFilePicker(t('photos', 'Select a source folder for your media')) - // TODO: uncomment when SEARCH on multiple folders is implemented. - // if (this.photosSourceFolder.includes(pickedFolder)) { - // return - // } - this.$store.dispatch('updateUserConfig', { key: 'photosSourceFolder', value: pickedFolder }) + if (this.photosSourceFolders.includes(pickedFolder)) { + return + } + this.$store.dispatch('updateUserConfig', { key: 'photosSourceFolders', value: [...this.photosSourceFolders, pickedFolder] }) }, removeSourceFolder(index) { - const folders = [...this.photosSourceFolder] + const folders = [...this.photosSourceFolders] folders.splice(index, 1) - this.$store.dispatch('updateUserConfig', { key: 'photosSourceFolder', value: folders }) + this.$store.dispatch('updateUserConfig', { key: 'photosSourceFolders', value: folders }) }, t, diff --git a/src/components/Settings/SettingsDialog.vue b/src/components/Settings/SettingsDialog.vue index f05db8281..73a9beeaa 100644 --- a/src/components/Settings/SettingsDialog.vue +++ b/src/components/Settings/SettingsDialog.vue @@ -7,7 +7,7 @@ - + diff --git a/src/mixins/FetchFilesMixin.js b/src/mixins/FetchFilesMixin.js index b58031973..e0130d114 100644 --- a/src/mixins/FetchFilesMixin.js +++ b/src/mixins/FetchFilesMixin.js @@ -102,7 +102,8 @@ export default { } catch (error) { if (error.response?.status === 404) { this.errorFetchingFiles = 404 - const source = joinPaths(davRootPath, store.state.userConfig.photosSourceFolder ?? '/Photos') + '/' + // TODO improve error handling + const source = joinPaths(davRootPath, store.state.userConfig.photosSourceFolders ?? ['/Photos']) + '/' logger.debug('Photo source does not exist, creating it.') try { await davGetClient().createDirectory(source) diff --git a/src/services/PhotoSearch.js b/src/services/PhotoSearch.js index 435297da1..091734340 100644 --- a/src/services/PhotoSearch.js +++ b/src/services/PhotoSearch.js @@ -27,6 +27,7 @@ import client from './DavClient.js' import { props } from './DavRequest.js' import moment from '@nextcloud/moment' import store from '../store/index.js' +import { davRootPath } from '@nextcloud/files' /** * List files from a folder and filter out unwanted mimes @@ -95,15 +96,14 @@ export default async function(options = {}) { }).join('\n')}` : '' - // TODO: uncomment when SEARCH on multiple folders is implemented. - // const sourceFolders = store.state.userConfig.photosSourceFolder - // .map(folder => ` - // - // ${davRootPath}/${folder} - // infinity - // - // `) - // .join('\n') + const sourceFolders = store.state.userConfig.photosSourceFolders + .map(folder => ` + + ${davRootPath}/${folder} + infinity + ` + ) + .join('\n') options = Object.assign({ method: 'SEARCH', @@ -123,10 +123,7 @@ export default async function(options = {}) { - - ${prefixPath}/${store.state.userConfig.photosSourceFolder ?? '/Photos'} - infinity - + ${sourceFolders} diff --git a/src/store/userConfig.js b/src/store/userConfig.js index ae201bdac..7fbb6f9a1 100644 --- a/src/store/userConfig.js +++ b/src/store/userConfig.js @@ -58,7 +58,7 @@ export async function getFolder(path) { /** * @typedef {object} UserConfigState * @property {boolean} croppedLayout - * @property {string} photosSourceFolder + * @property {string[]} photosSourceFolders * @property {string} photosLocation * @property {import('@nextcloud/files').Folder} [photosLocationFolder] */ @@ -68,7 +68,7 @@ const module = { state() { return { croppedLayout: loadState('photos', 'croppedLayout', 'false') === 'true', - photosSourceFolder: loadState('photos', 'photosSourceFolder', ''), + photosSourceFolders: loadState('photos', 'photosSourceFolders', ''), photosLocation: loadState('photos', 'photosLocation', ''), photosLocationFolder: undefined, } diff --git a/src/views/Timeline.vue b/src/views/Timeline.vue index 5cf0e6a05..88d1f5fd1 100644 --- a/src/views/Timeline.vue +++ b/src/views/Timeline.vue @@ -314,7 +314,7 @@ export default { }, handleUserConfigChange({ key }) { - if (key === 'photosSourceFolder') { + if (key === 'photosSourceFolders') { this.resetFetchFilesState() } },