From 559324ceb11bcd5cdc0f2ee2ac5870df12c7a5e4 Mon Sep 17 00:00:00 2001 From: Jamie Pine Date: Thu, 23 Oct 2025 18:36:17 -0700 Subject: [PATCH] refactor: remove RegisterOnly and redesign sync setup UX Replace confusing RegisterOnly action with clearer ShareLocalLibrary and JoinRemoteLibrary actions. Add placeholder for future MergeLibraries. - Remove RegisterOnly from LibrarySyncAction enum - Add ShareLocalLibrary (share your library to remote device) - Add JoinRemoteLibrary (join existing remote library) - Add MergeLibraries stub for future implementation - Update CLI with three-option menu instead of two - Simplify CLI arg parsing for new actions The new UX is clearer: users choose to either share their library or join a remote one, instead of the ambiguous "register only" concept. --- apps/cli/src/domains/library/args.rs | 40 ++++++++++++---- apps/cli/src/domains/library/mod.rs | 61 +++++++++++++----------- core/src/ops/network/sync_setup/input.rs | 27 ++++++----- 3 files changed, 79 insertions(+), 49 deletions(-) diff --git a/apps/cli/src/domains/library/args.rs b/apps/cli/src/domains/library/args.rs index 7a815dd91..42f28fbdd 100644 --- a/apps/cli/src/domains/library/args.rs +++ b/apps/cli/src/domains/library/args.rs @@ -161,21 +161,45 @@ impl SetupArgs { }; // Parse action - let action_str = self.action.as_deref().unwrap_or("register-only"); + let action_str = self.action.as_deref().unwrap_or("share-local"); let action = match action_str { - "register-only" => LibrarySyncAction::RegisterOnly, - "create-shared" => { + "share-local" => { let name = self .name .clone() - .ok_or_else(|| anyhow::anyhow!("--name is required for create-shared action"))?; - LibrarySyncAction::CreateShared { - leader_device_id, - name, + .ok_or_else(|| anyhow::anyhow!("--name is required for share-local action"))?; + LibrarySyncAction::ShareLocalLibrary { library_name: name } + } + "join-remote" => { + let remote_library_id = self + .remote_library + .ok_or_else(|| anyhow::anyhow!("--remote-library is required for join-remote action"))?; + let name = self + .name + .clone() + .ok_or_else(|| anyhow::anyhow!("--name is required for join-remote action"))?; + LibrarySyncAction::JoinRemoteLibrary { + remote_library_id, + remote_library_name: name, + } + } + "merge" => { + let local_library_id = local_library; + let remote_library_id = self + .remote_library + .ok_or_else(|| anyhow::anyhow!("--remote-library is required for merge action"))?; + let name = self + .name + .clone() + .ok_or_else(|| anyhow::anyhow!("--name is required for merge action"))?; + LibrarySyncAction::MergeLibraries { + local_library_id, + remote_library_id, + merged_name: name, } } _ => anyhow::bail!( - "Invalid action '{}'. Supported: register-only, create-shared", + "Invalid action '{}'. Supported: share-local, join-remote, merge", action_str ), }; diff --git a/apps/cli/src/domains/library/mod.rs b/apps/cli/src/domains/library/mod.rs index ea1c46da8..7d2aaeb5a 100644 --- a/apps/cli/src/domains/library/mod.rs +++ b/apps/cli/src/domains/library/mod.rs @@ -326,16 +326,31 @@ async fn run_interactive_sync_setup(ctx: &Context) -> Result { - // Register existing library + // Share local library + let name = libraries[library_idx].name.clone(); + + println!( + "\n✓ Will share library '{}' to remote device '{}'\n", + name, remote_device.name + ); + + ( + LibrarySyncAction::ShareLocalLibrary { library_name: name }, + None, + ) + } + 1 => { + // Join remote library if discovery_out.libraries.is_empty() { - anyhow::bail!("No libraries found on remote device. Use 'Create shared library' instead."); + anyhow::bail!("No libraries found on remote device. Use 'Share my library' instead."); } let remote_lib_choices: Vec = discovery_out @@ -349,42 +364,30 @@ async fn run_interactive_sync_setup(ctx: &Context) -> Result { - // Create shared library - the local library selected earlier will be shared to the remote device - let name = libraries[library_idx].name.clone(); - - println!( - "\n✓ Will share library '{}' to remote device '{}'\n", - name, remote_device.name + "\n✓ Will join remote library: {}\n", + remote_library.name ); ( - LibrarySyncAction::CreateShared { - leader_device_id: local_device_id, - name, + LibrarySyncAction::JoinRemoteLibrary { + remote_library_id: remote_library.id, + remote_library_name: remote_library.name.clone(), }, - None, + Some(remote_library.id), ) } + 2 => { + anyhow::bail!("Library merging is not yet implemented"); + } _ => unreachable!(), }; - let leader_device_id = match &action.0 { - LibrarySyncAction::CreateShared { - leader_device_id, .. - } => *leader_device_id, - _ => local_device_id, - }; + // Leader device is always local for now (deprecated concept but still in input struct) + let leader_device_id = local_device_id; Ok(LibrarySyncSetupInput { local_device_id, diff --git a/core/src/ops/network/sync_setup/input.rs b/core/src/ops/network/sync_setup/input.rs index bbbcc7419..b1a5b5095 100644 --- a/core/src/ops/network/sync_setup/input.rs +++ b/core/src/ops/network/sync_setup/input.rs @@ -8,23 +8,26 @@ use uuid::Uuid; #[derive(Debug, Clone, Serialize, Deserialize, Type)] #[serde(tag = "type", rename_all = "camelCase")] pub enum LibrarySyncAction { - /// Keep libraries separate, only register devices in each other's libraries - /// This allows Spacedrop and future selective sync without full library merge - RegisterOnly, - - /// Future: Merge remote library into local (local becomes leader) + /// Share local library to remote device (creates same library with same UUID on remote) + /// This is the primary way to create a shared library #[serde(rename_all = "camelCase")] - MergeIntoLocal { remote_library_id: Uuid }, + ShareLocalLibrary { library_name: String }, - /// Future: Merge local library into remote (remote becomes leader) + /// Join an existing remote library (creates same library with same UUID locally) + /// Use this when the other device has already shared their library #[serde(rename_all = "camelCase")] - MergeIntoRemote { local_library_id: Uuid }, + JoinRemoteLibrary { + remote_library_id: Uuid, + remote_library_name: String, + }, - /// Future: Create new shared library (choose leader) + /// Future: Merge two different libraries into one (combines data from both) + /// Not yet implemented - requires full sync system #[serde(rename_all = "camelCase")] - CreateShared { - leader_device_id: Uuid, - name: String, + MergeLibraries { + local_library_id: Uuid, + remote_library_id: Uuid, + merged_name: String, }, }