use crate::display::primary_lcd::PrimaryLcdDisplay; use crate::navigation::inputs::ButtonAction; use crate::navigation::navigation::CARD_DATA; use crate::navigation::navigation::NewState; use alloc::format; use embedded_graphics::Drawable; use embedded_graphics::geometry::AngleUnit as _; use embedded_graphics::geometry::Dimensions as _; use embedded_graphics::geometry::Size; use embedded_graphics::mono_font::MonoTextStyle; use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::Point; use embedded_graphics::prelude::RgbColor; use embedded_graphics::primitives::Arc; use embedded_graphics::primitives::Primitive as _; use embedded_graphics::primitives::PrimitiveStyleBuilder; use embedded_graphics::primitives::Rectangle; use embedded_graphics::primitives::StrokeAlignment; use embedded_graphics::text::Alignment; use embedded_graphics::text::Baseline; use embedded_graphics::text::Text; use embedded_graphics::text::TextStyleBuilder; use embedded_graphics_core::draw_target::DrawTarget; use crate::navigation::navigation::{Action, Navigable}; use crate::views::view::View; #[derive(Debug, Clone)] pub struct ScanMenu { pub progress: u8, // 0..255 } impl Navigable for ScanMenu { fn display( &self, display: &mut PrimaryLcdDisplay<'static>, ) -> impl core::future::Future + Send { let style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); display.clear(Rgb565::BLACK).unwrap(); let display_area = display.bounding_box(); Text::new("Scanning...", Point::new(20, 30), style) .draw(display) .unwrap(); // Create styles used by the drawing operations. let arc_stroke = PrimitiveStyleBuilder::new() .stroke_color(Rgb565::WHITE) .stroke_width(5) .stroke_alignment(StrokeAlignment::Inside) .build(); let character_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE); let text_style = TextStyleBuilder::new() .baseline(Baseline::Middle) .alignment(Alignment::Center) .build(); let sweep = self.progress as f32 * 360.0 / 255.0; let width = display_area.size.width; let bounding_box = Rectangle::with_center(display_area.center(), Size::new_equal(4 * width / 5)); // log::info!("bounding_box: {:?}", bounding_box); // log::info!("display_area: {:?}", display_area); // Draw an arc with a 5px wide stroke. Arc::new( bounding_box.top_left, bounding_box.size.width, 90.0.deg(), sweep.deg(), ) .into_styled(arc_stroke) .draw(display) .unwrap(); // Draw centered text. let text = format!("{:.2}%", 100. * (self.progress as f32) / 255.); Text::with_text_style(&text, display_area.center(), character_style, text_style) .draw(display) .unwrap(); core::future::ready(()) } fn handle_input(&self, input: Action) -> impl core::future::Future + Send { async move { log::info!("Scan view detected, checking for NFC card data"); if let Some(card_data) = CARD_DATA.lock().await.take() { log::info!("NFC Card to be displayed: {:?}", card_data); NewState { view: View::Card(crate::views::card_view::CardView { card: card_data }), replace_view: true, redraw: true, } } else { let new_progress = match input { Action::Button(ButtonAction::Up) => self.progress.wrapping_add(5), _ => self.progress, }; NewState { view: View::Scan(ScanMenu { progress: new_progress, }), replace_view: true, redraw: matches!(input, Action::Button(ButtonAction::Up) | Action::Timer), } } } } }