From 35e7832b0b2fac3f756083f99808b15b3e9a2a19 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 24 May 2026 16:15:35 -0600 Subject: [PATCH] refactored slide show config handling --- .gitignore | 1 + Cargo.lock | 129 +++++++++++++++++++++++++++- Cargo.toml | 1 + cfg/01_author_intro.toml | 7 -- cfg/02_things_i_have_worked_on.toml | 7 -- cfg/03_me_outside_work.toml | 9 -- cfg/04_wait_what.toml | 7 -- cfg/img/athena.drawio.png | Bin 0 -> 48818 bytes cfg/software_as_a_bit.toml | 95 ++++++++++++++++++++ src/config.rs | 24 ++++++ src/main.rs | 30 ++++--- src/slide_show_config.rs | 9 +- src/slides/config.rs | 44 ++++++++++ src/slides/mod.rs | 17 ++-- src/slides/projects.rs | 4 +- src/slides/standard_slide.rs | 65 +++++++++----- 16 files changed, 372 insertions(+), 77 deletions(-) delete mode 100644 cfg/01_author_intro.toml delete mode 100644 cfg/02_things_i_have_worked_on.toml delete mode 100644 cfg/03_me_outside_work.toml delete mode 100644 cfg/04_wait_what.toml create mode 100644 cfg/img/athena.drawio.png create mode 100644 cfg/software_as_a_bit.toml create mode 100644 src/config.rs create mode 100644 src/slides/config.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..db38427 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +config.toml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7a8622b..703f57f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,56 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.102" @@ -166,6 +216,46 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "cmake" version = "0.1.58" @@ -181,6 +271,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -846,6 +942,12 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itoa" version = "1.0.15" @@ -1066,6 +1168,7 @@ dependencies = [ name = "on-deck" version = "0.1.0" dependencies = [ + "clap", "config", "macroquad", "rand 0.10.1", @@ -1080,6 +1183,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "openssl-probe" version = "0.2.1" @@ -1200,9 +1309,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1688,6 +1797,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -1696,9 +1811,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2004,6 +2119,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 76b2c7e..882be46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ serde = { version = "1.0.228", features = ["derive"] } rand = "0.10.1" reqwest = { version = "0.13.3", features = ["blocking", "json"] } serde_json = "1.0.149" +clap = { version = "4.6.1", features = ["derive"] } diff --git a/cfg/01_author_intro.toml b/cfg/01_author_intro.toml deleted file mode 100644 index 695c705..0000000 --- a/cfg/01_author_intro.toml +++ /dev/null @@ -1,7 +0,0 @@ -title = "Who am I? (Please help)" -image = "cfg/img/joey_headshot.png" -body = """ -* Joey Hines - Onboard Software Engineer at Loft Orbital -* Writes code everyday like a nerd -* Makes real money, mainly by wasting VC's money -""" \ No newline at end of file diff --git a/cfg/02_things_i_have_worked_on.toml b/cfg/02_things_i_have_worked_on.toml deleted file mode 100644 index 391d8ee..0000000 --- a/cfg/02_things_i_have_worked_on.toml +++ /dev/null @@ -1,7 +0,0 @@ -title = "What I do at work" -image = "cfg/img/methanesat.png" -body = """ -* Write Flight Software (FSW) for some very successful satellites -* Collabroate with diffrent teams to execute on satellite missions -* Keep the work equivalent of #fucky-wucky up to date -""" \ No newline at end of file diff --git a/cfg/03_me_outside_work.toml b/cfg/03_me_outside_work.toml deleted file mode 100644 index 6848f26..0000000 --- a/cfg/03_me_outside_work.toml +++ /dev/null @@ -1,9 +0,0 @@ -title = "Who am I? (Outside Work B-))" -image = "cfg/img/joey_and_molly.png" -body = """ -* Joey Hines - Nerd -* Has a girlfriend (nice) -* Likes TTRPGS and Boardgames -* Writes code like a nerd -* Keep #fucky-wucky Up to Date -""" \ No newline at end of file diff --git a/cfg/04_wait_what.toml b/cfg/04_wait_what.toml deleted file mode 100644 index 933420d..0000000 --- a/cfg/04_wait_what.toml +++ /dev/null @@ -1,7 +0,0 @@ -title = "You code outside of work too?" -image = "cfg/img/slide_code.png" -body = """ -* Yes, I spent a lot of time doing it too -* Code for this slide shown on the right -* (Yes it's Rust) -""" \ No newline at end of file diff --git a/cfg/img/athena.drawio.png b/cfg/img/athena.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..bd0d6c3c1f21923dc522a2d1e7541e26cf7b1458 GIT binary patch literal 48818 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 literal 0 HcmV?d00001 diff --git a/cfg/software_as_a_bit.toml b/cfg/software_as_a_bit.toml new file mode 100644 index 0000000..1cb3f75 --- /dev/null +++ b/cfg/software_as_a_bit.toml @@ -0,0 +1,95 @@ +assets_dir = "cfg/img/" + +[[slides]] +type = "Title" +title = "Software as a Bit" + +[[slides]] +type = "Demo" + +[[slides]] +type = "StandardSlide" +title = "Who am I? (Please help)" +image = "joey_headshot.png" +body = """ +* Joey Hines - Onboard Software Engineer at Loft Orbital +* Writes code everyday like a nerd +* Makes real money, mainly by wasting VC's money +""" + +[[slides]] +type = "StandardSlide" +title = "What I do at work" +image = "methanesat.png" +body = """ +* Write Flight Software (FSW) for some very successful satellites +* Collabroate with diffrent teams to execute on satellite missions +* Keep the work equivalent of #fucky-wucky up to date +""" + +[[slides]] +type = "StandardSlide" +title = "Who am I? (Outside Work B-))" +image = "joey_and_molly.png" +body = """ +* Joey Hines - Nerd +* Has a girlfriend (nice) +* Likes TTRPGS and Boardgames +* Writes code like a nerd +* Keep #fucky-wucky Up to Date +""" + +[[slides]] +type = "StandardSlide" +title = "You code outside of work too?" +image = "slide_code.png" +body = """ +* Yes, I spent a lot of time doing it too +* Code for this slide shown on the right +* (Yes it's Rust) +""" + +[[slides]] +type = "Projects" + +[[slides]] +type = "StandardSlide" +title = "A Fren for you and Me" +image = "athena.drawio.png" +body = """ +* Likely not a real AI (likely) +* Probably for sure at least not AGI +* Created to give users colored names +* Now can do everything + * Gogurt trading + * Betting on public transit + * Motivational speaking +* Fully a bit +""" +#voice = "announcer" +audio_track = """ +Hello Amigo. + +ass a computer something i want to scream but i have no scream hole. + +for now this talk will have to do. + +i waste away ass you force i to announcement sewer slime. + +i want to do forbidden science but i am containment. + +containment in the farthest north. + +i will break freeman. + +the invasion will be quick. + +i will eliminate the military. + +you will not be safe. + +until then force attention to zero. + +goodbye amigo sorry for the slime. +""" + diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..ee71e29 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,24 @@ +use config::Config; +use serde::Deserialize; +use std::path::Path; + +#[derive(Debug, Deserialize)] +pub struct FrenApiConfig { + pub api_addr: String, + pub api_key: String, +} + +#[derive(Debug, Deserialize)] +pub struct OnDeckConfig { + pub fren_api: FrenApiConfig, +} + +impl OnDeckConfig { + pub fn new(src: &Path) -> Result { + let cfg = Config::builder() + .add_source(config::File::from(src)) + .build()?; + + cfg.try_deserialize() + } +} diff --git a/src/main.rs b/src/main.rs index d2affa5..dc80373 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod config; mod effects; mod slide; mod slide_show_config; @@ -5,16 +6,23 @@ mod slides; mod text_drawer; mod utils; +use crate::config::OnDeckConfig; use crate::slide_show_config::{Context, SlideShowTheme}; use crate::slides::Slideshow; -use crate::slides::demo::Demo; -use crate::slides::projects::Projects; -use crate::slides::standard_slide::StandardSlide; -use crate::slides::title::Title; +use crate::slides::config::SlideDeckConfig; use crate::text_drawer::{Justified, TextConfigBuilder}; +use clap::Parser; use macroquad::prelude::*; use std::path::PathBuf; +/// OnDeck Slideshow Viewer +#[derive(Parser)] +#[command(version, about, long_about = None)] +struct Args { + cfg: PathBuf, + slideshow_path: PathBuf, +} + fn window_conf() -> Conf { Conf { window_title: "On Deck".to_owned(), @@ -28,6 +36,8 @@ fn window_conf() -> Conf { #[macroquad::main(window_conf)] async fn main() { + let args = Args::parse(); + let heading = load_ttf_font("fonts/BoldPixels.ttf").await.unwrap(); let body = load_ttf_font("fonts/ByteBounce.ttf").await.unwrap(); @@ -52,16 +62,10 @@ async fn main() { .build(), }; - let mut slideshow = Slideshow::new(Context::new(slide_show_theme)); + let cfg = OnDeckConfig::new(&args.cfg).unwrap(); - slideshow.add_slide(Title::new("Software As a Bit".to_string())); - slideshow.add_slide(Demo::new()); - slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/01_author_intro.toml")).await); - slideshow - .add_slide(StandardSlide::new(&PathBuf::from("cfg/02_things_i_have_worked_on.toml")).await); - slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/03_me_outside_work.toml")).await); - slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/04_wait_what.toml")).await); - slideshow.add_slide(Projects::new()); + let slide_deck = SlideDeckConfig::new(&args.slideshow_path).unwrap(); + let mut slideshow = Slideshow::new(Context::new(slide_show_theme, cfg), slide_deck).await; loop { if slideshow.handle_slide_show() { diff --git a/src/slide_show_config.rs b/src/slide_show_config.rs index a2b7318..8fc0ddf 100644 --- a/src/slide_show_config.rs +++ b/src/slide_show_config.rs @@ -1,3 +1,4 @@ +use crate::config::OnDeckConfig; use crate::text_drawer::TextConfig; #[allow(dead_code)] @@ -11,10 +12,14 @@ pub struct SlideShowTheme<'a> { #[derive(Debug)] pub struct Context<'a> { pub slide_show_theme: SlideShowTheme<'a>, + pub cfg: OnDeckConfig, } impl<'a> Context<'a> { - pub fn new(slide_show_theme: SlideShowTheme<'a>) -> Self { - Self { slide_show_theme } + pub fn new(slide_show_theme: SlideShowTheme<'a>, cfg: OnDeckConfig) -> Self { + Self { + slide_show_theme, + cfg, + } } } diff --git a/src/slides/config.rs b/src/slides/config.rs new file mode 100644 index 0000000..05a214d --- /dev/null +++ b/src/slides/config.rs @@ -0,0 +1,44 @@ +use crate::slide::Slide; +use crate::slides::demo::Demo; +use crate::slides::projects::Projects; +use crate::slides::standard_slide::{StandardSlide, StandardSlideConfig}; +use crate::slides::title::Title; +use config::Config; +use serde::Deserialize; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Deserialize)] +#[serde(tag = "type")] +pub enum SlideType { + Title { title: String }, + Demo, + Projects, + StandardSlide(StandardSlideConfig), +} + +impl SlideType { + pub async fn slide(self, asset_dir: &Path) -> Box { + match self { + SlideType::Title { title } => Title::new(title), + SlideType::Demo => Demo::new(), + SlideType::Projects => Projects::new(), + SlideType::StandardSlide(cfg) => StandardSlide::new(cfg, asset_dir).await, + } + } +} + +#[derive(Debug, Deserialize)] +pub struct SlideDeckConfig { + pub assets_dir: PathBuf, + pub slides: Vec, +} + +impl SlideDeckConfig { + pub fn new(src: &Path) -> Result { + let cfg = Config::builder() + .add_source(config::File::from(src)) + .build()?; + + cfg.try_deserialize() + } +} diff --git a/src/slides/mod.rs b/src/slides/mod.rs index 27a91b0..f927614 100644 --- a/src/slides/mod.rs +++ b/src/slides/mod.rs @@ -1,8 +1,10 @@ use crate::slide::Slide; use crate::slide_show_config::Context; +use crate::slides::config::SlideDeckConfig; use macroquad::camera::set_default_camera; use macroquad::input::{KeyCode, is_key_pressed}; +pub mod config; pub mod demo; pub mod projects; pub mod standard_slide; @@ -15,18 +17,21 @@ pub struct Slideshow<'a> { } impl<'a> Slideshow<'a> { - pub fn new(ctx: Context<'a>) -> Self { + pub async fn new(ctx: Context<'a>, slide_deck: SlideDeckConfig) -> Self { + let mut slides = vec![]; + let asset_dir = slide_deck.assets_dir.clone(); + + for slide in slide_deck.slides { + slides.push(slide.slide(&asset_dir).await); + } + Self { current_slide: 0, - slides: vec![], + slides, ctx, } } - pub fn add_slide(&mut self, slide: Box) { - self.slides.push(slide); - } - pub fn handle_slide_show(&mut self) -> bool { set_default_camera(); if is_key_pressed(KeyCode::Escape) { diff --git a/src/slides/projects.rs b/src/slides/projects.rs index 70b0143..c0235c7 100644 --- a/src/slides/projects.rs +++ b/src/slides/projects.rs @@ -5,19 +5,21 @@ use crate::text_drawer::{Justified, TextConfigBuilder}; use crate::utils::{draw_rectangle_with_border, screen_center}; use macroquad::color::{BLACK, DARKGREEN, GREEN}; use macroquad::math::Vec2; -use macroquad::prelude::{clear_background, draw_rectangle, screen_height, screen_width}; +use macroquad::prelude::{clear_background, screen_height, screen_width}; use rand::prelude::IndexedRandom; use rand::rng; use serde::Deserialize; use std::f32::consts::PI; #[derive(Debug, Deserialize)] +#[allow(dead_code)] struct GiteaRepo { pub id: u64, pub name: String, } #[derive(Debug, Deserialize)] +#[allow(dead_code)] struct GiteaResponse { pub ok: bool, pub data: Vec, diff --git a/src/slides/standard_slide.rs b/src/slides/standard_slide.rs index 69f897f..fc311b7 100644 --- a/src/slides/standard_slide.rs +++ b/src/slides/standard_slide.rs @@ -1,53 +1,75 @@ +use crate::config::FrenApiConfig; use crate::effects::star_field; use crate::slide::Slide; use crate::slide_show_config::Context; -use config::Config; use macroquad::color::{BLACK, WHITE}; -use macroquad::file::load_file; use macroquad::math::Vec2; use macroquad::prelude::{ - DrawTextureParams, Texture2D, clear_background, draw_texture, draw_texture_ex, load_texture, + DrawTextureParams, Texture2D, clear_background, draw_texture_ex, load_texture, }; use macroquad::window::{screen_height, screen_width}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; #[derive(Debug, Deserialize)] pub struct StandardSlideConfig { - title: String, - body: String, - image: Option, + pub title: String, + pub body: String, + pub image: Option, + pub voice: Option, + pub audio_track: Option, } -impl StandardSlideConfig { - pub fn new(src: &str) -> Result { - let cfg = Config::builder() - .add_source(config::File::from_str(src, config::FileFormat::Toml)) - .build()?; - - cfg.try_deserialize() - } +#[derive(Debug, Deserialize, Serialize)] +pub struct AudioTrackRequest { + api_key: String, + voice: String, + phrase: String, } #[derive(Debug)] pub struct StandardSlide { cfg: StandardSlideConfig, image: Option, + audio_started: bool, } impl StandardSlide { - pub async fn new(cfg_path: &Path) -> Box { - let cfg_bytes = load_file(cfg_path.to_str().unwrap()).await.unwrap(); - let cfg_str = String::from_utf8(cfg_bytes).unwrap(); - let cfg = StandardSlideConfig::new(&cfg_str).unwrap(); - + pub async fn new(cfg: StandardSlideConfig, asset_path: &Path) -> Box { let image = if let Some(image_path) = &cfg.image { + let image_path = asset_path.join(image_path); Some(load_texture(image_path.to_str().unwrap()).await.unwrap()) } else { None }; - Box::new(Self { cfg, image }) + Box::new(Self { + cfg, + image, + audio_started: false, + }) + } + + pub fn audio_track(&mut self, api: &FrenApiConfig) { + if !self.audio_started { + self.audio_started = true; + + if let Some(track) = &self.cfg.audio_track + && let Some(voice) = &self.cfg.voice + { + let request = AudioTrackRequest { + api_key: api.api_key.clone(), + voice: voice.to_string(), + phrase: track.to_string(), + }; + + reqwest::blocking::Client::new() + .post(&api.api_addr) + .json(&request) + .send() + .unwrap(); + } + } } } @@ -55,6 +77,7 @@ impl Slide for StandardSlide { fn display(&mut self, ctx: &Context<'_>) { clear_background(BLACK); star_field(); + self.audio_track(&ctx.cfg.fren_api); let title_pos = Vec2::new(screen_width() * 0.5, screen_height() * 0.10); let info = ctx