use std::sync::mpsc::Receiver; use eframe::{ egui::{self, RichText, ScrollArea, Window}, emath::Align, epaint::Color32, }; use serde::{Deserialize, Serialize}; use tungstenite::Message; pub struct App { rx: Receiver, history: Vec, autoscroll: bool, description: String, selected_channel: String, channels: Vec, description_shown: bool, } #[derive(Serialize, Deserialize)] struct Log { name: String, description: String, message: String, channel: String, } impl App { pub fn new(rx: Receiver) -> Self { Self { rx, history: Vec::new(), autoscroll: false, description: "".to_string(), selected_channel: "".to_string(), channels: Vec::new(), description_shown: false, } } } impl eframe::App for App { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { let message = self.rx.try_recv(); // TODO: Add toasts for things like debug information and status changes (https://github.com/urholaukkarinen/egui-toast) if let Ok(message) = message { let text = message.to_string(); let json = serde_json::from_str(&text); if let Ok(json) = json { self.history.push(json); } } egui::CentralPanel::default().show(ctx, |ui| { Window::new("Description") .open(&mut self.description_shown) .collapsible(false) .show(ctx, |ui| { ScrollArea::vertical() .id_source("description_box") .show(ui, |ui| { ui.label(&self.description); }); }); ui.horizontal(|ui| { ui.checkbox(&mut self.autoscroll, "Autoscroll"); if ui.button("Reset").clicked() { self.history.clear(); self.channels.clear(); self.selected_channel.clear(); self.description.clear(); } if ui.button("Description").clicked() { self.description_shown = true; } }); ui.separator(); ui.horizontal(|ui| { ScrollArea::horizontal() .id_source("channel_bar") .show(ui, |ui| { for channel in &self.channels { if ui.button(channel).clicked() { self.selected_channel = channel.to_owned(); } } }); }); ui.separator(); ScrollArea::vertical() .id_source("messages_list") .show(ui, |ui| { for msg in &self.history { if !self.channels.contains(&msg.channel) { self.channels.push((&msg.channel).to_owned()); } if msg.channel == self.selected_channel { ui.horizontal(|ui| { ui.label(RichText::new(&msg.name).color(Color32::LIGHT_GRAY)); if !&msg.description.is_empty() { self.description = (&msg.description).to_owned(); ui.label(RichText::new("[AI]").color(Color32::DARK_GRAY)); } }); ui.label(&msg.message); ui.separator(); } if self.autoscroll { ui.scroll_to_cursor(Some(Align::BOTTOM)); } } }); }); ctx.request_repaint(); } }