Options: remember the user name between runs (#32) (#35)

Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
This commit is contained in:
MarekSpodBiedry
2026-10-09 09:02:16 -04:00
committed by GitHub
co-authored by Brandon Thomas
parent f2a8420679
commit 8588fb908a
3 changed files with 53 additions and 4 deletions
+2 -3
View File
@@ -57,8 +57,7 @@ fn load_prefs(app: &mut WordApp) {
&& let Ok(bytes) = std::fs::read(&p)
&& let Ok(ui) = serde_json::from_slice::<UiState>(&bytes)
{
app.ui = ui;
app.ui.backstage = false;
app.apply_prefs(ui);
}
}
@@ -70,7 +69,7 @@ fn save_prefs(app: &WordApp) {
if let Some(dir) = p.parent() {
let _ = std::fs::create_dir_all(dir);
}
if let Ok(bytes) = serde_json::to_vec_pretty(&app.ui) {
if let Ok(bytes) = serde_json::to_vec_pretty(&app.prefs()) {
let _ = std::fs::write(&p, bytes);
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ pub fn inspect(app: &mut WordApp, ctx: &egui::Context) -> Value {
let r = ctx.content_rect();
let caret = crate::canvas::caret_screen(app).map(|(p, h)| json!({"x": p.x, "y": p.y, "h": h}));
json!({
"ui": app.ui,
"ui": app.prefs(),
"view": app.session.view,
"dialog": app.dialog.as_ref().map(|d| serde_json::to_value(d).unwrap_or_default()),
"window": [r.width(), r.height()],
+50
View File
@@ -55,6 +55,8 @@ pub struct UiState {
pub dark: bool,
pub nav_tab: String,
pub show_discord: bool,
/// User name (File › Options) for comments and tracked changes; empty keeps the default.
pub author: String,
}
impl Default for UiState {
@@ -68,6 +70,7 @@ impl Default for UiState {
dark: false,
nav_tab: "headings".into(),
show_discord: true,
author: String::new(),
}
}
}
@@ -130,6 +133,24 @@ impl WordApp {
self
}
/// Preferences to save between runs: the UI state plus the current user name.
pub fn prefs(&self) -> UiState {
let mut ui = self.ui.clone();
ui.author = self.session.author.clone();
ui
}
/// Restore preferences saved by [`WordApp::prefs`].
pub fn apply_prefs(&mut self, ui: UiState) {
self.ui = ui;
self.ui.backstage = false;
// The session owns the name from here on; `prefs` copies it back when saving.
let author = std::mem::take(&mut self.ui.author);
if !author.trim().is_empty() {
self.session.author = author;
}
}
/// Run a command; UI-level commands (`ui.*`) are handled here, the rest by the engine.
pub fn run(&mut self, id: &str, params: Value) -> Result<Value, String> {
if let Some(r) = self.ui_command(id, &params) {
@@ -513,4 +534,33 @@ mod tests {
frame(Vec::new());
assert_eq!(ctx.zoom_factor(), 1.0);
}
fn app() -> WordApp {
WordApp::new(Session::new(wordcraft_doc::Document::new()), Services::default())
}
#[test]
fn user_name_survives_restart() {
let mut first = app();
first.run("file.setAuthor", json!({"name": "Ada Lovelace"})).unwrap();
let saved = serde_json::to_vec(&first.prefs()).unwrap();
let mut second = app();
second.apply_prefs(serde_json::from_slice(&saved).unwrap());
assert_eq!(second.session.author, "Ada Lovelace");
// A later rename is what gets saved next, not the name loaded at startup.
second.run("file.setAuthor", json!({"name": "Grace Hopper"})).unwrap();
assert_eq!(second.prefs().author, "Grace Hopper");
}
#[test]
fn prefs_without_user_name_keep_default() {
let mut a = app();
let default = a.session.author.clone();
a.apply_prefs(serde_json::from_str(r#"{"dark": true, "backstage": true}"#).unwrap());
assert_eq!(a.session.author, default);
assert!(a.ui.dark);
assert!(!a.ui.backstage);
}
}