app

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

commit e7157c55f9b970b5aa71e6ced52e33a2506f0e3b
parent 5888af48e2a36555fc273c795d75aba44f26039e
Author: triesap <tyson@radroots.org>
Date:   Sat, 21 Mar 2026 16:33:27 +0000

android: add remove-key action for local identities

- add the remove-key action to the android backend and remove the selected local account back to setup
- add an android unit test covering the generate-then-remove transition
- keep the change scoped to the android launcher crate with no android vault or host-project drift
- validate the android crate, host build, and emulator launch path before the commit

Diffstat:
Mcrates/android/src/lib.rs | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 63 insertions(+), 3 deletions(-)

diff --git a/crates/android/src/lib.rs b/crates/android/src/lib.rs @@ -6,10 +6,10 @@ use android_logger::Config; use eframe::egui::ViewportBuilder; #[cfg(any(target_os = "android", test))] use radroots_app_core::RadrootsAppBackend; -#[cfg(target_os = "android")] -use radroots_app_core::{APP_NAME, RadrootsApp}; #[cfg(any(target_os = "android", test))] -use radroots_app_core::{IdentityGateState, SetupActionState}; +use radroots_app_core::{HomeActionState, IdentityGateState, SetupActionState}; +#[cfg(target_os = "android")] +use radroots_app_core::{RadrootsApp, APP_NAME}; #[cfg(test)] use radroots_identity::RadrootsIdentity; #[cfg(test)] @@ -70,6 +70,35 @@ impl RadrootsAppBackend for AndroidBackend { Ok(Some(Self::unsupported_identity_state())) } } + + fn home_remove_action_state(&self) -> Option<HomeActionState> { + #[cfg(target_os = "android")] + { + return Some(HomeActionState { + label: "Remove Key From This Device".to_owned(), + enabled: true, + pending: false, + }); + } + + #[cfg(not(target_os = "android"))] + { + None + } + } + + fn request_home_remove_action(&self) -> Result<Option<IdentityGateState>, String> { + #[cfg(target_os = "android")] + { + let manager = Self::accounts_manager()?; + return Self::remove_selected_local_identity(&manager).map(Some); + } + + #[cfg(not(target_os = "android"))] + { + Ok(None) + } + } } #[cfg(any(target_os = "android", test))] @@ -134,6 +163,22 @@ impl AndroidBackend { .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(any(target_os = "android", test))] @@ -263,4 +308,19 @@ mod tests { assert!(!account_id.is_empty()); assert!(npub.starts_with("npub1")); } + + #[test] + fn local_identity_removal_transitions_android_back_to_missing() { + let manager = RadrootsNostrAccountsManager::new_in_memory(); + + AndroidBackend::generate_local_identity(&manager).expect("generate identity"); + let state = AndroidBackend::remove_selected_local_identity(&manager) + .expect("remove selected account"); + + assert_eq!(state, IdentityGateState::Missing); + assert_eq!( + manager.selected_account_id().expect("selected account"), + None + ); + } }