From 853895df799e57df74cebcfe7c10bccbd94cd944 Mon Sep 17 00:00:00 2001 From: Joscha Date: Wed, 13 Mar 2024 02:29:43 +0100 Subject: [PATCH] Add /calendar --- Cargo.lock | 41 +++++++++ showbits-thermal-printer/Cargo.toml | 1 + showbits-thermal-printer/src/drawer.rs | 4 + .../src/drawer/calendar.rs | 89 +++++++++++++++++++ showbits-thermal-printer/src/server.rs | 17 ++++ 5 files changed, 152 insertions(+) create mode 100644 showbits-thermal-printer/src/drawer/calendar.rs diff --git a/Cargo.lock b/Cargo.lock index d46b276..fd687c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,6 +365,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -882,6 +891,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.18" @@ -1061,6 +1076,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1368,6 +1389,7 @@ dependencies = [ "serde", "showbits-common", "taffy", + "time", "tokio", ] @@ -1502,6 +1524,25 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/showbits-thermal-printer/Cargo.toml b/showbits-thermal-printer/Cargo.toml index a788903..889f46a 100644 --- a/showbits-thermal-printer/Cargo.toml +++ b/showbits-thermal-printer/Cargo.toml @@ -16,6 +16,7 @@ rust-embed = "8.3.0" serde = { version = "1.0.197", features = ["derive"] } showbits-common.workspace = true taffy.workspace = true +time = "0.3.34" tokio = { version = "1.36.0", features = ["full"] } [lints] diff --git a/showbits-thermal-printer/src/drawer.rs b/showbits-thermal-printer/src/drawer.rs index b28616a..4c88c26 100644 --- a/showbits-thermal-printer/src/drawer.rs +++ b/showbits-thermal-printer/src/drawer.rs @@ -1,3 +1,5 @@ +mod calendar; + use image::RgbaImage; use showbits_common::{ color::{BLACK, WHITE}, @@ -20,6 +22,7 @@ pub enum Command { Image(RgbaImage), Photo { image: RgbaImage, title: String }, ChatMessage { username: String, content: String }, + Calendar { year: i32, month: u8 }, } #[derive(Default)] @@ -72,6 +75,7 @@ impl Drawer { Command::ChatMessage { username, content } => { self.on_chat_message(username, content)? } + Command::Calendar { year, month } => self.draw_calendar(year, month)?, } Ok(()) } diff --git a/showbits-thermal-printer/src/drawer/calendar.rs b/showbits-thermal-printer/src/drawer/calendar.rs new file mode 100644 index 0000000..b32fa0b --- /dev/null +++ b/showbits-thermal-printer/src/drawer/calendar.rs @@ -0,0 +1,89 @@ +use showbits_common::{ + color::{BLACK, WHITE}, + widgets::{Block, Text}, + Node, Tree, WidgetExt, +}; +use taffy::{ + style_helpers::{length, percent, repeat}, AlignContent, AlignItems, Display, FlexDirection +}; +use time::Date; + +use super::{Context, Drawer}; + +impl Drawer { + pub fn draw_calendar(&mut self, year: i32, month: u8) -> anyhow::Result<()> { + let mut date = Date::from_calendar_date(year, month.try_into()?, 1)?; + + let mut tree = Tree::::new(WHITE); + + let mut grid = Node::empty() + .with_display(Display::Grid) + .with_grid_template_columns(vec![repeat(7, vec![length(50.0)])]) + .with_grid_auto_rows(vec![length(50.0)]) + .with_gap(length(2.0)); + + for weekday in ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"] { + let text = Text::new() + .with_metrics(Text::default_metrics().scale(2.0)) + .and_plain(weekday) + .widget(&mut self.ctx.font_stuff) + .node() + .with_justify_self(Some(AlignItems::Center)) + .with_align_self(Some(AlignItems::Center)) + .register(&mut tree)?; + + grid = grid.and_child(text); + } + + let placeholders = date.weekday().number_days_from_monday(); + for _ in 0..placeholders { + let empty = Node::empty().register(&mut tree)?; + grid = grid.and_child(empty); + } + + loop { + let day = Text::new() + .and_plain(date.day().to_string()) + .widget(&mut self.ctx.font_stuff) + .node() + .register(&mut tree)?; + + let block = Block::new() + .with_border(BLACK) + .node() + .with_border(length(2.0)) + .with_display(Display::Flex) + .with_justify_content(Some(AlignContent::Center)) + .with_align_items(Some(AlignItems::Center)) + .and_child(day) + .register(&mut tree)?; + + grid = grid.and_child(block); + + let next_day = date.next_day().unwrap(); + if date.month() != next_day.month() { + break; + } + date = next_day; + } + + let title = Text::new() + .and_plain(format!("Ankreuzkalender {year:04}-{month:02}")) + .widget(&mut self.ctx.font_stuff) + .node() + .register(&mut tree)?; + + let root = Node::empty() + .with_size_width(percent(1.0)) + .with_padding_bottom(length(Self::FEED)) + .with_display(Display::Flex) + .with_flex_direction(FlexDirection::Column) + .with_align_items(Some(AlignItems::Center)) + .and_child(title) + .and_child(grid.register(&mut tree)?) + .register(&mut tree)?; + + self.printer.print_tree(&mut tree, &mut self.ctx, root)?; + Ok(()) + } +} diff --git a/showbits-thermal-printer/src/server.rs b/showbits-thermal-printer/src/server.rs index 43444ad..13e5eda 100644 --- a/showbits-thermal-printer/src/server.rs +++ b/showbits-thermal-printer/src/server.rs @@ -30,6 +30,7 @@ pub async fn run(tx: mpsc::Sender, addr: String) -> anyhow::Result<()> .route("/image", post(post_image).fallback(get_static_file)) .route("/photo", post(post_photo).fallback(get_static_file)) .route("/chat_message", post(post_chat_message)) + .route("/calendar", post(post_calendar)) .fallback(get(get_static_file)) .layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB .with_state(Server { tx }); @@ -124,3 +125,19 @@ async fn post_chat_message(server: State, request: Form, request: Form) { + let _ = server + .tx + .send(Command::Calendar { + year: request.0.year, + month: request.0.month, + }) + .await; +}