#505: merge origin/main; ja/uk rows, colorTheme kept in line, docs

- ja.tsv rows for the new appearance strings (no duplicate Dark/Light);
  uk.tsv gets Next Appearance Mode, which the pt-br menu catalog now has.
- appearance.colorTheme is legacy input but no longer goes stale: it follows the
  mode and theme choices (the theme a fixed mode shows, the dark theme in Auto).
- docs/project-files.md documents appearanceMode / darkTheme / lightTheme.
- #489's menu/settings label test compares with the theme cards' choices.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-10 07:01:41 -04:00
parent 5c4a07b148
commit 1ffe0cf4e7
7 changed files with 40 additions and 8 deletions

View File

@ -392,6 +392,7 @@ impl Preferences {
self.playback.postroll_seconds = secs(self.playback.postroll_seconds);
self.trim.large_trim_offset = self.trim.large_trim_offset.clamp(1, 1000);
self.labels.sanitize_labels();
self.appearance.sync_color_theme();
self.version = settings::PREFS_VERSION;
}
@ -454,12 +455,13 @@ impl Preferences {
let _: Preferences = serde_json::from_value(v.clone()).map_err(|e| format!("`{key}`: {e}"))?;
settings::sanitize(&mut v, &Self::default().to_value());
let mut p: Preferences = serde_json::from_value(v).map_err(|e| format!("`{key}`: {e}"))?;
p.clamp();
// Old clients that set the single Color Theme still pick the theme they name.
// Old clients that set the single Color Theme still pick the theme they name (before
// `clamp`, which brings `colorTheme` back in line with the mode and theme choices).
if key == "appearance.colorTheme" {
let theme = p.appearance.color_theme.clone();
p.appearance.select_theme(&theme);
}
p.clamp();
*self = p;
Ok(())
}

View File

@ -89,7 +89,10 @@ impl Default for GeneralPrefs {
#[serde(rename_all = "camelCase", default)]
pub struct AppearancePrefs {
/// Legacy single "Color Theme": `darkest` | `dark` | `light`. Setting it (old settings files,
/// automation, View ▸ Appearance) selects that theme and fixes the mode to its family.
/// automation, View ▸ Appearance) selects that theme and fixes the mode to its family. It is
/// kept in line with the fields below ([`AppearancePrefs::sync_color_theme`]): the light or
/// dark theme of a fixed mode, and the dark theme in Auto (whose shown theme depends on the
/// system; read `appearanceMode` for that).
pub color_theme: String,
/// "Appearance Mode": `auto` (follow the operating system) | `dark` (default) | `light`.
pub appearance_mode: String,
@ -140,6 +143,13 @@ impl AppearancePrefs {
}
}
/// Bring the legacy `color_theme` in line with the mode and theme choices, so clients that
/// still read it get the theme a fixed mode shows (the dark theme in Auto).
pub fn sync_color_theme(&mut self) {
let theme = self.shown_theme(None).to_string();
self.color_theme = theme;
}
/// The mode after this one in the header button's cycle: Auto, Light, Dark, Auto…
pub fn next_mode(&self) -> &'static str {
match self.appearance_mode.as_str() {

View File

@ -598,6 +598,17 @@ fn appearance_choices_validate_and_legacy_theme_still_selects() {
assert_eq!(s.prefs.appearance.dark_theme, "dark", "the dark choice is kept");
set(&mut s, "appearance.colorTheme", json!("darkest"));
assert_eq!((s.prefs.appearance.appearance_mode.as_str(), s.prefs.appearance.dark_theme.as_str()), ("dark", "darkest"));
// the legacy Color Theme follows the mode and theme choices, so clients reading it aren't stale
assert_eq!(s.prefs.appearance.color_theme, "darkest");
set(&mut s, "appearance.appearanceMode", json!("light"));
assert_eq!(s.prefs.appearance.color_theme, "light");
set(&mut s, "appearance.appearanceMode", json!("dark"));
set(&mut s, "appearance.darkTheme", json!("dark"));
assert_eq!(s.prefs.appearance.color_theme, "dark");
set(&mut s, "appearance.appearanceMode", json!("auto"));
assert_eq!(s.prefs.appearance.color_theme, "dark", "Auto: the dark theme");
set(&mut s, "appearance.colorTheme", json!("light"));
assert_eq!((s.prefs.appearance.appearance_mode.as_str(), s.prefs.appearance.color_theme.as_str()), ("light", "light"));
// the header button's cycle
let mut a = settings::AppearancePrefs::default();
let mut seen = Vec::new();

View File

@ -3435,8 +3435,13 @@
Username ユーザー名
Vertical Type Tool 縦書き文字ツール
# System appearance mode menu command.
# System appearance modes and theme cards.
Active 使用中
Appearance Mode 外観モード
Dark Theme ダークテーマ
Light Theme ライトテーマ
Next Appearance Mode 次の外観モード
Sync with system システムと同期
Go to previous keyframe 前のキーフレームへ移動
Go to next keyframe 次のキーフレームへ移動
Add keyframe キーフレームを追加

Can't render this file because it contains an unexpected character in line 11 and column 59.

View File

@ -216,6 +216,7 @@
New Створити
New Layer Новий шар
New Project Panel Нова панель проєкту
Next Appearance Mode Наступний режим вигляду
Next in Sequence Наступний у секвенції
Next in Track Наступний на доріжці
Normalize Mix Track… Нормалізувати доріжку міксу…

Can't render this file because it has a wrong number of fields in line 7.

View File

@ -251,9 +251,12 @@ fn view_menu_and_settings_name_each_color_theme_alike() {
let menu = d.ok("ui.menu.list", json!({}));
let menu_label = |id: &str| menu.as_array().unwrap().iter().find(|m| m["id"] == id).unwrap()["label"].as_str().unwrap().to_string();
d.menu("app.settings.appearance");
d.click("settings.appearance.colorTheme");
for (menu_id, pref) in [("view.theme.dark", "darkest"), ("view.theme.medium", "dark"), ("view.theme.light", "light")] {
let id = format!("settings.appearance.colorTheme.{pref}");
// the theme cards' choices (the single Color Theme is no longer drawn)
for (menu_id, id) in [
("view.theme.dark", "settings.appearance.darkTheme.darkest"),
("view.theme.medium", "settings.appearance.darkTheme.dark"),
("view.theme.light", "settings.appearance.lightTheme.light"),
] {
let found = d.ok("ui.elements", json!({"prefix": id}));
let choice = found.as_array().unwrap().iter().find(|e| e["id"] == json!(id)).unwrap();
assert_eq!(menu_label(menu_id), choice["label"].as_str().unwrap(), "{menu_id} and {id} name the same theme");

View File

@ -215,7 +215,7 @@ opens the dialog on a page.
| Category | Takes effect |
|---|---|
| General | At Startup (Show Home = demo project, Open Most Recent, empty project; recent projects are remembered on open/save), Show Tool Tips |
| Appearance | Color Theme (Darkest / Dark / Light; View ▸ Appearance writes it too), highlight colour, accessible contrast |
| Appearance | Appearance Mode `appearanceMode` (`auto` = Sync with system / `dark` (default) / `light`; the header button and View ▸ Appearance ▸ Next Appearance Mode cycle it), Dark Theme `darkTheme` (`darkest` (default) / `dark`), Light Theme `lightTheme` (`light`), highlight colour, accessible contrast. `colorTheme` (Darkest / Dark / Light) is legacy input: setting it (older files and clients, View ▸ Appearance ▸ a theme) selects that theme and fixes the mode to its family; a file without `appearanceMode` migrates to its theme's fixed mode. It is kept in line with the choices: the theme a fixed mode shows, the dark theme in Auto |
| Audio | Automatch Time, Large Volume Adjustment, automation keyframe thinning (linear, minimum time) |
| Audio Hardware | device class (cpal host), output device, I/O buffer size, sample rate, force document rate, Output Mapping (programme L/R → device channels) |
| Auto Save | the auto-save ring and the crash-recovery journal |