use crate::card::model::Card; use crate::navigation::inputs::ButtonAction; use crate::navigation::inputs::Inputs; use crate::navigation::outputs::Outputs; use crate::navigation::state::NavigationState; use crate::views::view::View; use embassy_futures::select::{Either, select}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time::{Duration, Timer}; pub type Mutex = embassy_sync::mutex::Mutex; pub type Signal = embassy_sync::signal::Signal; pub static CARD_DATA: Mutex> = Mutex::new(None); const DEBOUNCE_DURATION_MILLIS: u64 = 100; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Action { Button(ButtonAction), Timer, } pub struct NewState { pub view: View, pub replace_view: bool, pub redraw: bool, } pub trait Navigable { fn display(&self, outputs: &mut Outputs) -> impl core::future::Future + Send; fn handle_input(&self, input: Action) -> impl core::future::Future + Send; } #[embassy_executor::task] pub async fn run(mut inputs: Inputs, mut outputs: Outputs) { log::info!("starting navigation"); let mut state = NavigationState::new(); state.screens.last().unwrap().display(&mut outputs).await; loop { let selection = select( inputs.wait_for_press(), Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)), ) .await; let action = match selection { Either::First(button) => Action::Button(button), Either::Second(_) => Action::Timer, }; if Action::Timer != action { log::info!("Action: {:?}", action); } let new_state = if action == Action::Button(ButtonAction::Back) { if state.screens.len() > 1 { state.screens.pop(); } NewState { view: state.screens.last().expect("no screen on stack").clone(), replace_view: false, redraw: true, } } else { let new_state = state .screens .last() .expect("no screen on stack") .handle_input(action) .await; if action == Action::Timer && !new_state.redraw { continue; } new_state }; if new_state.replace_view { state.screens.pop(); } state.screens.push(new_state.view); if action != Action::Timer || new_state.redraw { state.screens.last().unwrap().display(&mut outputs).await; } Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await; } }