Compare commits
No commits in common. "ba976d9e124079fe27ac43d8f4346131e1a24e0d" and "8df3893baa57d3b1817c3f78e27b0182ce8ddf6e" have entirely different histories.
ba976d9e12
...
8df3893baa
8 changed files with 21 additions and 220 deletions
|
@ -15,4 +15,4 @@ toml = "0.9.5"
|
||||||
slint-build = "1.12.1"
|
slint-build = "1.12.1"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = "s"
|
||||||
|
|
125
src/config.rs
125
src/config.rs
|
@ -2,138 +2,23 @@ use std::path::PathBuf;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct RawColors {
|
|
||||||
pub background: Option<u32>,
|
|
||||||
pub timeline: Option<u32>,
|
|
||||||
pub background_text: Option<u32>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Colors {
|
|
||||||
pub background: u32,
|
|
||||||
pub timeline: u32,
|
|
||||||
pub background_text: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Colors {
|
|
||||||
fn default() -> Self {
|
|
||||||
Colors {
|
|
||||||
background: 0xff_808080,
|
|
||||||
timeline: 0xff_a9a9a9,
|
|
||||||
background_text: 0xff_000000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RawColors> for Colors {
|
|
||||||
fn from(value: RawColors) -> Self {
|
|
||||||
let default_colors: Colors = Default::default();
|
|
||||||
Colors {
|
|
||||||
background: value.background.unwrap_or(default_colors.background),
|
|
||||||
timeline: value.timeline.unwrap_or(default_colors.timeline),
|
|
||||||
background_text: value.background_text.unwrap_or(default_colors.background_text),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct RawConfig {
|
|
||||||
pub log_path: Option<PathBuf>,
|
|
||||||
pub colors: Option<RawColors>,
|
|
||||||
pub event_colors: Option<Vec<u32>>,
|
|
||||||
pub text_colors: Option<Vec<u32>>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// directory, where config is located
|
/// directory, where config is located
|
||||||
|
#[serde(skip)]
|
||||||
pub conf_path: PathBuf,
|
pub conf_path: PathBuf,
|
||||||
pub log_path: PathBuf,
|
pub log_path: PathBuf
|
||||||
pub colors: Colors,
|
|
||||||
pub event_colors: Vec<u32>,
|
|
||||||
pub text_colors: Vec<u32>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Config {
|
|
||||||
fn default() -> Self {
|
|
||||||
let conf_path = PathBuf::new();
|
|
||||||
let colors: Colors = Default::default();
|
|
||||||
let event_colors: Vec<u32> = vec![
|
|
||||||
0xff_97f9f9,
|
|
||||||
0xff_a4def9,
|
|
||||||
0xff_c1e0f7,
|
|
||||||
0xff_cfbae1,
|
|
||||||
0xff_c59fc9,
|
|
||||||
0xff_4e3d42,
|
|
||||||
0xff_c9d5b5,
|
|
||||||
0xff_2d82b7,
|
|
||||||
0xff_556f44,
|
|
||||||
0xff_772e25,
|
|
||||||
0xff_c44536,
|
|
||||||
0xff_7c6a0a,
|
|
||||||
0xff_babd8d,
|
|
||||||
0xff_ffdac6,
|
|
||||||
0xff_fa9500,
|
|
||||||
0xff_eb6424
|
|
||||||
];
|
|
||||||
let text_colors: Vec<u32> = vec![
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xffffffff,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xffffffff,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000,
|
|
||||||
0xff000000
|
|
||||||
];
|
|
||||||
Config {
|
|
||||||
conf_path,
|
|
||||||
log_path: PathBuf::from("./logs"),
|
|
||||||
colors,
|
|
||||||
event_colors,
|
|
||||||
text_colors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RawConfig> for Config {
|
|
||||||
fn from(value: RawConfig) -> Self {
|
|
||||||
let default_config: Config = Default::default();
|
|
||||||
let colors: Colors = match value.colors {
|
|
||||||
Some(raw_colors) => raw_colors.into(),
|
|
||||||
None => default_config.colors.clone()
|
|
||||||
};
|
|
||||||
Config {
|
|
||||||
conf_path: default_config.conf_path,
|
|
||||||
log_path: value.log_path.unwrap_or(default_config.log_path),
|
|
||||||
colors,
|
|
||||||
event_colors: value.event_colors.unwrap_or(default_config.event_colors.clone()),
|
|
||||||
text_colors: value.text_colors.unwrap_or(default_config.text_colors.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new(conf_path: PathBuf) -> Self {
|
pub fn new(conf_path: PathBuf) -> Self {
|
||||||
let conf_dir: PathBuf = conf_path.parent().unwrap().into();
|
let conf_dir: PathBuf = conf_path.parent().unwrap().into();
|
||||||
Config {
|
Config { conf_path: conf_dir, log_path: PathBuf::from("./logs") }
|
||||||
conf_path: conf_dir,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(path: PathBuf) -> Self {
|
pub fn load(path: PathBuf) -> Self {
|
||||||
if let Ok(toml_string) = std::fs::read_to_string(path.clone()) {
|
if let Ok(toml_string) = std::fs::read_to_string(path.clone()) {
|
||||||
let conf = toml::from_str::<RawConfig>(&toml_string);
|
let conf = toml::from_str::<Self>(&toml_string);
|
||||||
if let Ok(raw_conf) = conf {
|
if let Ok(mut conf) = conf {
|
||||||
let mut conf: Config = raw_conf.into();
|
|
||||||
conf.conf_path = path.parent().unwrap().into();
|
conf.conf_path = path.parent().unwrap().into();
|
||||||
return conf;
|
return conf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use std::{hash::{DefaultHasher, Hash, Hasher}, path::PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
|
@ -13,10 +13,3 @@ pub fn load_config() -> Config {
|
||||||
}
|
}
|
||||||
Config::new(PathBuf::from("./config.toml"))
|
Config::new(PathBuf::from("./config.toml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get random-like color id in range 0..16 by computing string hash
|
|
||||||
pub fn color_id_from_name(name: String) -> i32 {
|
|
||||||
let mut s = DefaultHasher::new();
|
|
||||||
name.hash(&mut s);
|
|
||||||
let hash = s.finish();
|
|
||||||
(hash % 16) as i32 }
|
|
||||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
use std::{error::Error, rc::Rc, sync::{Arc, Mutex}};
|
use std::{error::Error, rc::Rc, sync::{Arc, Mutex}};
|
||||||
|
|
||||||
use aliveline::{color_id_from_name, config::Config, load_config, log::{Event, Log}};
|
use aliveline::{config::Config, load_config, log::{Event, Log}};
|
||||||
use chrono::{Datelike, Timelike};
|
use chrono::{Datelike, Timelike};
|
||||||
use slint::{Color, Model, ModelRc, SharedString, ToSharedString, VecModel, Weak};
|
use slint::{Model, ModelRc, SharedString, ToSharedString, VecModel, Weak};
|
||||||
use toml::value::{Date as TomlDate, Time};
|
use toml::value::{Date as TomlDate, Time};
|
||||||
|
|
||||||
slint::include_modules!();
|
slint::include_modules!();
|
||||||
|
@ -22,8 +22,7 @@ impl From<Event> for TimelineEvent {
|
||||||
start,
|
start,
|
||||||
duration: end - start,
|
duration: end - start,
|
||||||
label: event.name.to_shared_string(),
|
label: event.name.to_shared_string(),
|
||||||
finished: event.finished,
|
finished: event.finished
|
||||||
color_id: color_id_from_name(event.name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,26 +60,6 @@ fn load_log(ui_weak: Weak<AppWindow>, log: Arc<Mutex<Log>>) {
|
||||||
ui.set_in_progress(in_progress);
|
ui.set_in_progress(in_progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_colors(ui_weak: Weak<AppWindow>, config: Arc<Config>) {
|
|
||||||
let ui = ui_weak.unwrap();
|
|
||||||
let pal = ui.global::<Palette>();
|
|
||||||
pal.set_background(Color::from_argb_encoded(config.colors.background));
|
|
||||||
pal.set_timeline(Color::from_argb_encoded(config.colors.timeline));
|
|
||||||
pal.set_background_text(Color::from_argb_encoded(config.colors.background_text));
|
|
||||||
|
|
||||||
// This looks like war crime
|
|
||||||
let event_colors_rc: ModelRc<Color> = Rc::new(VecModel::from(
|
|
||||||
config.event_colors.iter()
|
|
||||||
.map(|value| Color::from_argb_encoded(*value)).collect::<Vec<Color>>()
|
|
||||||
)).into();
|
|
||||||
pal.set_event_colors(event_colors_rc);
|
|
||||||
let event_text_rc: ModelRc<Color> = Rc::new(VecModel::from(
|
|
||||||
config.text_colors.iter()
|
|
||||||
.map(|value| Color::from_argb_encoded(*value)).collect::<Vec<Color>>()
|
|
||||||
)).into();
|
|
||||||
pal.set_event_text(event_text_rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let ui = AppWindow::new()?;
|
let ui = AppWindow::new()?;
|
||||||
|
|
||||||
|
@ -100,10 +79,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let log = writing_log.clone();
|
let log = writing_log.clone();
|
||||||
load_log(ui_weak, log);
|
load_log(ui_weak, log);
|
||||||
|
|
||||||
let ui_weak = ui.as_weak();
|
|
||||||
let config_arc = config.clone();
|
|
||||||
load_colors(ui_weak, config_arc);
|
|
||||||
|
|
||||||
ui.invoke_update_record_offset(offset as i32);
|
ui.invoke_update_record_offset(offset as i32);
|
||||||
|
|
||||||
ui.on_fetch_log({
|
ui.on_fetch_log({
|
||||||
|
@ -168,9 +143,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let event = TimelineEvent {
|
let event = TimelineEvent {
|
||||||
duration: 0,
|
duration: 0,
|
||||||
finished: false,
|
finished: false,
|
||||||
label: event_name.clone(),
|
label: event_name,
|
||||||
start: offset,
|
start: offset
|
||||||
color_id: color_id_from_name(event_name.to_string())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -203,9 +177,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let new_event = TimelineEvent {
|
let new_event = TimelineEvent {
|
||||||
duration: offset - event.start,
|
duration: offset - event.start,
|
||||||
finished: true,
|
finished: true,
|
||||||
label: event.label.clone(),
|
label: event.label,
|
||||||
start: event.start,
|
start: event.start
|
||||||
color_id: color_id_from_name(event.label.to_string())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -242,7 +215,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let maybe_unfinished_event = log_guard.events.iter().find(|event| !event.finished);
|
let maybe_unfinished_event = log_guard.events.iter().find(|event| !event.finished);
|
||||||
match maybe_unfinished_event {
|
match maybe_unfinished_event {
|
||||||
Some(unfinished_event) => Some(Event::new(unfinished_event.name.clone(), 0, 0, false)),
|
Some(unfinished_event) => Some(Event::new(unfinished_event.name.clone(), 0, 0, false)),
|
||||||
_ => None
|
None => None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { TabWidget } from "std-widgets.slint";
|
||||||
import { RecordWidget } from "record.slint";
|
import { RecordWidget } from "record.slint";
|
||||||
import { ReviewWidget } from "review.slint";
|
import { ReviewWidget } from "review.slint";
|
||||||
import { TimelineEvent } from "timeline.slint";
|
import { TimelineEvent } from "timeline.slint";
|
||||||
export { Palette } from "theme.slint";
|
|
||||||
|
|
||||||
export component AppWindow inherits Window {
|
export component AppWindow inherits Window {
|
||||||
callback start-new-event <=> record.start-new-event;
|
callback start-new-event <=> record.start-new-event;
|
||||||
|
@ -32,6 +31,7 @@ export component AppWindow inherits Window {
|
||||||
property<[string]> combo-spans: ["1 Hour", "4 Hours", "8 Hours", "24 Hours"];
|
property<[string]> combo-spans: ["1 Hour", "4 Hours", "8 Hours", "24 Hours"];
|
||||||
|
|
||||||
title: "Aliveline";
|
title: "Aliveline";
|
||||||
|
|
||||||
TabWidget {
|
TabWidget {
|
||||||
Tab {
|
Tab {
|
||||||
title: "Record";
|
title: "Record";
|
||||||
|
|
|
@ -16,6 +16,7 @@ export component RecordWidget inherits VerticalBox {
|
||||||
property<string> event-name: "";
|
property<string> event-name: "";
|
||||||
property<bool> minimized: false;
|
property<bool> minimized: false;
|
||||||
property<int> combo-index: 0;
|
property<int> combo-index: 0;
|
||||||
|
|
||||||
tl := Timeline {
|
tl := Timeline {
|
||||||
preferred-height: 100%;
|
preferred-height: 100%;
|
||||||
updating: true;
|
updating: true;
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
export global Palette {
|
|
||||||
in-out property<color> background: gray;
|
|
||||||
in-out property<color> timeline: darkgray;
|
|
||||||
in-out property<color> background-text: black;
|
|
||||||
// Note: these colors were almost randomly picked
|
|
||||||
in-out property<[color]> event-colors: [
|
|
||||||
#97f9f9,
|
|
||||||
#a4def9,
|
|
||||||
#c1e0f7,
|
|
||||||
#cfbae1,
|
|
||||||
#c59fc9,
|
|
||||||
#4e3d42,
|
|
||||||
#c9d5b5,
|
|
||||||
#2d82b7,
|
|
||||||
#556f44,
|
|
||||||
#772e25,
|
|
||||||
#c44536,
|
|
||||||
#7c6a0a,
|
|
||||||
#babd8d,
|
|
||||||
#ffdac6,
|
|
||||||
#fa9500,
|
|
||||||
#eb6424
|
|
||||||
];
|
|
||||||
|
|
||||||
in-out property <[color]> event-text: [
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#ffffff,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#ffffff,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000,
|
|
||||||
#000000
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,11 +1,8 @@
|
||||||
import { Palette } from "theme.slint";
|
|
||||||
|
|
||||||
export struct TimelineEvent {
|
export struct TimelineEvent {
|
||||||
start: int,
|
start: int,
|
||||||
duration: int,
|
duration: int,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
label: string,
|
label: string
|
||||||
color-id: int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global TimeString {
|
global TimeString {
|
||||||
|
@ -29,7 +26,6 @@ global TimeString {
|
||||||
export component Timeline inherits Rectangle {
|
export component Timeline inherits Rectangle {
|
||||||
callback new-day-started;
|
callback new-day-started;
|
||||||
callback clicked <=> ta.clicked;
|
callback clicked <=> ta.clicked;
|
||||||
background: Palette.background;
|
|
||||||
|
|
||||||
in-out property<bool> updating: true;
|
in-out property<bool> updating: true;
|
||||||
in-out property<[TimelineEvent]> events: [];
|
in-out property<[TimelineEvent]> events: [];
|
||||||
|
@ -56,6 +52,7 @@ export component Timeline inherits Rectangle {
|
||||||
preferred-height: 100%;
|
preferred-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
background: gray;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: black;
|
border-color: black;
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -66,21 +63,19 @@ export component Timeline inherits Rectangle {
|
||||||
height: parent.height / 2;
|
height: parent.height / 2;
|
||||||
border-color: black;
|
border-color: black;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
background: Palette.timeline;
|
background: purple;
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
x: 0;
|
x: 0;
|
||||||
y: parent.height - self.height;
|
y: parent.height - self.height;
|
||||||
text: TimeString.from(visible-offset - visible-time);
|
text: TimeString.from(visible-offset - visible-time);
|
||||||
color: Palette.background-text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
x: parent.width - self.width;
|
x: parent.width - self.width;
|
||||||
y: parent.height - self.height;
|
y: parent.height - self.height;
|
||||||
text: TimeString.from(visible-offset);
|
text: TimeString.from(visible-offset);
|
||||||
color: Palette.background-text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for event in events: timeline-event := Rectangle {
|
for event in events: timeline-event := Rectangle {
|
||||||
|
@ -96,14 +91,13 @@ export component Timeline inherits Rectangle {
|
||||||
visible: self.width > 0 && self.real-x < parent.width;
|
visible: self.width > 0 && self.real-x < parent.width;
|
||||||
border-color: black;
|
border-color: black;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
background: Palette.event-colors[event.color-id];
|
background: red;
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
x: 0;
|
x: 0;
|
||||||
y: -self.height;
|
y: -self.height;
|
||||||
text: event.label;
|
text: event.label;
|
||||||
visible: timeline-event.visible;
|
visible: timeline-event.visible;
|
||||||
color: Palette.background-text;
|
|
||||||
}
|
}
|
||||||
start-txt := Text {
|
start-txt := Text {
|
||||||
x: 0;
|
x: 0;
|
||||||
|
@ -114,7 +108,6 @@ export component Timeline inherits Rectangle {
|
||||||
visible: timeline-event.visible &&
|
visible: timeline-event.visible &&
|
||||||
(self.width * 2 < timeline-event.width ||
|
(self.width * 2 < timeline-event.width ||
|
||||||
(!end-txt.visible && self.width < timeline-event.width));
|
(!end-txt.visible && self.width < timeline-event.width));
|
||||||
color: Palette.event-text[event.color-id];
|
|
||||||
}
|
}
|
||||||
end-txt := Text {
|
end-txt := Text {
|
||||||
x: timeline-event.width - self.width;
|
x: timeline-event.width - self.width;
|
||||||
|
@ -123,7 +116,6 @@ export component Timeline inherits Rectangle {
|
||||||
TimeString.from(event.start + event.duration) :
|
TimeString.from(event.start + event.duration) :
|
||||||
TimeString.from(visible-offset);
|
TimeString.from(visible-offset);
|
||||||
visible: timeline-event.visible && timeline-event.width - self.width * 2 > 0;
|
visible: timeline-event.visible && timeline-event.width - self.width * 2 > 0;
|
||||||
color: Palette.event-text[event.color-id];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@children
|
@children
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue