app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 5888af48e2a36555fc273c795d75aba44f26039e
parent 0d64bb263df61730fb202f0dde55e79476c8359d
Author: triesap <tyson@radroots.org>
Date:   Sat, 21 Mar 2026 12:58:12 +0000

ios: add remove-key action for local identities

- add the remove-key action to the ios backend and remove the selected local account back to setup
- add an ios unit test covering the generate-then-remove transition
- scope eframe features per launcher crate so the ios host build stays on the intended renderer path
- keep desktop and android launcher validation green after the feature split

Diffstat:
MCargo.toml | 2+-
Mcrates/android/Cargo.toml | 2+-
Mcrates/desktop/Cargo.toml | 2+-
Mcrates/ios/Cargo.toml | 2+-
Mcrates/ios/src/lib.rs | 48+++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -22,7 +22,7 @@ readme = "README.md" [workspace.dependencies] android_logger = "0.15.1" directories = "6" -eframe = { version = "0.33.3", default-features = false, features = ["android-game-activity", "default_fonts", "glow", "wgpu", "wayland", "x11"] } +eframe = { version = "0.33.3", default-features = false, features = ["default_fonts"] } egui = { version = "0.33.3", features = ["serde"] } image = { version = "0.25.10", default-features = false, features = ["ico", "png"] } jni = "0.21.1" diff --git a/crates/android/Cargo.toml b/crates/android/Cargo.toml @@ -15,7 +15,7 @@ path = "src/lib.rs" crate-type = ["cdylib", "rlib"] [dependencies] -eframe.workspace = true +eframe = { workspace = true, features = ["android-game-activity", "glow"] } log.workspace = true radroots-app-core = { path = "../core" } radroots-identity.workspace = true diff --git a/crates/desktop/Cargo.toml b/crates/desktop/Cargo.toml @@ -16,7 +16,7 @@ workspace = true [dependencies] directories.workspace = true -eframe.workspace = true +eframe = { workspace = true, features = ["wgpu", "wayland", "x11"] } egui.workspace = true image.workspace = true radroots-app-core = { path = "../core" } diff --git a/crates/ios/Cargo.toml b/crates/ios/Cargo.toml @@ -15,7 +15,7 @@ path = "src/lib.rs" crate-type = ["staticlib", "rlib"] [dependencies] -eframe.workspace = true +eframe = { workspace = true, features = ["wgpu"] } radroots-app-apple-security.workspace = true radroots-app-core = { path = "../core" } radroots-identity.workspace = true diff --git a/crates/ios/src/lib.rs b/crates/ios/src/lib.rs @@ -5,7 +5,9 @@ use eframe::egui::ViewportBuilder; #[cfg(any(target_os = "ios", test))] use radroots_app_core::IdentityGateState; #[cfg(target_os = "ios")] -use radroots_app_core::{APP_NAME, RadrootsApp, RadrootsAppBackend, SetupActionState}; +use radroots_app_core::{ + HomeActionState, RadrootsApp, RadrootsAppBackend, SetupActionState, APP_NAME, +}; #[cfg(any(target_os = "ios", test))] use radroots_nostr_accounts::prelude::{ RadrootsNostrAccountsManager, RadrootsNostrSelectedAccountStatus, @@ -52,6 +54,22 @@ impl IosBackend { .map_err(|source| source.to_string())?; Self::identity_state_from_manager(manager) } + + fn remove_selected_local_identity( + manager: &RadrootsNostrAccountsManager, + ) -> Result<IdentityGateState, String> { + let Some(account_id) = manager + .selected_account_id() + .map_err(|source| source.to_string())? + else { + return Ok(IdentityGateState::Missing); + }; + + manager + .remove_account(&account_id) + .map_err(|source| source.to_string())?; + Self::identity_state_from_manager(manager) + } } #[cfg(target_os = "ios")] @@ -73,6 +91,19 @@ impl RadrootsAppBackend for IosBackend { let manager = Self::accounts_manager()?; Self::generate_local_identity(&manager).map(Some) } + + fn home_remove_action_state(&self) -> Option<HomeActionState> { + Some(HomeActionState { + label: "Remove Key From This Device".to_owned(), + enabled: true, + pending: false, + }) + } + + fn request_home_remove_action(&self) -> Result<Option<IdentityGateState>, String> { + let manager = Self::accounts_manager()?; + Self::remove_selected_local_identity(&manager).map(Some) + } } #[cfg(target_os = "ios")] @@ -152,4 +183,19 @@ mod tests { assert!(!account_id.is_empty()); assert!(npub.starts_with("npub1")); } + + #[test] + fn local_identity_removal_transitions_back_to_missing() { + let manager = RadrootsNostrAccountsManager::new_in_memory(); + + IosBackend::generate_local_identity(&manager).expect("generate identity"); + let state = + IosBackend::remove_selected_local_identity(&manager).expect("remove selected account"); + + assert_eq!(state, IdentityGateState::Missing); + assert_eq!( + manager.selected_account_id().expect("selected account"), + None + ); + } }