app

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

commit 2d6c259ef6c15d16e849445dfab6504c79b2951f
parent 140c6e99217b0f681450df0a5f53a1294f895559
Author: triesap <tyson@radroots.org>
Date:   Sun, 22 Mar 2026 02:12:02 +0000

core: add home location tools module

- add a dedicated core module for future home location lookup state instead of growing the root app file further
- move home location tool lifecycle ownership into the app state so it resets cleanly across identity transitions
- keep the extraction slice behavior-neutral while establishing the first real geocoder consumer boundary
- add core tests covering the location tool state reset contract

Diffstat:
Acrates/core/src/home_location_tools.rs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/core/src/lib.rs | 8++++++++
2 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/crates/core/src/home_location_tools.rs b/crates/core/src/home_location_tools.rs @@ -0,0 +1,55 @@ +use crate::{RadrootsLocationPoint, RadrootsResolvedLocation}; + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct HomeLocationLookupResult { + pub queried_point: RadrootsLocationPoint, + pub matches: Vec<RadrootsResolvedLocation>, +} + +#[derive(Debug, Default, Clone, PartialEq)] +pub(crate) struct HomeLocationTools { + latitude_input: String, + longitude_input: String, + status_message: Option<String>, + lookup_result: Option<HomeLocationLookupResult>, +} + +impl HomeLocationTools { + pub(crate) fn new() -> Self { + Self::default() + } + + pub(crate) fn clear(&mut self) { + self.latitude_input.clear(); + self.longitude_input.clear(); + self.status_message = None; + self.lookup_result = None; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn clear_resets_inputs_and_feedback() { + let mut tools = HomeLocationTools::new(); + tools.latitude_input = "10.5".to_owned(); + tools.longitude_input = "20.5".to_owned(); + tools.status_message = Some("lookup failed".to_owned()); + tools.lookup_result = Some(HomeLocationLookupResult { + queried_point: RadrootsLocationPoint { + lat: 10.5, + lng: 20.5, + }, + matches: Vec::new(), + }); + + tools.clear(); + + assert_eq!(tools.latitude_input, ""); + assert_eq!(tools.longitude_input, ""); + assert_eq!(tools.status_message, None); + assert_eq!(tools.lookup_result, None); + } +} diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs @@ -4,6 +4,7 @@ use eframe::egui; use std::time::Duration; use zeroize::Zeroizing; +mod home_location_tools; mod location_resolver; mod offline_geocoder; @@ -18,6 +19,8 @@ pub use offline_geocoder::{ RadrootsOfflineGeocoderState, RadrootsOfflineGeocoderUnavailableKind, }; +use home_location_tools::HomeLocationTools; + #[derive(Debug, Clone, PartialEq, Eq)] pub struct SetupActionState { pub label: String, @@ -137,6 +140,7 @@ pub struct RadrootsApp { screen: AppScreen, offline_geocoder_state: Option<RadrootsOfflineGeocoderState>, status_message: Option<String>, + home_location_tools: HomeLocationTools, pending_home_confirmation: Option<HomeActionKind>, pending_import_entry: bool, secret_key_input: Zeroizing<String>, @@ -150,6 +154,7 @@ impl RadrootsApp { screen: AppScreen::Setup, offline_geocoder_state: None, status_message: None, + home_location_tools: HomeLocationTools::new(), pending_home_confirmation: None, pending_import_entry: false, secret_key_input: Zeroizing::new(String::new()), @@ -171,6 +176,7 @@ impl RadrootsApp { IdentityGateState::Missing => { self.screen = AppScreen::Setup; self.status_message = None; + self.home_location_tools.clear(); self.pending_home_confirmation = None; self.pending_import_entry = false; self.secret_key_input.clear(); @@ -179,6 +185,7 @@ impl RadrootsApp { IdentityGateState::Ready { account_id, npub } => { self.screen = AppScreen::Home { account_id, npub }; self.status_message = None; + self.home_location_tools.clear(); self.pending_home_confirmation = None; self.pending_import_entry = false; self.secret_key_input.clear(); @@ -187,6 +194,7 @@ impl RadrootsApp { IdentityGateState::Unsupported { reason } => { self.screen = AppScreen::Setup; self.status_message = Some(reason); + self.home_location_tools.clear(); self.pending_home_confirmation = None; self.pending_import_entry = false; self.secret_key_input.clear();