// Prevent console window in addition to Slint window in Windows release builds when, e.g., starting the app via file manager. Ignored on other platforms. #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 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 toml::value::{Date as TomlDate, Time}; slint::include_modules!(); impl From for TimelineEvent { fn from(event: Event) -> Self { let start = (event.start.hour as i32) * 3600 + (event.start.minute as i32) * 60 + (event.start.second as i32); let end = (event.end.hour as i32) * 3600 + (event.end.minute as i32) * 60 + (event.end.second as i32); TimelineEvent { start, duration: end - start, label: event.name.to_shared_string(), finished: event.finished } } } impl From for Event { fn from(event: TimelineEvent) -> Self { let start = Time { hour: (event.start / 3600) as u8, minute: ((event.start % 3600) / 60) as u8, second: (event.start % 60) as u8, nanosecond: 0 }; let endsecs = event.start + event.duration; let end = Time { hour: (endsecs / 3600) as u8, minute: ((endsecs % 3600) / 60) as u8, second: (endsecs % 60) as u8, nanosecond: 0 }; Event { start, end, name: event.label.to_string(), finished: event.finished } } } fn main() -> Result<(), Box> { let ui = AppWindow::new()?; let now = chrono::Local::now(); let offset = now.hour() * 3600 + now.minute() * 60 + now.second(); let date: TomlDate = TomlDate { day: now.day() as u8, month: now.month() as u8, year: now.year() as u16 }; let config: Arc = Arc::new(load_config()); let writing_log: Arc> = Arc::new(Mutex::new(Log::load_from(&config, date))); { println!("Log: {:?}", writing_log.lock().unwrap().events); let ui_weak = ui.as_weak(); let log = writing_log.clone(); (move || { println!("c"); 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(); println!("get: {:?}", model); ui.set_record_events(model); ui.set_in_progress(in_progress); })() } ui.invoke_update_record_offset(offset as i32); ui.invoke_load_log(); ui.invoke_another_call(); ui.on_save_log({ let config = config.clone(); let log = writing_log.clone(); move || { let log_guard = log.lock().expect("Log shouldn't be used twice"); if let Err(error) = (*log_guard).save(&config) { eprintln!("Error occured while saving log: {error}"); } } }); ui.on_another_call({ println!("outside move"); move || { println!("inside move"); } }); ui.on_update_record_visible_time({ let ui_weak = ui.as_weak(); move |hours_string: SharedString| { let ui = ui_weak.unwrap(); let hours = hours_string.split(' ') .next() .map(|h| h.parse::().unwrap()) .unwrap(); ui.set_record_visible_time(hours * 3600); } }); ui.on_start_new_event({ let ui_weak = ui.as_weak(); let log = writing_log.clone(); move |event_name: SharedString| { let ui = ui_weak.unwrap(); let events_rc = ui.get_record_events(); let events = events_rc.as_any() .downcast_ref::>() .unwrap(); let offset = ui.get_record_offset(); let event = TimelineEvent { duration: 0, finished: false, label: event_name, start: offset }; { let mut log_guard = log.lock().expect("Log shouldn't be used twice"); (*log_guard).events.push(Event::from(event.clone())); } ui.invoke_save_log(); events.push(event); } }); ui.on_stop_event({ let ui_weak = ui.as_weak(); let log = writing_log.clone(); move || { let ui = ui_weak.unwrap(); let events_rc = ui.get_record_events(); let events = events_rc.as_any() .downcast_ref::>().unwrap(); let offset = ui.get_record_offset(); let event_id = events.iter() .position(|data| !data.finished) .unwrap(); let event = events.row_data(event_id) .expect("stop-event called without unfinished events"); let new_event = TimelineEvent { duration: offset - event.start, finished: true, label: event.label, start: event.start }; { 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); } ui.invoke_save_log(); events.set_row_data(event_id, new_event); } }); ui.on_chain_event({ let ui_weak = ui.as_weak(); move |event_name: SharedString| { let ui = ui_weak.unwrap(); ui.invoke_stop_event(); ui.invoke_start_new_event(event_name); } }); ui.run()?; Ok(()) }