use crate::effects::star_field; use crate::slide::Slide; use crate::slide_show_config::Context; 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, 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, } #[derive(Debug)] struct FloatingText { pos: Vec2, vel: Vec2, text: String, } #[derive(Debug)] pub struct Projects { repos: Vec, } impl Projects { pub fn new() -> Box { let resp: GiteaResponse = reqwest::blocking::get("https://git.ahines.net/api/v1/repos/search") .unwrap() .json() .unwrap(); let repos: Vec = resp .data .into_iter() .filter_map(|r| { if !r.name.starts_with("_") { Some(FloatingText { pos: Default::default(), vel: Default::default(), text: r.name, }) } else { None } }) .collect(); Box::new(Self { repos }) } } impl Slide for Projects { fn display(&mut self, ctx: &Context<'_>) { clear_background(BLACK); star_field(); let text_cfg = TextConfigBuilder::new(ctx.slide_show_theme.body_config.clone()) .font_size(75) .justification(Justified::Center) .build(); for repo in &mut self.repos { if repo.pos.x <= 0.0 || repo.pos.y <= 0.0 || repo.pos.x > screen_width() || repo.pos.y > screen_height() { repo.pos = screen_center(); let vel: f32 = rand::random_range(1.0..1.5); let angle: f32 = rand::random_range(0.0..2.0 * PI); repo.vel = Vec2::new(vel, 0.0).rotate(Vec2::from(angle.sin_cos())); repo.vel = Vec2::new(rand::random_range(0.1..1.5), rand::random_range(0.1..1.5)); repo.vel.x *= [-1.0, 1.0].choose(&mut rng()).unwrap(); repo.vel.y *= [-1.0, 1.0].choose(&mut rng()).unwrap(); } text_cfg.draw_text(&repo.text, repo.pos); repo.pos += repo.vel } let dim = ctx .slide_show_theme .heading_config .measure_text("https://git.ahines.net"); let background_rectangle_size = Vec2::new(dim.width * 1.2, dim.height * 1.2); let pos = screen_center() - background_rectangle_size * 0.5 - Vec2::new(0.0, dim.offset_y * 0.5); draw_rectangle_with_border( pos, background_rectangle_size, background_rectangle_size.x * 0.01, GREEN, DARKGREEN, ); ctx.slide_show_theme .heading_config .draw_text("https://git.ahines.net", screen_center()); } }