96 lines
2.9 KiB
Rust
96 lines
2.9 KiB
Rust
use crate::card::model::Card;
|
|
use crate::display::shared_bus::DualPrimaryDisplay;
|
|
use crate::navigation::inputs::ButtonAction;
|
|
use crate::navigation::inputs::Inputs;
|
|
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};
|
|
use embedded_graphics::draw_target::DrawTarget;
|
|
use embedded_graphics::pixelcolor::Rgb565;
|
|
|
|
pub type Mutex<T> = embassy_sync::mutex::Mutex<CriticalSectionRawMutex, T>;
|
|
pub type Signal<T> = embassy_sync::signal::Signal<CriticalSectionRawMutex, T>;
|
|
pub static CARD_DATA: Mutex<Option<Card>> = 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<D>(&self, display: &mut D) -> impl core::future::Future<Output = ()> + Send
|
|
where
|
|
D: DrawTarget<Color = Rgb565> + Send,
|
|
D::Error: core::fmt::Debug;
|
|
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = NewState> + Send;
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
pub async fn run(mut inputs: Inputs, display: &'static mut DualPrimaryDisplay<'static>) {
|
|
log::info!("starting navigation");
|
|
|
|
let mut state = NavigationState::new();
|
|
state.screens.last().unwrap().display(display).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(display).await;
|
|
}
|
|
|
|
Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await;
|
|
}
|
|
}
|