From 2bb173f2e32a21907fce684620e6d40596e4e7fe Mon Sep 17 00:00:00 2001 From: EternalShade3D Date: Fri, 16 Oct 2026 17:12:53 +0100 Subject: [PATCH] feat(settings): keep the settings inside a portable suite portable.txt puts ArtCraftLauncherData next to the exe, but the settings still went to eframe's storage folder in the user's profile, so a suite carried on a stick lost its settings on another computer. path() now returns the suite's own data folder when a portable suite is detected, and main.rs passes it as persistence_path so eframe writes the window state to the same file. Nothing changes for a normal install. --- apps/artcraft-launcher/src/main.rs | 10 +++++++++- apps/artcraft-launcher/src/settings_file.rs | 19 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/artcraft-launcher/src/main.rs b/apps/artcraft-launcher/src/main.rs index e6b3547a..7220bd6b 100644 --- a/apps/artcraft-launcher/src/main.rs +++ b/apps/artcraft-launcher/src/main.rs @@ -154,7 +154,15 @@ fn native_options(hidden: bool) -> eframe::NativeOptions { } else if let Some(icon) = icon { viewport = viewport.with_icon(icon); } - eframe::NativeOptions { viewport, persist_window: true, wgpu_options: wgpu_options(), ..Default::default() } + // Persistence goes to the same file `settings_file` uses, so a portable suite keeps its + // settings and window state inside itself instead of in the user's profile. + eframe::NativeOptions { + viewport, + persist_window: true, + persistence_path: settings_file::path(APP_ID), + wgpu_options: wgpu_options(), + ..Default::default() + } } /// wgpu's backend list. On Windows that is Direct3D 12 with GL as the fallback, not Vulkan: diff --git a/apps/artcraft-launcher/src/settings_file.rs b/apps/artcraft-launcher/src/settings_file.rs index d09acde2..2e68741b 100644 --- a/apps/artcraft-launcher/src/settings_file.rs +++ b/apps/artcraft-launcher/src/settings_file.rs @@ -8,9 +8,18 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -/// Where eframe keeps its state for `app_id`, as it picks it for a window with that app id. +/// Where the settings file is. In portable mode it is inside `ArtCraftLauncherData`, so a suite +/// carried on a stick keeps its settings when it is plugged into another computer. Without +/// `portable.txt` it is eframe's own folder, which is in the user's profile and cannot travel. pub fn path(app_id: &str) -> Option { - eframe::storage_dir(app_id).map(|dir| dir.join("app.ron")) + artcraft_launcher_native::paths::portable_root() + .map(|root| portable_settings(&root)) + .or_else(|| eframe::storage_dir(app_id).map(|dir| dir.join("app.ron"))) +} + +/// The settings file inside a portable suite: the same `data` folder `Paths` already uses. +fn portable_settings(root: &Path) -> PathBuf { + root.join("data").join("app.ron") } /// The value stored under `key`, if the file has one that still reads. @@ -91,6 +100,12 @@ mod tests { } } + #[test] + fn a_portable_suite_keeps_its_settings_inside_itself() { + let root = PathBuf::from("E:\\Suite\\ArtCraftLauncherData"); + assert_eq!(portable_settings(&root), PathBuf::from("E:\\Suite\\ArtCraftLauncherData\\data\\app.ron")); + } + #[test] fn settings_saved_with_no_file_read_back() { let dir = Scratch::new("settings-round-trip");