Mainmenu #28

Merged
rhetenor merged 19 commits from mainmenu into main 2026-08-18 23:44:28 +02:00
4 changed files with 105 additions and 57 deletions
Showing only changes of commit 0fb87f2913 - Show all commits
+33 -1
View File
@@ -1,3 +1,5 @@
use core::future;
use crate::{display::primary_lcd::PrimaryLcdDisplay, navigation::inputs::Inputs};
use alloc::format;
@@ -10,13 +12,16 @@ use embedded_graphics::text::Text;
use embedded_graphics::{Drawable, geometry::Size, primitives::Rectangle};
use embedded_graphics_core::draw_target::DrawTarget;
use super::state::Menu;
pub const MAX_SELECTED: i8 = 3;
#[derive(Debug, Clone)]
pub struct MainMenu {
pub selected: i8,
}
impl super::navigation::Displayable for MainMenu {
impl super::navigation::Navigable for MainMenu {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
@@ -62,4 +67,31 @@ impl super::navigation::Displayable for MainMenu {
core::future::ready(())
}
fn handle_input(
&self,
input: super::navigation::Action,
) -> impl core::future::Future<Output = Menu> + Send {
let new_menu = match input {
super::navigation::Action::Up => {
let new_selected = if (self.selected - 1) < 0 {
MAX_SELECTED - 1
} else {
self.selected - 1
};
Menu::Main(MainMenu {
selected: new_selected,
})
}
super::navigation::Action::Down => {
let new_selected = self.selected.wrapping_add(1) % MAX_SELECTED;
Menu::Main(MainMenu {
selected: new_selected,
})
}
_ => Menu::Main(self.clone()),
};
future::ready(new_menu)
}
}
+24 -38
View File
@@ -1,4 +1,4 @@
use crate::navigation::main_menu::{MAX_SELECTED, MainMenu};
use crate::navigation::state::{Menu, NavigationState};
use crate::{display::primary_lcd::PrimaryLcdDisplay, navigation::inputs::Inputs};
use embassy_futures::select::Either6;
@@ -7,21 +7,30 @@ use embassy_time::{Duration, Timer};
const DEBOUNCE_DURATION_MILLIS: u64 = 100;
pub trait Displayable {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Action {
Up,
Down,
Left,
Right,
Ok,
Back,
}
pub trait Navigable {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send;
fn handle_input(&self, input: Action) -> impl core::future::Future<Output = Menu> + Send;
}
#[embassy_executor::task]
pub async fn run(mut inputs: Inputs, display: &'static mut PrimaryLcdDisplay<'static>) {
let mut state = MainMenu { selected: 0 };
let mut state = NavigationState::default();
state.display(display).await;
log::info!("starting navigation");
loop {
log::info!("await button press");
let selection = select6(
inputs.up.wait_for_low(),
inputs.down.wait_for_low(),
@@ -32,41 +41,18 @@ pub async fn run(mut inputs: Inputs, display: &'static mut PrimaryLcdDisplay<'st
)
.await;
log::info!("button pressed");
let value = match selection {
Either6::First(_) => {
log::info!("up pressed");
if (state.selected - 1) < 0 {
MAX_SELECTED - 1
} else {
state.selected - 1
}
}
Either6::Second(_) => {
log::info!("down pressed");
(state.selected.wrapping_add(1)) % MAX_SELECTED
}
Either6::Third(_) => {
log::info!("left pressed");
continue;
}
Either6::Fourth(_) => {
log::info!("right pressed");
continue;
}
Either6::Fifth(_) => {
log::info!("ok pressed");
continue;
}
Either6::Sixth(_) => {
log::info!("back pressed");
continue;
}
let action = match selection {
Either6::First(_) => Action::Up,
Either6::Second(_) => Action::Down,
Either6::Third(_) => Action::Left,
Either6::Fourth(_) => Action::Right,
Either6::Fifth(_) => Action::Ok,
Either6::Sixth(_) => Action::Back,
};
state.selected = value;
state.display(display).await;
log::info!("Action: {:?}", action);
state.current_screen = state.current_screen.handle_input(action).await;
state.current_screen.display(display).await;
Timer::after(Duration::from_millis(DEBOUNCE_DURATION_MILLIS)).await;
}
+11 -1
View File
@@ -19,11 +19,14 @@ use embedded_graphics::text::Text;
use embedded_graphics::text::TextStyleBuilder;
use embedded_graphics_core::draw_target::DrawTarget;
use super::state::Menu;
#[derive(Debug, Clone)]
pub struct ScanMenu {
progress: u8, // 0..255
}
impl super::navigation::Displayable for ScanMenu {
impl super::navigation::Navigable for ScanMenu {
fn display(
&self,
display: &mut PrimaryLcdDisplay<'static>,
@@ -69,4 +72,11 @@ impl super::navigation::Displayable for ScanMenu {
core::future::ready(())
}
fn handle_input(
&self,
_input: super::navigation::Action,
) -> impl core::future::Future<Output = Menu> + Send {
core::future::ready(Menu::Scan(self.clone()))
}
}
+37 -17
View File
@@ -1,23 +1,49 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScreenMode {
CardDetail,
DexGrid,
use crate::navigation::{main_menu::MainMenu, navigation::Navigable, scan_menu::ScanMenu};
#[derive(Debug, Clone)]
pub enum Menu {
Main(MainMenu),
Scan(ScanMenu),
Settings,
}
#[derive(Debug, Clone, Copy)]
impl Navigable for Menu {
fn display(
&self,
display: &mut crate::display::primary_lcd::PrimaryLcdDisplay<'static>,
) -> impl core::future::Future<Output = ()> + Send {
async move {
match self {
Menu::Main(main_menu) => main_menu.display(display).await,
Menu::Scan(scan_menu) => scan_menu.display(display).await,
Menu::Settings => {}
}
}
}
fn handle_input(
&self,
input: crate::navigation::navigation::Action,
) -> impl core::future::Future<Output = Self> + Send {
async move {
match self {
Menu::Main(main_menu) => main_menu.handle_input(input).await,
Menu::Scan(scan_menu) => scan_menu.handle_input(input).await,
Menu::Settings => Self::Settings,
}
}
}
}
#[derive(Debug, Clone)]
pub struct NavigationState {
pub current_screen: ScreenMode,
pub card_index: usize,
pub use_first_payload: bool,
pub current_screen: Menu,
}
impl Default for NavigationState {
fn default() -> Self {
Self {
current_screen: ScreenMode::CardDetail,
card_index: 0,
use_first_payload: true,
current_screen: Menu::Main(MainMenu { selected: 0 }),
}
}
}
@@ -26,10 +52,4 @@ impl NavigationState {
pub fn new() -> Self {
Self::default()
}
pub fn toggle_payload(&mut self) -> bool {
let current = self.use_first_payload;
self.use_first_payload = !self.use_first_payload;
current
}
}