From 0ea420cba3cab8d693df5b211a9fffdce897fd0e Mon Sep 17 00:00:00 2001 From: gnacho Date: Mon, 9 Nov 2026 00:18:42 +0100 Subject: [PATCH] feat(ui): default the local folder to the documents for OpenCloud Nextcloud accounts keep $HOME/NextCloud. OpenCloud ones start from the documents folder and the chooser title follows the provider. --- po/es.po | 3 +++ src/storage/config.rs | 34 ++++++++++++++++++++++++++++++++++ src/ui/settings.rs | 19 ++++++++++++++----- src/ui/setup.rs | 21 ++++++++++++++------- src/util/translations/es.rs | 1 + 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/po/es.po b/po/es.po index a639fb5..633d259 100644 --- a/po/es.po +++ b/po/es.po @@ -1205,6 +1205,9 @@ msgstr "Elige una carpeta local absoluta." msgid "Choose NextCloud Folder" msgstr "Elegir carpeta de NextCloud" +msgid "Choose OpenCloud Folder" +msgstr "Elegir carpeta de OpenCloud" + #: src/nextsync/ui/settings.py:419 msgid "Synchronization" msgstr "Sincronización" diff --git a/src/storage/config.rs b/src/storage/config.rs index c189d52..359882e 100644 --- a/src/storage/config.rs +++ b/src/storage/config.rs @@ -563,6 +563,30 @@ pub fn default_sync_root() -> PathBuf { home_dir().join("NextCloud") } +/// Default local sync root for an account of `provider` (issue #331). +/// +/// Nextcloud keeps `$HOME/NextCloud`, the name of its own desktop client. +/// OpenCloud accounts start from the user's documents folder instead, whose +/// name follows the localized XDG layout (`Documentos` on a Spanish system, +/// `Documents` otherwise). +pub fn default_sync_root_for(provider: Provider) -> PathBuf { + match provider { + Provider::Nextcloud => default_sync_root(), + Provider::OpenCloud => home_dir().join(documents_dir_name()), + } +} + +/// Name of the documents folder under `$HOME`, preferring the one that +/// exists so the default points at a real directory. +fn documents_dir_name() -> &'static str { + let home = home_dir(); + if home.join("Documentos").is_dir() { + "Documentos" + } else { + "Documents" + } +} + /// Resolve `~`-prefixed paths against `$HOME` (no `~user` support). pub fn expanduser(path: &str) -> PathBuf { if path == "~" { @@ -1376,6 +1400,16 @@ fn default_runtime_value() -> Value { #[cfg(test)] mod tests { + #[test] + fn default_sync_root_follows_the_provider() { + assert!(super::default_sync_root_for(super::Provider::Nextcloud).ends_with("NextCloud")); + let opencloud = super::default_sync_root_for(super::Provider::OpenCloud); + assert!( + opencloud.ends_with("Documentos") || opencloud.ends_with("Documents"), + "unexpected OpenCloud default: {opencloud:?}" + ); + } + use super::*; use std::os::unix::fs::PermissionsExt; use tempfile::tempdir; diff --git a/src/ui/settings.rs b/src/ui/settings.rs index 93facc6..9efa38f 100644 --- a/src/ui/settings.rs +++ b/src/ui/settings.rs @@ -53,7 +53,7 @@ use crate::nextcloud::api::{ use crate::nextcloud::credentials::CredentialsStore; use crate::nextcloud::provider::Provider; use crate::storage::config::{ - default_sync_root, expanduser, remote_path_for, validate_pattern, AccountConfig, Config, + default_sync_root_for, expanduser, remote_path_for, validate_pattern, AccountConfig, Config, ConfigError, ConfigStore, FolderConfig, GeneralConfig, LoggingConfig, DEFAULT_PATTERNS, }; use crate::util::i18n::t; @@ -1518,8 +1518,14 @@ pub fn present_add_folder_dialog( ) { let account = store.account(&account_id).ok().flatten(); let (previous_local, previous_remote) = previous.unwrap_or_default(); + let provider = account + .as_ref() + .map(|account| account.provider) + .unwrap_or_default(); let local_default = if previous_local.is_empty() { - default_sync_root().to_string_lossy().into_owned() + default_sync_root_for(provider) + .to_string_lossy() + .into_owned() } else { previous_local }; @@ -1565,7 +1571,7 @@ pub fn present_add_folder_dialog( .build(); let entry_for_picker = local_entry.clone(); choose.connect_clicked(move |_| { - choose_local_folder(entry_for_picker.clone()); + choose_local_folder(entry_for_picker.clone(), provider); }); local_entry.add_suffix(&choose); entry_box.append(&local_entry); @@ -1861,9 +1867,12 @@ fn size_threshold_bytes(store: &ConfigStore) -> Option { } /// Present a folder chooser and write the selection into the entry row. -fn choose_local_folder(entry: libadwaita::EntryRow) { +fn choose_local_folder(entry: libadwaita::EntryRow, provider: Provider) { let dialog = gtk4::FileDialog::builder() - .title(t("Choose NextCloud Folder")) + .title(match provider { + Provider::OpenCloud => t("Choose OpenCloud Folder"), + Provider::Nextcloud => t("Choose NextCloud Folder"), + }) .modal(true) .build(); dialog.select_folder( diff --git a/src/ui/setup.rs b/src/ui/setup.rs index 932a5f5..4d52c8e 100644 --- a/src/ui/setup.rs +++ b/src/ui/setup.rs @@ -67,7 +67,7 @@ use crate::nextcloud::login_flow::{ }; use crate::nextcloud::provider::Provider; use crate::storage::config::{ - account_id, default_sync_root, expanduser, normalize_remote_path, normalize_server_url, + account_id, default_sync_root_for, expanduser, normalize_remote_path, normalize_server_url, AccountConfig, Config, ConfigError, ConfigStore, FolderConfig, }; use crate::util::i18n::t; @@ -656,7 +656,8 @@ fn build_folders_page(ctx: &SetupContext) { /// Re-label the authentication page widgets for the selected provider. fn configure_authentication(ctx: &SetupContext) { - let opencloud = ctx.state.borrow().provider == Provider::OpenCloud; + let provider = ctx.state.borrow().provider; + let opencloud = provider == Provider::OpenCloud; ctx.widgets.server_title.set_text(if opencloud { t("Connect to OpenCloud") } else { @@ -1020,7 +1021,8 @@ fn present_add_folder_dialog( previous: Option<(String, String)>, error: Option, ) { - let opencloud = ctx.state.borrow().provider == Provider::OpenCloud; + let provider = ctx.state.borrow().provider; + let opencloud = provider == Provider::OpenCloud; let spaces = ctx.state.borrow().spaces.clone(); let discovered_space = ctx.state.borrow().space_id.clone(); if opencloud && spaces.is_empty() { @@ -1034,7 +1036,9 @@ fn present_add_folder_dialog( } let (previous_local, previous_remote) = previous.unwrap_or_default(); let local_default = if previous_local.is_empty() { - default_sync_root().to_string_lossy().into_owned() + default_sync_root_for(ctx.state.borrow().provider) + .to_string_lossy() + .into_owned() } else { previous_local }; @@ -1076,7 +1080,7 @@ fn present_add_folder_dialog( .build(); let entry_for_picker = local_entry.clone(); choose.connect_clicked(move |_| { - choose_local_folder(entry_for_picker.clone()); + choose_local_folder(entry_for_picker.clone(), provider); }); local_entry.add_suffix(&choose); entry_box.append(&local_entry); @@ -1871,9 +1875,12 @@ fn populate_wizard_remote_picker( } /// Present a folder chooser and write the selection into the entry row. -fn choose_local_folder(entry: libadwaita::EntryRow) { +fn choose_local_folder(entry: libadwaita::EntryRow, provider: Provider) { let dialog = gtk4::FileDialog::builder() - .title(t("Choose NextCloud Folder")) + .title(match provider { + Provider::OpenCloud => t("Choose OpenCloud Folder"), + Provider::Nextcloud => t("Choose NextCloud Folder"), + }) .modal(true) .build(); dialog.select_folder( diff --git a/src/util/translations/es.rs b/src/util/translations/es.rs index af13608..b113faa 100644 --- a/src/util/translations/es.rs +++ b/src/util/translations/es.rs @@ -73,6 +73,7 @@ pub static CATALOG: &[(&str, &str)] = &[ ("Checking credentials…", "Comprobando credenciales…"), ("Checking for Updates", "Buscando actualizaciones"), ("Choose NextCloud Folder", "Elegir carpeta de NextCloud"), + ("Choose OpenCloud Folder", "Elegir carpeta de OpenCloud"), ("Choose a local folder and an optional remote folder to mirror from this account.", "Elige una carpeta local y una carpeta remota opcional para sincronizarla desde esta cuenta."), ("Choose a local folder to synchronize", "Elige una carpeta local para sincronizar"), ("Choose an absolute local folder.", "Elige una carpeta local absoluta."),