feat: more stuff

This commit is contained in:
Strix 2024-03-05 18:17:01 +01:00
parent c83273e4da
commit dae1b6f190
No known key found for this signature in database
GPG key ID: 5F35B3B8537287A7
10 changed files with 164 additions and 50 deletions

19
Cargo.lock generated
View file

@ -554,6 +554,9 @@ name = "bitflags"
version = "2.4.2" version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "block" name = "block"
@ -936,9 +939,12 @@ version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"eframe", "eframe",
"egui",
"egui_extras", "egui_extras",
"env_logger", "env_logger",
"reqwest", "reqwest",
"serde",
"serde_json",
] ]
[[package]] [[package]]
@ -1047,6 +1053,7 @@ dependencies = [
"epaint", "epaint",
"log", "log",
"nohash-hasher", "nohash-hasher",
"ron",
"serde", "serde",
] ]
@ -2740,6 +2747,18 @@ dependencies = [
"winreg", "winreg",
] ]
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags 2.4.2",
"serde",
"serde_derive",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.23" version = "0.1.23"

View file

@ -8,6 +8,7 @@ publish = false
[dependencies] [dependencies]
chrono = "0.4.34" chrono = "0.4.34"
egui = { version = "0.26.2", features = ["persistence"] }
eframe = { version = "0.26.2", features = [ eframe = { version = "0.26.2", features = [
"default", "default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
@ -21,3 +22,5 @@ env_logger = { version = "0.11.2", default-features = false, features = [
"humantime", "humantime",
] } ] }
reqwest = { version = "0.11.24", features = ["blocking"] } reqwest = { version = "0.11.24", features = ["blocking"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"

View file

@ -6,13 +6,24 @@ use eframe::{
App, App,
}; };
use crate::prelude::CanonicalName;
#[derive(Default)]
pub struct ClockWidget; pub struct ClockWidget;
impl CanonicalName for ClockWidget {
fn canonical_name() -> String {
"Clock".into()
}
}
impl App for ClockWidget { impl App for ClockWidget {
fn update(&mut self, ctx: &eframe::egui::Context, frame: &mut eframe::Frame) { fn update(&mut self, ctx: &eframe::egui::Context, frame: &mut eframe::Frame) {
Window::new("Clock") Window::new("Clock")
.title_bar(false)
.resizable(false) .resizable(false)
.movable(true) .movable(true)
.open(&mut true)
.show(ctx, |ui| { .show(ctx, |ui| {
ui.label( ui.label(
RichText::new(Local::now().format("%H:%M:%S").to_string()) RichText::new(Local::now().format("%H:%M:%S").to_string())

View file

@ -1,3 +1,4 @@
pub mod uptime; pub mod uptime;
pub mod greeting; pub mod greeting;
pub mod clock; pub mod clock;
pub mod todo;

39
src/apps/todo.rs Normal file
View file

@ -0,0 +1,39 @@
use eframe::WindowBuilder;
use egui::{Key, Window};
use crate::prelude::CanonicalName;
#[derive(Default)]
pub struct TodoWidget {
todos: Vec<(String, bool)>,
_goal_input_cache: String,
}
impl CanonicalName for TodoWidget {
fn canonical_name() -> String {
"Todos".into()
}
}
impl eframe::App for TodoWidget {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
Window::new("Todos").show(ctx, |ui| {
self.todos.sort_by_key(|a| !a.1);
self.todos.retain_mut(|t| {
ui.horizontal(|ui| {
ui.checkbox(&mut t.1, t.0.clone());
!ui.button("remove").clicked()
})
.inner
});
ui.horizontal(|ui| {
ui.text_edit_singleline(&mut self._goal_input_cache);
if ctx.input(|i| i.key_pressed(Key::Enter)) || ui.button("add").clicked() {
self.todos.push((self._goal_input_cache.clone(), false));
self._goal_input_cache = String::default();
}
});
});
}
}

View file

@ -1,13 +1,17 @@
use eframe::egui::{Color32, Context, Label, Response, Ui, Widget}; use chrono::Local;
use eframe::egui::{Color32, Context, Label, Response, RichText, Ui, Widget};
use eframe::{egui, Frame}; use eframe::{egui, Frame};
use reqwest::Url; use serde::{Deserialize, Serialize};
use std::default;
use std::ops::Sub; use std::ops::Sub;
use std::str::FromStr; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use std::time::{Duration, Instant};
use crate::prelude::CanonicalName;
#[derive(Serialize, Deserialize)]
pub struct MonitorTarget { pub struct MonitorTarget {
url: String, url: String,
last_update: Instant, last_update: u128,
last_status: bool, last_status: bool,
} }
@ -16,14 +20,14 @@ impl MonitorTarget {
MonitorTarget { MonitorTarget {
url: url.into(), url: url.into(),
last_status: false, last_status: false,
last_update: Instant::now().sub(Duration::new(30, 0)), last_update: Local::now().timestamp_millis() as u128,
} }
} }
pub fn check(&mut self) -> bool { pub fn check(&mut self) -> bool {
if self.last_update.elapsed().as_secs() > 30 { if (Local::now().timestamp_millis() as u128 - self.last_update) > 30 {
self.last_status = reqwest::blocking::get(self.url.as_str()).is_ok(); self.last_status = reqwest::blocking::get(self.url.as_str()).is_ok();
self.last_update = Instant::now(); self.last_update = Local::now().timestamp_millis() as u128;
} }
self.last_status self.last_status
} }
@ -35,23 +39,27 @@ pub struct UptimeWidget {
_url_input_cache: String, _url_input_cache: String,
} }
impl CanonicalName for UptimeWidget {
fn canonical_name() -> String {
"Uptimes".into()
}
}
impl eframe::App for UptimeWidget { impl eframe::App for UptimeWidget {
fn update(&mut self, ctx: &Context, frame: &mut Frame) { fn update(&mut self, ctx: &Context, frame: &mut Frame) {
egui::Window::new("Uptime Widget").show(ctx, |ui| { egui::Window::new("Uptime Settings")
self.targets.retain_mut(|target| { .default_open(false)
.show(ctx, |ui| {
self.targets.retain(|t| {
ui.add_space(1.);
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label(target.url.clone()); ui.style_mut().visuals.extreme_bg_color = Color32::DARK_GRAY;
ui.label({ ui.label(t.url.clone());
if target.check() { !ui.button("remove").clicked()
format!("OK ({}s ago)", target.last_update.elapsed().as_secs())
} else {
format!("FAIL ({}s ago)", target.last_update.elapsed().as_secs())
}
});
!ui.button("x").clicked()
}) })
.inner .inner
}); });
ui.add_space(2.);
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.text_edit_singleline(&mut self._url_input_cache) ui.text_edit_singleline(&mut self._url_input_cache)
.on_hover_text("URL to add"); .on_hover_text("URL to add");
@ -61,10 +69,33 @@ impl eframe::App for UptimeWidget {
self._url_input_cache = String::default(); self._url_input_cache = String::default();
} }
}); });
});
if ui.is_visible() { self.targets.iter_mut().for_each(|t| {
egui::Window::new(t.url.clone())
.title_bar(false)
.movable(true)
.resizable(true)
.show(ctx, |ui| {
ui.vertical_centered(|ui| {
ui.label(t.url.clone());
ui.label({
if ctx.is_using_pointer() {
RichText::new("...")
} else if t.check() {
RichText::new("Up").color(Color32::LIGHT_GREEN)
} else {
RichText::new("Down")
.color(Color32::LIGHT_RED)
.strong()
}.size(32.)
});
});
});
});
if self.targets.len() > 0 {
ctx.request_repaint(); ctx.request_repaint();
} }
});
} }
} }

View file

@ -2,11 +2,14 @@ use std::collections::HashMap;
use crate::apps::clock::ClockWidget; use crate::apps::clock::ClockWidget;
use crate::apps::greeting::Greeting; use crate::apps::greeting::Greeting;
use crate::apps::todo::TodoWidget;
use crate::apps::uptime::UptimeWidget; use crate::apps::uptime::UptimeWidget;
use crate::prelude::CanonicalName;
use eframe::egui::accesskit::Role::Window; use eframe::egui::accesskit::Role::Window;
use eframe::egui::panel::Side; use eframe::egui::panel::Side;
use eframe::egui::{CentralPanel, Id, SidePanel}; use eframe::egui::{CentralPanel, Id, SidePanel};
use eframe::{egui, App}; use eframe::{egui, App};
use serde::{Deserialize, Serialize};
#[derive(Default)] #[derive(Default)]
pub struct Dashboard { pub struct Dashboard {
@ -29,16 +32,16 @@ impl Dashboard {
} }
macro_rules! register_app { macro_rules! register_app {
($dash:ident, $ui:ident, $name:literal, $app:expr) => { ($dash:ident, $ui:ident, $app:tt) => {
let button = $ui.button($name); let button = $ui.button($app::canonical_name());
if button.clicked() { if button.clicked() {
if $dash.has_app($name) { if $dash.has_app($app::canonical_name()) {
$dash.remove_app($name); $dash.remove_app($app::canonical_name());
} else { } else {
$dash.add_app($name, Box::new($app)); $dash.add_app($app::canonical_name(), Box::new($app::default()));
} }
} }
if $dash.has_app($name) { if $dash.has_app($app::canonical_name()) {
button.highlight(); button.highlight();
} }
}; };
@ -48,10 +51,11 @@ impl eframe::App for Dashboard {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
SidePanel::new(Side::Left, Id::new("side_panel")).show(ctx, |ui| { SidePanel::new(Side::Left, Id::new("side_panel")).show(ctx, |ui| {
ui.heading("Apps"); ui.heading("Apps");
register_app!(self, ui, "Clock", ClockWidget); register_app!(self, ui, ClockWidget);
register_app!(self, ui, "Uptime Widget", UptimeWidget::default()); register_app!(self, ui, UptimeWidget);
register_app!(self, ui, TodoWidget);
}); });
CentralPanel::default().show(ctx, |ui| {}); CentralPanel::default().show(ctx, |_| {});
self.apps.iter_mut().for_each(|(_, app)| { self.apps.iter_mut().for_each(|(_, app)| {
app.update(ctx, frame); app.update(ctx, frame);
}) })

View file

@ -7,9 +7,11 @@ use dashboard::Dashboard;
use eframe::egui; use eframe::egui;
use std::ops::Sub; use std::ops::Sub;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::prelude::CanonicalName;
mod apps; mod apps;
mod dashboard; mod dashboard;
pub mod prelude;
fn main() -> Result<(), eframe::Error> { fn main() -> Result<(), eframe::Error> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`). env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

3
src/prelude.rs Normal file
View file

@ -0,0 +1,3 @@
pub trait CanonicalName {
fn canonical_name() -> String;
}

1
todo.txt Normal file
View file

@ -0,0 +1 @@
persistance