Add a state file to persist data

This commit is contained in:
Quentin Boyer 2023-11-11 23:07:23 +01:00
parent e9058c6b27
commit 066bcb5555
3 changed files with 187 additions and 19 deletions

104
Cargo.lock generated
View file

@ -90,6 +90,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]] [[package]]
name = "approx" name = "approx"
version = "0.5.1" version = "0.5.1"
@ -428,6 +434,27 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "dispatch" name = "dispatch"
version = "0.2.0" version = "0.2.0"
@ -679,9 +706,13 @@ checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945"
name = "glaurung" name = "glaurung"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"directories",
"iced", "iced",
"iced_aw", "iced_aw",
"itertools", "itertools",
"serde",
"serde_json",
] ]
[[package]] [[package]]
@ -1055,6 +1086,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]] [[package]]
name = "jni-sys" name = "jni-sys"
version = "0.3.0" version = "0.3.0"
@ -1137,6 +1174,17 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "libredox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.4.1",
"libc",
"redox_syscall 0.4.1",
]
[[package]] [[package]]
name = "libredox" name = "libredox"
version = "0.0.2" version = "0.0.2"
@ -1517,13 +1565,19 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]] [[package]]
name = "orbclient" name = "orbclient"
version = "0.3.47" version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166"
dependencies = [ dependencies = [
"libredox", "libredox 0.0.2",
] ]
[[package]] [[package]]
@ -1857,6 +1911,17 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "redox_users"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
dependencies = [
"getrandom",
"libredox 0.0.1",
"thiserror",
]
[[package]] [[package]]
name = "renderdoc-sys" name = "renderdoc-sys"
version = "1.0.0" version = "1.0.0"
@ -1892,6 +1957,12 @@ dependencies = [
"unicode-script", "unicode-script",
] ]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]] [[package]]
name = "scoped-tls" name = "scoped-tls"
version = "1.0.1" version = "1.0.1"
@ -1917,6 +1988,37 @@ dependencies = [
"tiny-skia 0.8.4", "tiny-skia 0.8.4",
] ]
[[package]]
name = "serde"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "serde_json"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.7" version = "0.3.7"

View file

@ -5,9 +5,13 @@ authors = ["traxys <quentin@familleboyer.net>"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.75"
directories = "5.0.1"
iced = { version = "0.10.0", features = ["lazy"] } iced = { version = "0.10.0", features = ["lazy"] }
iced_aw = { version = "0.7.0", default-features = false, features = [ iced_aw = { version = "0.7.0", default-features = false, features = [
"modal", "modal",
"card", "card",
] } ] }
itertools = "0.11.0" itertools = "0.11.0"
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108"

View file

@ -1,25 +1,23 @@
use std::collections::BTreeMap; use std::{
collections::BTreeMap,
fs::{File, OpenOptions},
io::BufReader,
path::PathBuf,
};
use anyhow::anyhow;
use directories::ProjectDirs;
use iced::{ use iced::{
font, font, subscription,
widget::{button, column, component, horizontal_rule, row, text, text_input}, widget::{button, column, component, horizontal_rule, row, text, text_input},
Application, Command, Renderer, Settings, Theme, window, Application, Command, Event, Renderer, Settings, Theme,
}; };
use iced_aw::{card, modal}; use iced_aw::{card, modal};
use itertools::Itertools; use itertools::Itertools;
use serde::{Deserialize, Serialize};
type Element<'a> = iced::Element<'a, Message>; type Element<'a> = iced::Element<'a, Message>;
#[derive(Clone, Debug)]
enum Message {
AddRecurring(String, f64),
FontLoaded(Result<(), font::Error>),
}
struct Glaurung {
recurring: BTreeMap<String, f64>,
}
struct AddRecurring<F> { struct AddRecurring<F> {
on_submit: F, on_submit: F,
} }
@ -226,16 +224,45 @@ where
} }
} }
#[derive(Clone, Debug)]
enum Message {
Event(Event),
AddRecurring(String, f64),
FontLoaded(Result<(), font::Error>),
}
struct Glaurung {
recurring: BTreeMap<String, f64>,
save_file: File,
}
#[derive(Serialize, Deserialize, Default)]
struct SaveFile {
recurring: BTreeMap<String, f64>,
}
#[derive(Default)]
struct AppConfig {
save: SaveFile,
save_file: PathBuf,
}
impl Application for Glaurung { impl Application for Glaurung {
type Message = Message; type Message = Message;
type Theme = Theme; type Theme = Theme;
type Executor = iced::executor::Default; type Executor = iced::executor::Default;
type Flags = (); type Flags = AppConfig;
fn new(_flags: Self::Flags) -> (Self, Command<Message>) { fn new(config: Self::Flags) -> (Self, Command<Message>) {
( (
Self { Self {
recurring: BTreeMap::new(), recurring: config.save.recurring,
save_file: OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(config.save_file)
.expect("Can't open data file"),
}, },
Command::batch(vec![ Command::batch(vec![
font::load(iced_aw::graphics::icons::ICON_FONT_BYTES).map(Message::FontLoaded) font::load(iced_aw::graphics::icons::ICON_FONT_BYTES).map(Message::FontLoaded)
@ -247,12 +274,29 @@ impl Application for Glaurung {
"Glaurung - Account Manager".into() "Glaurung - Account Manager".into()
} }
fn subscription(&self) -> iced::Subscription<Self::Message> {
subscription::events().map(Message::Event)
}
fn update(&mut self, message: Self::Message) -> Command<Message> { fn update(&mut self, message: Self::Message) -> Command<Message> {
match message { match message {
Message::AddRecurring(name, value) => { Message::AddRecurring(name, value) => {
self.recurring.insert(name, value); self.recurring.insert(name, value);
} }
Message::FontLoaded(r) => r.expect("could not load font"), Message::FontLoaded(r) => r.expect("could not load font"),
Message::Event(ev) => {
if let Event::Window(window::Event::CloseRequested) = ev {
serde_json::to_writer(
&mut self.save_file,
&SaveFile {
recurring: std::mem::take(&mut self.recurring),
},
)
.expect("could not write save file");
return window::close();
}
}
} }
Command::none() Command::none()
@ -275,6 +319,24 @@ impl Application for Glaurung {
} }
} }
fn main() -> iced::Result { fn main() -> anyhow::Result<()> {
Glaurung::run(Settings::default()) let project_dir = ProjectDirs::from("net", "traxys", "glaurung").ok_or(anyhow!(""))?;
let state_dir = project_dir
.state_dir()
.ok_or(anyhow!("No state directory"))?;
std::fs::create_dir_all(state_dir)?;
let save_file = state_dir.join("data.json");
let save = match save_file.exists() {
false => Default::default(),
true => serde_json::from_reader(BufReader::new(File::open(&save_file)?))?,
};
let mut settings = Settings::with_flags(AppConfig { save, save_file });
settings.exit_on_close_request = false;
Glaurung::run(settings)?;
Ok(())
} }