aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <yvchraiqi@protonmail.com>2022-08-17 10:54:02 +0200
committermetamuffin <yvchraiqi@protonmail.com>2022-08-17 10:54:02 +0200
commitcfc5fd51582d694b98ff69a680d0ad727354c8c3 (patch)
treeded58259b8eb3f8b25cc543a6c28883809a72127
parent5e6509163df53788799bb7aa97d07a90bf416eb7 (diff)
downloadkarlender-cfc5fd51582d694b98ff69a680d0ad727354c8c3.tar
karlender-cfc5fd51582d694b98ff69a680d0ad727354c8c3.tar.bz2
karlender-cfc5fd51582d694b98ff69a680d0ad727354c8c3.tar.zst
idk
-rw-r--r--Cargo.lock31
-rw-r--r--karlgui/Cargo.toml1
-rw-r--r--karlgui/src/globals.rs96
-rw-r--r--karlgui/src/helper.rs5
-rw-r--r--karlgui/src/main.rs29
-rw-r--r--karlgui/src/views/calendar.rs68
-rw-r--r--karlgui/src/views/edit.rs2
7 files changed, 193 insertions, 39 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d5cf770..8113137 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -45,6 +45,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
+name = "android_system_properties"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "anyhow"
version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -179,15 +188,17 @@ dependencies = [
[[package]]
name = "chrono"
-version = "0.4.19"
+version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [
- "libc",
+ "iana-time-zone",
+ "js-sys",
"num-integer",
"num-traits",
"serde",
"time",
+ "wasm-bindgen",
"winapi",
]
@@ -739,6 +750,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
+name = "iana-time-zone"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef5528d9c2817db4e10cc78f8d4c8228906e5854f389ff6b076cee3572a09d35"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys 0.8.3",
+ "js-sys",
+ "wasm-bindgen",
+ "winapi",
+]
+
+[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -853,6 +877,7 @@ dependencies = [
name = "karlgui"
version = "0.1.0"
dependencies = [
+ "chrono",
"crossbeam-channel",
"eframe",
"egui",
diff --git a/karlgui/Cargo.toml b/karlgui/Cargo.toml
index fd1aec0..caf0777 100644
--- a/karlgui/Cargo.toml
+++ b/karlgui/Cargo.toml
@@ -8,6 +8,7 @@ karlcommon = { path = "../karlcommon" }
crossbeam-channel = "0.5.6"
serde_json = "1.0.83"
+chrono = "0.4.22"
env_logger = "0.9.0"
log = "0.4.17"
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() {