commit 6a90ef4b75d5cf8fac94a11f6bd3e0c0455a4677
parent 8322ab86f1e79514395ff925a4021313484caa77
Author: Sylvia Ivory <git@sivory.net>
Date: Thu, 19 Jun 2025 21:18:57 -0700
Allow config to be saved and loaded
Diffstat:
6 files changed, 116 insertions(+), 10 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -165,6 +165,12 @@ dependencies = [
]
[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -986,12 +992,21 @@ dependencies = [
]
[[package]]
+name = "directories"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
+dependencies = [
+ "dirs-sys 0.5.0",
+]
+
+[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
- "dirs-sys",
+ "dirs-sys 0.3.7",
]
[[package]]
@@ -1001,11 +1016,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
- "redox_users",
+ "redox_users 0.4.6",
"winapi",
]
[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users 0.5.0",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1283,7 +1310,9 @@ dependencies = [
name = "fjordgard"
version = "0.1.0"
dependencies = [
+ "anyhow",
"chrono",
+ "directories",
"env_logger",
"fjordgard-unsplash",
"fjordgard-weather",
@@ -1291,6 +1320,8 @@ dependencies = [
"log",
"open",
"rfd",
+ "serde",
+ "serde_json",
"strum",
"tokio",
]
@@ -3185,6 +3216,12 @@ dependencies = [
]
[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
name = "orbclient"
version = "0.3.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3697,6 +3734,17 @@ dependencies = [
]
[[package]]
+name = "redox_users"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
+dependencies = [
+ "getrandom 0.2.16",
+ "libredox",
+ "thiserror 2.0.12",
+]
+
+[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
@@ -10,7 +10,9 @@ version = "0.1.0"
edition = "2024"
[dependencies]
+anyhow = "1.0.98"
chrono = "0.4.41"
+directories = "6.0.0"
env_logger = "0.11.8"
fjordgard-unsplash = { version = "0.1.0", path = "crates/unsplash" }
fjordgard-weather = { version = "0.1.0", path = "crates/weather" }
@@ -18,5 +20,7 @@ iced = { version = "0.13.1", features = ["tokio", "canvas", "image", "svg"] }
log = "0.4.27"
open = "5.3.2"
rfd = "0.15.3"
+serde = { version = "1.0.219", features = ["derive"] }
+serde_json = "1.0.140"
strum = { version = "0.27.1", features = ["derive"] }
tokio = { version = "1.45.1", features = ["full"] }
diff --git a/src/background.rs b/src/background.rs
@@ -3,8 +3,7 @@ use fjordgard_unsplash::{
model::{Collection, CollectionPhotos, CollectionPhotosOptions, Format, PhotoFetchOptions},
};
use iced::{
- Color, ContentFit, Element, Length, Point, Renderer, Size, Task, Theme,
- mouse,
+ Color, ContentFit, Element, Length, Point, Renderer, Size, Task, Theme, mouse,
widget::{button, canvas, container, image, row, stack, text},
};
use log::{debug, error};
diff --git a/src/config.rs b/src/config.rs
@@ -1,4 +1,12 @@
-#[derive(Debug, Clone, Copy, PartialEq, strum::Display, strum::VariantArray)]
+use std::fs;
+
+use anyhow::bail;
+use directories::ProjectDirs;
+use serde::{Deserialize, Serialize};
+
+#[derive(
+ Serialize, Deserialize, Debug, Clone, Copy, PartialEq, strum::Display, strum::VariantArray,
+)]
pub enum BackgroundMode {
Unsplash,
Solid,
@@ -24,14 +32,14 @@ impl BackgroundMode {
}
}
-#[derive(Clone)]
+#[derive(Serialize, Deserialize, Clone)]
pub struct Location {
pub longitude: f64,
pub latitude: f64,
pub name: Option<String>,
}
-#[derive(Clone)]
+#[derive(Serialize, Deserialize, Clone)]
pub struct Config {
pub time_format: String,
pub background_mode: BackgroundMode,
@@ -40,6 +48,39 @@ pub struct Config {
pub location: Option<Location>,
}
+impl Config {
+ pub fn load() -> anyhow::Result<Config> {
+ if let Some(dir) = ProjectDirs::from("net.sivory", "", "fjordgard") {
+ let config_file = dir.config_dir().join("config.json");
+
+ if !config_file.exists() {
+ return Ok(Config::default());
+ }
+
+ let data = fs::read_to_string(config_file)?;
+
+ Ok(serde_json::from_str(&data)?)
+ } else {
+ Ok(Config::default())
+ }
+ }
+
+ pub async fn save(&self) -> anyhow::Result<()> {
+ if let Some(dir) = ProjectDirs::from("net.sivory", "", "fjordgard") {
+ let config_dir = dir.config_dir();
+ tokio::fs::create_dir_all(config_dir).await?;
+
+ let contents = serde_json::to_string(self)?;
+
+ tokio::fs::write(config_dir.join("config.json"), contents).await?;
+
+ Ok(())
+ } else {
+ bail!("no config directory found")
+ }
+ }
+}
+
impl Default for Config {
fn default() -> Self {
Self {
diff --git a/src/main.rs b/src/main.rs
@@ -76,7 +76,7 @@ impl Fjordgard {
let main_window_size = settings.size;
let (id, open) = window::open(settings);
- let config = Config::default();
+ let config = Config::load().unwrap();
let format_string = config.time_format.clone();
let format_parsed = StrftimeItems::new_lenient(&format_string)
@@ -106,6 +106,7 @@ impl Fjordgard {
Task::batch([
open.map(|_| Message::MainWindowOpened),
task.map(Message::Background),
+ Task::done(Message::RequestForecastUpdate),
]),
)
}
diff --git a/src/settings.rs b/src/settings.rs
@@ -65,6 +65,7 @@ pub enum Message {
Save,
Committed,
+ Saved(Result<(), String>),
}
impl Settings {
@@ -217,7 +218,6 @@ impl Settings {
Task::none()
}
Message::Save => {
- // TODO; this should also commit to a file
let mut config = self.config.borrow_mut();
config.time_format = self.time_format.clone();
@@ -245,8 +245,21 @@ impl Settings {
}
}
- Task::done(Message::Committed)
+ let cloned = config.clone();
+
+ Task::batch([
+ Task::done(Message::Committed),
+ Task::future(async move { cloned.save().await })
+ .map(|r| Message::Saved(r.map_err(|e| e.to_string()))),
+ ])
}
+ Message::Saved(res) => match res {
+ Err(e) => {
+ error!("failed to save config: {e}");
+ Task::none()
+ }
+ Ok(()) => Task::none(),
+ },
_ => Task::none(),
}
}