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:
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
+ );
+ }
}