diff --git a/apps/figcraft/src/main.rs b/apps/figcraft/src/main.rs index 1bba81e8..00856c5d 100644 --- a/apps/figcraft/src/main.rs +++ b/apps/figcraft/src/main.rs @@ -193,10 +193,8 @@ fn main() -> eframe::Result { // default, never a build from source unless asked). session.live.links = figcraft_collab_net::links::system(); session.invite_links_startup(); - // A first run (no settings kept yet, nothing to open) starts on the home screen, with its - // tips and templates; later runs start in a new file. let first_run = svc.prefs.is_none() && args.join.is_none(); - if session.docs.is_empty() && !first_run { + if session.docs.is_empty() && opens_new_file(first_run, session.prefs.start_on_home, port.is_some()) { let _ = session.execute("file.new", &json!({})); } // The interface language from the first frame on, and for the message when the window can't @@ -268,6 +266,14 @@ fn main() -> eframe::Result { result } +/// With nothing to open, whether the window starts in a new file rather than on the home screen. +/// A first run (no settings kept yet) shows the home screen's tips and templates, and later runs +/// start in a new file unless the preference asks for Home, which `--control` overrides: its +/// callers expect a document to act on. +fn opens_new_file(first_run: bool, start_on_home: bool, control: bool) -> bool { + !first_run && (!start_on_home || control) +} + fn desktop_title_bar() -> figcraft_ui_egui::TitleBar { use figcraft_ui_egui::TitleBar; if cfg!(target_os = "macos") { TitleBar::Inset } else { TitleBar::Custom } @@ -292,3 +298,16 @@ mod linux_window_tests { assert_eq!(viewport.decorations, Some(false)); } } + +#[cfg(test)] +mod start_tests { + use super::opens_new_file; + + #[test] + fn the_home_preference_starts_on_home_except_for_control_callers() { + assert!(opens_new_file(false, false, false), "a new file by default"); + assert!(!opens_new_file(false, true, false), "Home when the preference asks"); + assert!(opens_new_file(false, true, true), "--control still starts with a document"); + assert!(!opens_new_file(true, false, false), "a first run shows the home screen"); + } +} diff --git a/crates/engine/src/cmd/view.rs b/crates/engine/src/cmd/view.rs index eb573c57..154cab00 100644 --- a/crates/engine/src/cmd/view.rs +++ b/crates/engine/src/cmd/view.rs @@ -388,6 +388,7 @@ pub fn specs() -> Vec { } ), spec!("pref.autoSave", "Save files automatically", "{on?}", false, |s, p| pref(s, p, |x| &mut x.auto_save)), + spec!("pref.startOnHome", "Start on the Home screen", "{on?}", false, |s, p| pref(s, p, |x| &mut x.start_on_home)), spec!("pref.nudge", "Nudge amount", "{small?, big?}", false, |s, p| { s.prefs.nudge_small = num(p, "small").unwrap_or(s.prefs.nudge_small).clamp(0.01, 1000.0); s.prefs.nudge_big = num(p, "big").unwrap_or(s.prefs.nudge_big).clamp(0.01, 10000.0); @@ -539,3 +540,24 @@ pub fn specs() -> Vec { #[allow(dead_code)] fn unused(_: NodeId) {} + +#[cfg(test)] +mod start_on_home_tests { + use serde_json::json; + + use crate::Session; + + #[test] + fn start_on_home_is_a_preference_that_persists() { + let mut s = Session::new(); + assert!(!s.prefs.start_on_home); + assert_eq!(s.execute("pref.startOnHome", &json!({})).unwrap()["on"], true); + assert!(s.prefs.start_on_home); + // Saved with the other preferences and read back; older settings files without it read as off. + let saved: crate::Prefs = serde_json::from_value(serde_json::to_value(&s.prefs).unwrap()).unwrap(); + assert!(saved.start_on_home); + assert_eq!(s.execute("pref.startOnHome", &json!({"on": false})).unwrap()["on"], false); + let old: crate::Prefs = serde_json::from_value(json!({"theme": "dark"})).unwrap(); + assert!(!old.start_on_home); + } +} diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index df533b24..f52d23e8 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -655,6 +655,8 @@ pub struct Prefs { /// Files that have a path are saved by themselves a few seconds after they change (the app's /// timer; off: only File ▸ Save writes them). pub auto_save: bool, + /// The desktop app starts on the Home screen instead of in a new file. + pub start_on_home: bool, /// `figcraft://` invite links open this app (`collab.registerLinks`); `None`: on for installed /// builds, off for development builds. pub invite_links: Option, @@ -722,6 +724,7 @@ impl Default for Prefs { reduce_motion: false, ui_scale: 1.0, auto_save: false, + start_on_home: false, invite_links: None, plugins: Vec::new(), plugin_settings: BTreeMap::new(), diff --git a/crates/ui-egui/locales/de.toml b/crates/ui-egui/locales/de.toml index ed0ea698..5c0a2bb3 100644 --- a/crates/ui-egui/locales/de.toml +++ b/crates/ui-egui/locales/de.toml @@ -1225,6 +1225,7 @@ status = "draft — needs native review" "Start ascending from / stop descending at" = "Aufwärts zählen ab / abwärts zählen bis" "Start from a blank canvas" = "Mit einer leeren Arbeitsfläche beginnen" "Start on path" = "Anfang auf dem Pfad" +"Start on the Home screen" = "Mit Start beginnen" "Start point" = "Startpunkt" "Start sharing" = "Teilen starten" "Starting to share…" = "Teilen wird gestartet…" @@ -1935,6 +1936,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "Bewegung reduzieren" "pref.renameDuplicates" = "Duplizierte Ebenen umbenennen" "pref.showDimensions" = "Abmessungen an Objekten anzeigen" +"pref.startOnHome" = "Mit Start beginnen" "pref.userName" = "Ihr Name in Kommentaren" "proto.action.add" = "Prototyp-Aktion hinzufügen" "proto.action.move" = "Prototyp-Aktion neu anordnen" diff --git a/crates/ui-egui/locales/en.toml b/crates/ui-egui/locales/en.toml index f28cfe60..fd0f2dbf 100644 --- a/crates/ui-egui/locales/en.toml +++ b/crates/ui-egui/locales/en.toml @@ -1301,6 +1301,7 @@ name = "English" "Start from a blank canvas" = "Start from a blank canvas" "Start from a template" = "Start from a template" "Start on path" = "Start on path" +"Start on the Home screen" = "Start on the Home screen" "Start point" = "Start point" "Start sharing" = "Start sharing" "Start sharing with the Share button, then pass on the code it gives" = "Start sharing with the Share button, then pass on the code it gives" diff --git a/crates/ui-egui/locales/es.toml b/crates/ui-egui/locales/es.toml index e78f9e09..3445a4c2 100644 --- a/crates/ui-egui/locales/es.toml +++ b/crates/ui-egui/locales/es.toml @@ -1302,6 +1302,7 @@ status = "draft — needs native review" "Start from a blank canvas" = "Empieza con un lienzo en blanco" "Start from a template" = "Empieza con una plantilla" "Start on path" = "Inicio en el trazado" +"Start on the Home screen" = "Empezar en Inicio" "Start point" = "Punto inicial" "Start sharing" = "Empezar a compartir" "Start sharing with the Share button, then pass on the code it gives" = "Empieza a compartir con el botón Compartir y pasa el código que te da" @@ -2040,6 +2041,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "Reducir movimiento" "pref.renameDuplicates" = "Renombrar capas duplicadas" "pref.showDimensions" = "Mostrar dimensiones en los objetos" +"pref.startOnHome" = "Empezar en Inicio" "pref.uiScale" = "Tamaño de la interfaz" "pref.userName" = "Tu nombre en los comentarios" "proto.action.add" = "Añadir acción de prototipo" diff --git a/crates/ui-egui/locales/fi.toml b/crates/ui-egui/locales/fi.toml index f49b17ee..837d7839 100644 --- a/crates/ui-egui/locales/fi.toml +++ b/crates/ui-egui/locales/fi.toml @@ -1301,6 +1301,7 @@ status = "draft — needs native review" "Start from a blank canvas" = "Aloita tyhjältä piirtoalueelta" "Start from a template" = "Aloita mallista" "Start on path" = "Aloituskohta polulla" +"Start on the Home screen" = "Aloita Aloitus-näkymästä" "Start point" = "Alkupiste" "Start sharing" = "Aloita jakaminen" "Start sharing with the Share button, then pass on the code it gives" = "Aloita jakaminen Jaa-painikkeella ja välitä sen antama koodi" @@ -2036,6 +2037,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "Vähennä liikettä" "pref.renameDuplicates" = "Nimeä monistetut tasot uudelleen" "pref.showDimensions" = "Näytä objektien mitat" +"pref.startOnHome" = "Aloita Aloitus-näkymästä" "pref.userName" = "Nimesi kommenteissa" "proto.action.add" = "Lisää prototyyppitoiminto" "proto.action.move" = "Muuta prototyyppitoimintojen järjestystä" diff --git a/crates/ui-egui/locales/fr.toml b/crates/ui-egui/locales/fr.toml index cc77ce6a..dc61c3e9 100644 --- a/crates/ui-egui/locales/fr.toml +++ b/crates/ui-egui/locales/fr.toml @@ -1296,6 +1296,7 @@ status = "draft — needs native review" "Start from a blank canvas" = "Commencer avec un canevas vide" "Start from a template" = "Commencer avec un modèle" "Start on path" = "Début sur le tracé" +"Start on the Home screen" = "Démarrer sur l’Accueil" "Start point" = "Point de départ" "Start sharing" = "Commencer le partage" "Start sharing with the Share button, then pass on the code it gives" = "Commencez à partager avec le bouton Partager, puis communiquez le code qu’il donne" @@ -2029,6 +2030,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "Réduire les animations" "pref.renameDuplicates" = "Renommer les calques dupliqués" "pref.showDimensions" = "Afficher les dimensions sur les objets" +"pref.startOnHome" = "Démarrer sur l’Accueil" "pref.uiScale" = "Taille de l’interface" "pref.userName" = "Votre nom dans les commentaires" "proto.action.add" = "Ajouter une action de prototype" diff --git a/crates/ui-egui/locales/ja.toml b/crates/ui-egui/locales/ja.toml index e0d0de2c..2bf3dfcc 100644 --- a/crates/ui-egui/locales/ja.toml +++ b/crates/ui-egui/locales/ja.toml @@ -1283,6 +1283,7 @@ status = "draft — needs native review" "Start from a blank canvas" = "空白のキャンバスから始める" "Start from a template" = "テンプレートから始める" "Start on path" = "パス上の開始位置" +"Start on the Home screen" = "起動時にホームを表示" "Start point" = "始点" "Start sharing" = "共有を開始" "Start sharing with the Share button, then pass on the code it gives" = "共有ボタンで共有を開始し、表示されたコードを相手に伝える" @@ -2008,6 +2009,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "動きを減らす" "pref.renameDuplicates" = "複製したレイヤーの名前を変更" "pref.showDimensions" = "オブジェクトに寸法を表示" +"pref.startOnHome" = "起動時にホームを表示" "pref.userName" = "コメントに表示する名前" "proto.action.add" = "プロトタイプのアクションを追加" "proto.action.move" = "プロトタイプのアクションの順序を変更" diff --git a/crates/ui-egui/locales/ko.toml b/crates/ui-egui/locales/ko.toml index b949b847..47cb0a01 100644 --- a/crates/ui-egui/locales/ko.toml +++ b/crates/ui-egui/locales/ko.toml @@ -1219,6 +1219,7 @@ status = "draft — needs native review" "Start ascending from / stop descending at" = "오름차순 시작 값 / 내림차순 끝 값" "Start from a blank canvas" = "빈 캔버스로 시작" "Start on path" = "패스 시작 위치" +"Start on the Home screen" = "홈에서 시작" "Start point" = "시작점" "Start sharing" = "공유 시작" "Starting to share…" = "공유를 시작하는 중…" @@ -1926,6 +1927,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "동작 줄이기" "pref.renameDuplicates" = "복제한 레이어 이름 바꾸기" "pref.showDimensions" = "개체에 치수 표시" +"pref.startOnHome" = "홈에서 시작" "pref.userName" = "댓글에 표시할 이름" "proto.action.add" = "프로토타입 액션 추가" "proto.action.move" = "프로토타입 액션 순서 변경" diff --git a/crates/ui-egui/locales/nl.toml b/crates/ui-egui/locales/nl.toml index 6a758d67..aecbc566 100644 --- a/crates/ui-egui/locales/nl.toml +++ b/crates/ui-egui/locales/nl.toml @@ -1301,6 +1301,7 @@ status = "draft — needs native review" "Start from a blank canvas" = "Begin vanaf een leeg canvas" "Start from a template" = "Begin met een sjabloon" "Start on path" = "Begin op het pad" +"Start on the Home screen" = "Starten op Home" "Start point" = "Startpunt" "Start sharing" = "Delen starten" "Start sharing with the Share button, then pass on the code it gives" = "Begin met delen via de knop Delen en geef daarna de code door die je krijgt" @@ -2035,6 +2036,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "Beweging verminderen" "pref.renameDuplicates" = "Gedupliceerde lagen hernoemen" "pref.showDimensions" = "Afmetingen op objecten tonen" +"pref.startOnHome" = "Starten op Home" "pref.userName" = "Je naam in reacties" "proto.action.add" = "Prototypeactie toevoegen" "proto.action.move" = "Volgorde van prototypeactie wijzigen" diff --git a/crates/ui-egui/locales/pt-BR.toml b/crates/ui-egui/locales/pt-BR.toml index 377f66e8..762928ec 100644 --- a/crates/ui-egui/locales/pt-BR.toml +++ b/crates/ui-egui/locales/pt-BR.toml @@ -1218,6 +1218,7 @@ status = "draft — needs native review" "Start ascending from / stop descending at" = "Contar para cima a partir de / para baixo até" "Start from a blank canvas" = "Comece com uma tela em branco" "Start on path" = "Início no caminho" +"Start on the Home screen" = "Começar no Início" "Start point" = "Ponto inicial" "Start sharing" = "Começar a compartilhar" "Starting to share…" = "Começando a compartilhar…" @@ -1925,6 +1926,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "Reduzir movimento" "pref.renameDuplicates" = "Renomear camadas duplicadas" "pref.showDimensions" = "Mostrar dimensões nos objetos" +"pref.startOnHome" = "Começar no Início" "pref.userName" = "Seu nome nos comentários" "proto.action.add" = "Adicionar ação de protótipo" "proto.action.move" = "Reordenar ação de protótipo" diff --git a/crates/ui-egui/locales/sv.toml b/crates/ui-egui/locales/sv.toml index 8f618bf4..5d299de7 100644 --- a/crates/ui-egui/locales/sv.toml +++ b/crates/ui-egui/locales/sv.toml @@ -1287,6 +1287,7 @@ name = "Svenska" "Start from a blank canvas" = "Börja med en tom arbetsyta" "Start from a template" = "Börja med en mall" "Start on path" = "Början på banan" +"Start on the Home screen" = "Börja på Start" "Start point" = "Startpunkt" "Start sharing" = "Börja dela" "Start sharing with the Share button, then pass on the code it gives" = "Börja dela med knappen Dela och skicka sedan vidare koden du får" @@ -2016,6 +2017,7 @@ name = "Svenska" "pref.reduceMotion" = "Minska rörelse" "pref.renameDuplicates" = "Byt namn på duplicerade lager" "pref.showDimensions" = "Visa dimensioner på objekt" +"pref.startOnHome" = "Börja på Start" "pref.userName" = "Ditt namn i kommentarer" "proto.action.add" = "Lägg till prototypåtgärd" "proto.action.move" = "Ändra ordning på prototypåtgärd" diff --git a/crates/ui-egui/locales/zh-Hans.toml b/crates/ui-egui/locales/zh-Hans.toml index 15d03ede..786cd313 100644 --- a/crates/ui-egui/locales/zh-Hans.toml +++ b/crates/ui-egui/locales/zh-Hans.toml @@ -1220,6 +1220,7 @@ status = "draft — needs native review" "Start ascending from / stop descending at" = "升序起点 / 降序终点" "Start from a blank canvas" = "从空白画布开始" "Start on path" = "路径起点" +"Start on the Home screen" = "启动时显示主页" "Start point" = "起点" "Start sharing" = "开始分享" "Starting to share…" = "正在开始分享…" @@ -1927,6 +1928,7 @@ status = "draft — needs native review" "pref.reduceMotion" = "减少动态效果" "pref.renameDuplicates" = "重命名副本图层" "pref.showDimensions" = "在对象上显示尺寸" +"pref.startOnHome" = "启动时显示主页" "pref.userName" = "评论中显示的名字" "proto.action.add" = "添加原型操作" "proto.action.move" = "调整原型操作顺序" diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 6830dac3..bf9f1b29 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -226,6 +226,9 @@ pub fn show(app: &mut FigApp, ctx: &Context) { if !cfg!(target_arch = "wasm32") && crate::widgets::checkbox(ui, prefs.auto_save, tr("Save files automatically")) { toggles.push("pref.autoSave"); } + if !cfg!(target_arch = "wasm32") && crate::widgets::checkbox(ui, prefs.start_on_home, tr("Start on the Home screen")) { + toggles.push("pref.startOnHome"); + } for c in toggles { app.run(c, json!({})); } diff --git a/docs/mcp.md b/docs/mcp.md index e8dc9f37..911d1c71 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -428,6 +428,9 @@ on; `key` resolves keys the way the canvas does. Commands behind keys: it is larger; the choice is kept. In the browser the interface always follows the browser's zoom. - `pref.autoSave {on?}`: files that have a path save themselves a few seconds after they change (off by default; the desktop app's timer does it, so scripts still call `file.save`). +- `pref.startOnHome {on?}`: the desktop app starts on the Home screen instead of in a new file + (off by default; files named on the command line still open, and `--control` starts in a new + file anyway, so control callers have a document). - `pref.language {language: system|en|cs|ru|es|es-419|fr|de|pt-BR|ja|ko|zh-Hans|…}`: the app's interface language, applied live ("system": - `pref.language {language: system|en|es|es-419|fr|de|pt-BR|ja|ko|sv|zh-Hans|…}`: the app's interface language, applied live ("system": the OS or browser language; a language without a catalog shows English). Command ids, labels and