diff options
Diffstat (limited to 'karlgui/src')
-rw-r--r-- | karlgui/src/globals.rs | 96 | ||||
-rw-r--r-- | karlgui/src/helper.rs | 5 | ||||
-rw-r--r-- | karlgui/src/main.rs | 29 | ||||
-rw-r--r-- | karlgui/src/views/calendar.rs | 68 | ||||
-rw-r--r-- | karlgui/src/views/edit.rs | 2 |
5 files changed, 164 insertions, 36 deletions
diff --git a/karlgui/src/globals.rs b/karlgui/src/globals.rs new file mode 100644 index 0000000..202cce6 --- /dev/null +++ b/karlgui/src/globals.rs @@ -0,0 +1,96 @@ +use crate::{client::Client, helper::from_timestamp}; +use chrono::NaiveDateTime; +use karlcommon::{ClientboundPacket, ServerboundPacket, Task}; +use log::warn; +use std::{ + collections::{HashMap, VecDeque}, + ops::Range, +}; + +pub struct Globals { + pub client: Client, + pub tasks: HashMap<u64, Task>, + pub awaiting_instance_requests: VecDeque<(u64, Range<NaiveDateTime>)>, + + pub instance_cache: + HashMap<(u64, Range<NaiveDateTime>), Option<Vec<Range<Option<NaiveDateTime>>>>>, +} + +impl Globals { + pub fn new(client: Client) -> Self { + Globals { + client, + tasks: Default::default(), + instance_cache: Default::default(), + awaiting_instance_requests: Default::default(), + } + } + pub fn update_network(&mut self) { + for p in self.client.receiver.try_iter() { + match p { + ClientboundPacket::TaskList(t) => { + self.tasks = HashMap::from_iter(t.into_iter().map(|e| (e.id, e))); + } + ClientboundPacket::Sync => { + self.client.busy = false; + } + ClientboundPacket::InstanceList(is) => { + if let Some(i) = self.awaiting_instance_requests.pop_front() { + self.instance_cache.insert( + i, + Some( + is.iter() + .map(|r| r.start.map(from_timestamp)..r.end.map(from_timestamp)) + .collect(), + ), + ); + } else { + warn!("got unknown instance list packet") + } + } + _ => {} + } + } + } + pub fn get_all_instances_range( + &mut self, + start: NaiveDateTime, + end: NaiveDateTime, + ) -> Option<Vec<(u64, Range<Option<NaiveDateTime>>)>> { + let mut l = vec![]; + for t in &self.tasks.values().map(|e| e.id).collect::<Vec<_>>() { + if let Some(r) = self.get_instances_range(*t, start, end) { + l.extend(r.into_iter().map(|e| (*t, e.clone()))); + } + } + if l.len() > 0 { + Some(l) + } else { + None + } + } + pub fn get_instances_range( + &mut self, + task: u64, + start: NaiveDateTime, + end: NaiveDateTime, + ) -> &Option<Vec<Range<Option<NaiveDateTime>>>> { + // looks silly but the borrow checker likes it more + let has = self.instance_cache.contains_key(&(task, start..end)); + if has { + if let Some(c) = self.instance_cache.get(&(task, start..end)) { + return c; + } + return &None; + } + self.awaiting_instance_requests + .push_back((task, start..end)); + self.instance_cache.insert((task, start..end), None); + self.client.send_sync(ServerboundPacket::ListInstances { + task, + range: Some(start.timestamp())..Some(end.timestamp()), + limit: 100, + }); + &None + } +} diff --git a/karlgui/src/helper.rs b/karlgui/src/helper.rs index eb4c981..4f8f4f4 100644 --- a/karlgui/src/helper.rs +++ b/karlgui/src/helper.rs @@ -1,6 +1,11 @@ +use chrono::NaiveDateTime; use egui::{DragValue, Ui}; use karlcommon::Property; +pub fn from_timestamp(t: i64) -> NaiveDateTime { + NaiveDateTime::from_timestamp(t, 0) +} + pub fn format_value(prop: Property, value: i64) -> String { match prop { Property::Year => format!("{value}"), diff --git a/karlgui/src/main.rs b/karlgui/src/main.rs index d683a78..b3a6f62 100644 --- a/karlgui/src/main.rs +++ b/karlgui/src/main.rs @@ -1,11 +1,12 @@ pub mod client; +pub mod globals; pub mod helper; pub mod views; -use crate::client::Client; +use crate::{client::Client, globals::Globals}; use eframe::CreationContext; use egui::CentralPanel; -use karlcommon::{socket_path, ClientboundPacket, ServerboundPacket, Task}; +use karlcommon::{socket_path, ServerboundPacket}; use log::{error, info}; use std::{os::unix::net::UnixStream, process::exit}; use views::{calendar::Calendar, edit::ShowAndEdit}; @@ -19,11 +20,6 @@ fn main() { ) } -pub struct Globals { - client: Client, - tasks: Vec<Task>, -} - struct App { g: Globals, @@ -57,31 +53,16 @@ impl App { client.send(ServerboundPacket::ListTasks); App { current_tab: Tab::ShowAndEdit, - g: Globals { - client, - tasks: vec![], - }, + g: Globals::new(client), show_and_edit: Default::default(), calendar: Default::default(), } } - - pub fn update_network(&mut self) { - for p in self.g.client.receiver.try_iter() { - match p { - ClientboundPacket::TaskList(t) => self.g.tasks = t, - ClientboundPacket::Sync => { - self.g.client.busy = false; - } - _ => {} - } - } - } } impl eframe::App for App { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - self.update_network(); + self.g.update_network(); CentralPanel::default().show(ctx, |ui| { ui.add_enabled_ui(!self.g.client.busy, |ui| { ui.horizontal(|ui| { diff --git a/karlgui/src/views/calendar.rs b/karlgui/src/views/calendar.rs index b216504..c332b80 100644 --- a/karlgui/src/views/calendar.rs +++ b/karlgui/src/views/calendar.rs @@ -1,12 +1,32 @@ +use std::ops::Range; + use crate::{helper::weekday_to_str, Globals}; +use chrono::{Duration, NaiveDateTime}; use egui::Ui; use egui_extras::TableBuilder; #[derive(Default)] -pub struct Calendar; +pub struct Calendar { + // offset: NaiveDate, +} impl Calendar { - pub fn ui(&mut self, ui: &mut Ui, _g: &mut Globals) { + pub fn ui(&mut self, ui: &mut Ui, g: &mut Globals) { + let start_date = chrono::Utc::now().date_naive(); //self.offset; + let end_date = start_date + chrono::Duration::days(7); + let start_dt = start_date.and_hms(0, 0, 0); + let end_dt = end_date.and_hms(0, 0, 0); + + let instances = if let Some(instances) = g.get_all_instances_range(start_dt, end_dt) { + instances + } else { + ui.horizontal(|ui| { + ui.spinner(); + ui.label("Loading…"); + }); + return; + }; + TableBuilder::new(ui) .column(egui_extras::Size::exact(50.0)) .columns(egui_extras::Size::remainder(), 7) @@ -18,17 +38,43 @@ impl Calendar { }); } }) - .body(|ui| { - ui.rows(50.0, 24, |h, mut ui| { - ui.col(|ui| { - ui.heading(&format!("{h:02}:00")); - }); - for d in 0..7 { + .body(|mut ui| { + let mut cols: [Vec<u64>; 7] = + [vec![], vec![], vec![], vec![], vec![], vec![], vec![]]; + for h in 0..24 { + ui.row(50.0, |mut ui| { ui.col(|ui| { - ui.label(&format!("day {d} at {h}:00")); + ui.heading(&format!("{h:02}:00")); }); - } - }) + for d in 0..7 { + let _col = &mut cols[d]; + let time = start_dt + Duration::days(d as i64) + Duration::hours(h); + let instances_here = + instances.iter().filter(|(_, r)| r.includes(&time)); + + ui.col(|ui| { + for (id, _) in instances_here { + g.tasks.get(id).unwrap(); + ui.label(&format!("{id}")); + } + }); + } + }) + } }) } } + +trait Includes<T> { + fn includes(&self, p: &T) -> bool; +} +impl Includes<NaiveDateTime> for Range<Option<NaiveDateTime>> { + fn includes(&self, p: &NaiveDateTime) -> bool { + match (&self.start, &self.end) { + (None, None) => false, + (None, Some(e)) => p < e, + (Some(s), None) => s <= p, + (Some(s), Some(e)) => s <= p && p < e, + } + } +} diff --git a/karlgui/src/views/edit.rs b/karlgui/src/views/edit.rs index 04146dd..0a8058c 100644 --- a/karlgui/src/views/edit.rs +++ b/karlgui/src/views/edit.rs @@ -15,7 +15,7 @@ pub struct ShowAndEdit { impl ShowAndEdit { pub fn ui(&mut self, ui: &mut Ui, g: &mut Globals) { - for t in &mut g.tasks { + for t in g.tasks.values_mut() { let edit = self.edit == Some(t.id); let changed = if edit { if ui.button("💾 Save").clicked() { |