diff --git a/Cargo.lock b/Cargo.lock index 5aa4671..7877dc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,7 +147,7 @@ dependencies = [ [[package]] name = "aliveline" -version = "0.1.0" +version = "0.1.1" dependencies = [ "chrono", "serde", diff --git a/Cargo.toml b/Cargo.toml index b7d15fc..49e34c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aliveline" -version = "0.1.0" +version = "0.1.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/main.rs b/src/main.rs index 19baaa8..3285d0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use std::{error::Error, rc::Rc, sync::{Arc, Mutex}}; use aliveline::{config::Config, load_config, log::{Event, Log}}; use chrono::{Datelike, Timelike}; -use slint::{Model, ModelRc, SharedString, ToSharedString, VecModel}; +use slint::{Model, ModelRc, SharedString, ToSharedString, VecModel, Weak}; use toml::value::{Date as TomlDate, Time}; slint::include_modules!(); @@ -46,6 +46,20 @@ impl From for Event { } } +fn load_log(ui_weak: Weak, log: Arc>) { + let ui = ui_weak.unwrap(); + let log_guard = log.lock().expect("Log shouldn't be used twice"); + let events: Vec = (*log_guard) + .events + .iter() + .map(|event| TimelineEvent::from((*event).clone())) + .collect(); + let in_progress = events.iter().any(|event| !event.finished); + let model: ModelRc = Rc::new(VecModel::from(events)).into(); + ui.set_record_events(model); + ui.set_in_progress(in_progress); +} + fn main() -> Result<(), Box> { let ui = AppWindow::new()?; @@ -61,23 +75,9 @@ fn main() -> Result<(), Box> { let config: Arc = Arc::new(load_config()); let writing_log: Arc> = Arc::new(Mutex::new(Log::load_from(&config, date))); - { - let ui_weak = ui.as_weak(); - let log = writing_log.clone(); - (move || { - let ui = ui_weak.unwrap(); - let log_guard = log.lock().expect("Log shouldn't be used twice"); - let events: Vec = (*log_guard) - .events - .iter() - .map(|event| TimelineEvent::from((*event).clone())) - .collect(); - let in_progress = events.iter().any(|event| !event.finished); - let model: ModelRc = Rc::new(VecModel::from(events)).into(); - ui.set_record_events(model); - ui.set_in_progress(in_progress); - })() - } + let ui_weak = ui.as_weak(); + let log = writing_log.clone(); + load_log(ui_weak, log); ui.invoke_update_record_offset(offset as i32); @@ -165,7 +165,8 @@ fn main() -> Result<(), Box> { let ui = ui_weak.unwrap(); let events_rc = ui.get_record_events(); let events = events_rc.as_any() - .downcast_ref::>().unwrap(); + .downcast_ref::>() + .unwrap(); let offset = ui.get_record_offset(); let event_id = events.iter() @@ -182,9 +183,9 @@ fn main() -> Result<(), Box> { { let mut log_guard = log.lock().expect("Log shouldn't be used twice"); - (*log_guard).events.push(Event::from(new_event.clone())); - let index = (*log_guard).events.iter().position(|data| !data.finished).unwrap(); - (*log_guard).events.swap_remove(index); + log_guard.events.push(Event::from(new_event.clone())); + let index = log_guard.events.iter().position(|data| !data.finished).unwrap(); + log_guard.events.swap_remove(index); } ui.invoke_save_log(); @@ -202,6 +203,47 @@ fn main() -> Result<(), Box> { } }); + ui.on_new_day_started({ + let ui_weak = ui.as_weak(); + let log = writing_log.clone(); + move || { + let ui = ui_weak.unwrap(); + + let new_event: Option = { + let log_guard = log.lock().expect("Log shouldn't be used twice"); + + let maybe_unfinished_event = log_guard.events.iter().find(|event| !event.finished); + match maybe_unfinished_event { + Some(unfinished_event) => Some(Event::new(unfinished_event.name.clone(), 0, 0, false)), + None => None + } + }; + + ui.invoke_stop_event(); + + { + let mut log_guard = log.lock().expect("Log shouldn't be used twice"); + log_guard.events.clear(); + let now = chrono::Local::now(); + + let date = TomlDate { + year: now.year() as u16, + month: now.month() as u8, + day: now.day() as u8 + }; + + log_guard.date = date; + log_guard.events.clear(); + + if let Some(event) = new_event { + log_guard.events.push(event); + } + } + + load_log(ui.as_weak(), log.clone()); + ui.invoke_save_log(); + } + }); ui.run()?; diff --git a/ui/app-window.slint b/ui/app-window.slint index 89a10b6..373e060 100644 --- a/ui/app-window.slint +++ b/ui/app-window.slint @@ -7,6 +7,7 @@ export component AppWindow inherits Window { callback start-new-event <=> record.start-new-event; callback stop-event <=> record.stop-event; callback chain-event <=> record.chain-event; + callback new-day-started <=> record.new-day-started; callback update-record-offset(int); callback save-log; diff --git a/ui/record.slint b/ui/record.slint index cf195af..d8a942a 100644 --- a/ui/record.slint +++ b/ui/record.slint @@ -2,6 +2,7 @@ import { VerticalBox, LineEdit, Button, ComboBox } from "std-widgets.slint"; import { Timeline } from "timeline.slint"; export component RecordWidget inherits VerticalBox { + callback new-day-started <=> tl.new-day-started; callback update-visible-time(string); callback start-new-event(string); callback chain-event(string); diff --git a/ui/review.slint b/ui/review.slint index 9727c24..14727ce 100644 --- a/ui/review.slint +++ b/ui/review.slint @@ -22,7 +22,7 @@ export component ReviewWidget inherits VerticalBox { spacing-horizontal: 16px; Slider { minimum: visible-time; - maximum: 24 * 3600; + maximum: tl.max-offset; value: offset; row: 0; colspan: 2; diff --git a/ui/timeline.slint b/ui/timeline.slint index c6069a0..66d571a 100644 --- a/ui/timeline.slint +++ b/ui/timeline.slint @@ -24,16 +24,24 @@ global TimeString { } export component Timeline inherits Rectangle { + callback new-day-started; + in-out property updating: true; in-out property<[TimelineEvent]> events: []; in-out property visible-time: 3600; property visible-offset: max(offset, visible-time); in-out property offset: 0; + out property max-offset: 24 * 3600 - 1; timer := Timer { interval: 1s; running: updating; triggered => { + if (offset >= max-offset) { + root.new-day-started(); + offset = 0; + return; + } offset += 1; } } @@ -70,10 +78,10 @@ export component Timeline inherits Rectangle { y: parent.height / 4; z: 1; width: event.finished ? - (event.duration) / visible-time * parent.width + min(real-x, 0): + min(parent.width - self.x, event.duration / visible-time * parent.width + min(real-x, 0)): parent.width - self.x; height: parent.height / 2; - visible: self.real-x + self.width > 0 && self.real-x < parent.width; + visible: self.width > 0 && self.real-x < parent.width; border-color: black; border-width: 1px; background: red;