fix(qt): a theme's options sit under its picker, boxed and collapsible
In Settings > Appearance the rows that exist only for one theme trailed the whole THEME group: the Custom editor and the Auto source rows came after Album header gradient, Compact header and Dynamic background. With a Wallpaper background, Background image then ran straight into the Custom editor and read as one of its options. Each choice's options now follow their own picker inside a SettingsFieldset: a bordered group with a header whose chevron folds it (> folded, v open). The Custom and Auto theme options sit right under Theme, Custom starting at "Start from current theme", and the Wallpaper background's Background image sits under Dynamic background. The rows themselves are unchanged. Each box keeps its folded state across restarts through settingsBool and ui_prefs, the way the sidebar sections do (theme-custom-collapsed, theme-auto-collapsed, ambient-options-collapsed; default open). Folding the Custom box also closes an open color picker. tst_settings_fieldset covers the rows inside the border, the header click and keys, the settings below moving up, and a row click not toggling. cc
This commit is contained in:
8 files changed
+391
-103
No files matched your search
@@ -628,6 +628,7 @@ fn main() {
|
||||
"qml/controls/IconTextButton.qml",
|
||||
"qml/controls/SettingsButton.qml",
|
||||
"qml/controls/SettingsDivider.qml",
|
||||
"qml/controls/SettingsFieldset.qml",
|
||||
"qml/controls/SettingsSpacer.qml",
|
||||
// Moved out of views/local/ on 2026-07-31: the album/track
|
||||
// CARD badges mount it too, and Slint keeps its counterpart in
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// SettingsFieldset — a bordered, collapsible group of settings rows that
|
||||
// belong to ONE control above them (the options of the selected theme).
|
||||
//
|
||||
// The border and the faint fill are what say "these rows are part of the
|
||||
// same thing"; the header's chevron (> collapsed, v expanded) hides the body.
|
||||
// The component does not own the collapsed state: the host passes the
|
||||
// persisted value in and writes it back from `toggleRequested`, the same way
|
||||
// the sidebar sections and the media-server panels keep theirs across
|
||||
// restarts (settingsBool -> ui_prefs -> settingsJson).
|
||||
//
|
||||
// Rows go straight in as children; the body is a Column with a side inset,
|
||||
// so a SettingRow still takes the full inner width.
|
||||
|
||||
import QtQuick
|
||||
import com.blitzfc.qbz
|
||||
import "../theme"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool kioskHost: false
|
||||
property string title: ""
|
||||
property bool collapsed: false
|
||||
signal toggleRequested()
|
||||
default property alias content: body.data
|
||||
|
||||
QbzTheme { id: theme }
|
||||
|
||||
readonly property int inset: kioskHost ? 16 : 12
|
||||
|
||||
width: parent ? parent.width : 0
|
||||
height: header.height + (collapsed ? 0 : body.height + inset)
|
||||
radius: theme.radiusMd
|
||||
color: theme.alphaTier(3)
|
||||
border.width: 1
|
||||
border.color: theme.borderMuted
|
||||
|
||||
Rectangle {
|
||||
id: header
|
||||
x: 1
|
||||
y: 1
|
||||
width: parent.width - 2
|
||||
height: root.kioskHost ? 52 : 40
|
||||
radius: theme.radiusMd
|
||||
color: headerArea.containsMouse ? theme.elevatedHoverFill : "transparent"
|
||||
activeFocusOnTab: true
|
||||
border.width: activeFocus ? 2 : 0
|
||||
border.color: theme.accent
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: root.title
|
||||
Accessible.onPressAction: root.toggleRequested()
|
||||
Keys.onPressed: function (event) {
|
||||
if (!event.isAutoRepeat
|
||||
&& (event.key === Qt.Key_Space
|
||||
|| event.key === Qt.Key_Return
|
||||
|| event.key === Qt.Key_Enter)) {
|
||||
root.toggleRequested()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.inset - 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 8
|
||||
QbzIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: root.collapsed ? "chevron-right" : "chevron-down"
|
||||
width: root.kioskHost ? 20 : 16
|
||||
height: root.kioskHost ? 20 : 16
|
||||
tintName: "secondary"
|
||||
}
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.title
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: root.kioskHost ? theme.fontBody * 1.2 : theme.fontBody
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: headerArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: header.forceActiveFocus()
|
||||
onClicked: root.toggleRequested()
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: body
|
||||
visible: !root.collapsed
|
||||
x: root.inset
|
||||
y: header.y + header.height
|
||||
width: root.width - 2 * root.inset
|
||||
spacing: 4
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,15 @@ Column {
|
||||
readonly property bool tbLocked: doc.hideTitleBar === true || doc.useSystemTitleBar === true
|
||||
|
||||
// ============================ THEME ==================================
|
||||
// ── EACH CHOICE'S OPTIONS SIT UNDER ITS OWN PICKER (2026-09-14) ────────
|
||||
// The rows that exist only for one choice used to trail the whole group:
|
||||
// Custom's editor and Auto's source rows came after Album header
|
||||
// gradient, Compact header and Dynamic background, and Background image
|
||||
// (an option of the Wallpaper background) ran straight into the Custom
|
||||
// editor, so it read as part of the theme. Now each picker is followed by
|
||||
// ITS options, boxed in a SettingsFieldset whose chevron state persists:
|
||||
// the theme's right under Theme, the background's right under Dynamic
|
||||
// background. The rows themselves are unchanged.
|
||||
GroupHeader { kioskHost: root.kioskHost; text: QbzSession.tr("THEME", QbzSession.trRev) }
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Theme", QbzSession.trRev)
|
||||
@@ -122,6 +131,113 @@ Column {
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The applied theme's display name, the legend of its options box.
|
||||
readonly property string currentThemeLabel: {
|
||||
for (let i = 0; i < themeEntries.length; i++) {
|
||||
if (themeEntries[i].slug === QbzShell.themeSlug) return themeEntries[i].label
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Auto-theme rows (the "auto" theme only).
|
||||
SettingsFieldset { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "auto"
|
||||
title: root.currentThemeLabel
|
||||
collapsed: root.doc.themeAutoCollapsed === true
|
||||
onToggleRequested: QbzBridge.settingsBool("theme-auto-collapsed", root.doc.themeAutoCollapsed !== true)
|
||||
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Source", QbzSession.trRev)
|
||||
description: QbzSession.tr("Generate a color theme from your system wallpaper or a custom image", QbzSession.trRev)
|
||||
QbzSelect { kioskHost: root.kioskHost;
|
||||
menuWidth: 200
|
||||
options: root.doc.autoThemeSources || []
|
||||
currentIndex: root.doc.autoThemeSourceIndex || 0
|
||||
onSelected: function (i) { QbzBridge.settingsSelect("auto-theme-source", i) }
|
||||
}
|
||||
}
|
||||
// "Custom Image" only (source index 2) — AppearanceSettings.slint:283-292.
|
||||
// The row's LABEL is the picked path, which is how the reference shows
|
||||
// what is currently in use; with nothing picked it repeats the button's
|
||||
// text. Both strings already exist in the catalogs.
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: (root.doc.autoThemeSourceIndex || 0) === 2
|
||||
label: (root.doc.autoThemeImagePath || "") !== ""
|
||||
? root.doc.autoThemeImagePath
|
||||
: QbzSession.tr("Select Image...", QbzSession.trRev)
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Select Image...", QbzSession.trRev)
|
||||
// The action seam for button rows is settingsString with an empty
|
||||
// payload — the `library-pick-folder` precedent
|
||||
// (LibraryFolderTable.qml:111).
|
||||
onClicked: QbzBridge.settingsString("auto-theme-select-image", "")
|
||||
}
|
||||
}
|
||||
// The detected desktop, with the experimental caveat under it
|
||||
// (`:294-297`). Hint only — no control, and it hides when the shared
|
||||
// detector cannot name a desktop.
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: (root.doc.autoThemeDetectedDe || "") !== ""
|
||||
label: QbzSession.tr("Detected: ", QbzSession.trRev)
|
||||
+ (root.doc.autoThemeDetectedDe || "")
|
||||
description: QbzSession.tr("Experimental: theme may not match your system exactly.", QbzSession.trRev)
|
||||
}
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Regenerate", QbzSession.trRev)
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Regenerate", QbzSession.trRev)
|
||||
onClicked: QbzShell.themeSet(QbzShell.themeSlug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom-theme editor rows (the appended "Custom" theme only), 1:1 with
|
||||
// AppearanceSettings.slint:313-425. "Start from current theme" re-seeds
|
||||
// the base from the applied palette; the "Dark theme" toggle flips
|
||||
// polarity; the grid below edits each base token and the rest of the
|
||||
// palette is derived live in Rust on every change.
|
||||
//
|
||||
// There is deliberately NO save / save-as, NO delete, NO named-theme list
|
||||
// and NO import/export: the model is ONE implicit custom theme that
|
||||
// autosaves, and the reference has none of those affordances either.
|
||||
SettingsFieldset { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "custom"
|
||||
title: root.currentThemeLabel
|
||||
collapsed: root.doc.themeCustomCollapsed === true
|
||||
onToggleRequested: {
|
||||
// A picker left open inside a folded box would come back open.
|
||||
customThemeEditor.closePicker()
|
||||
QbzBridge.settingsBool("theme-custom-collapsed", root.doc.themeCustomCollapsed !== true)
|
||||
}
|
||||
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Start from current theme", QbzSession.trRev)
|
||||
description: QbzSession.tr("Copy the colors of the currently applied theme into the editor as a starting point.", QbzSession.trRev)
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Use current colors", QbzSession.trRev)
|
||||
onClicked: {
|
||||
QbzShell.customSeedFromCurrent()
|
||||
customThemeEditor.closePicker()
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Dark theme", QbzSession.trRev)
|
||||
description: QbzSession.tr("Set the overall light or dark polarity. Affects derived shades, borders and overlays.", QbzSession.trRev)
|
||||
QbzToggle { kioskHost: root.kioskHost;
|
||||
checked: customThemeEditor.isDark
|
||||
onToggled: function (v) { QbzShell.customToggleDark(v) }
|
||||
}
|
||||
}
|
||||
// NOT inside a SettingRow: that control hardcodes 52/64px and centres one
|
||||
// child, which would clip the ~250px picker. The reference keeps the grid
|
||||
// outside its own rows for the same reason.
|
||||
CustomThemeEditor { kioskHost: root.kioskHost;
|
||||
id: customThemeEditor
|
||||
visible: QbzShell.themeSlug === "custom"
|
||||
}
|
||||
}
|
||||
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Album header gradient", QbzSession.trRev)
|
||||
description: QbzSession.tr("Use artwork-derived blur as a backdrop in album and artist detail views.", QbzSession.trRev)
|
||||
@@ -148,113 +264,36 @@ Column {
|
||||
onSelected: function (i) { QbzBridge.settingsSelect("app-background", i) }
|
||||
}
|
||||
}
|
||||
// The picture behind the two Wallpaper modes: the desktop's, or one of
|
||||
// the user's own (wallpaper_qt.rs).
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: (root.doc.appBackgroundIndex || 0) >= 3
|
||||
label: QbzSession.tr("Background image", QbzSession.trRev)
|
||||
description: (root.doc.appBackgroundImage || "") !== ""
|
||||
? root.doc.appBackgroundImage
|
||||
: QbzSession.tr("The system wallpaper. Choose an image of your own instead.", QbzSession.trRev)
|
||||
Row {
|
||||
spacing: 8
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Choose image…", QbzSession.trRev)
|
||||
onClicked: QbzBridge.settingsPickBackgroundImage()
|
||||
}
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
visible: (root.doc.appBackgroundImage || "") !== ""
|
||||
text: QbzSession.tr("System wallpaper", QbzSession.trRev)
|
||||
onClicked: QbzBridge.settingsClearBackgroundImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
// Auto-theme rows (the "auto" theme only).
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "auto"
|
||||
label: QbzSession.tr("Source", QbzSession.trRev)
|
||||
description: QbzSession.tr("Generate a color theme from your system wallpaper or a custom image", QbzSession.trRev)
|
||||
QbzSelect { kioskHost: root.kioskHost;
|
||||
menuWidth: 200
|
||||
options: root.doc.autoThemeSources || []
|
||||
currentIndex: root.doc.autoThemeSourceIndex || 0
|
||||
onSelected: function (i) { QbzBridge.settingsSelect("auto-theme-source", i) }
|
||||
}
|
||||
}
|
||||
// "Custom Image" only (source index 2) — AppearanceSettings.slint:283-292.
|
||||
// The row's LABEL is the picked path, which is how the reference shows
|
||||
// what is currently in use; with nothing picked it repeats the button's
|
||||
// text. Both strings already exist in the catalogs.
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "auto"
|
||||
&& (root.doc.autoThemeSourceIndex || 0) === 2
|
||||
label: (root.doc.autoThemeImagePath || "") !== ""
|
||||
? root.doc.autoThemeImagePath
|
||||
: QbzSession.tr("Select Image...", QbzSession.trRev)
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Select Image...", QbzSession.trRev)
|
||||
// The action seam for button rows is settingsString with an empty
|
||||
// payload — the `library-pick-folder` precedent
|
||||
// (LibraryFolderTable.qml:111).
|
||||
onClicked: QbzBridge.settingsString("auto-theme-select-image", "")
|
||||
}
|
||||
}
|
||||
// The detected desktop, with the experimental caveat under it
|
||||
// (`:294-297`). Hint only — no control, and it hides when the shared
|
||||
// detector cannot name a desktop.
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "auto"
|
||||
&& (root.doc.autoThemeDetectedDe || "") !== ""
|
||||
label: QbzSession.tr("Detected: ", QbzSession.trRev)
|
||||
+ (root.doc.autoThemeDetectedDe || "")
|
||||
description: QbzSession.tr("Experimental: theme may not match your system exactly.", QbzSession.trRev)
|
||||
}
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "auto"
|
||||
label: QbzSession.tr("Regenerate", QbzSession.trRev)
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Regenerate", QbzSession.trRev)
|
||||
onClicked: QbzShell.themeSet(QbzShell.themeSlug)
|
||||
}
|
||||
}
|
||||
// The options of the chosen background: only the two Wallpaper modes
|
||||
// (3 Wallpaper, 4 Wallpaper, blurred) have any.
|
||||
readonly property int backgroundIndex: root.doc.appBackgroundIndex || 0
|
||||
SettingsFieldset { kioskHost: root.kioskHost;
|
||||
visible: root.backgroundIndex >= 3
|
||||
title: (root.doc.appBackgroundModes || [])[root.backgroundIndex] || ""
|
||||
collapsed: root.doc.ambientOptionsCollapsed === true
|
||||
onToggleRequested: QbzBridge.settingsBool("ambient-options-collapsed", root.doc.ambientOptionsCollapsed !== true)
|
||||
|
||||
// Custom-theme editor rows (the appended "Custom" theme only), 1:1 with
|
||||
// AppearanceSettings.slint:313-425. "Start from current theme" re-seeds
|
||||
// the base from the applied palette; the "Dark theme" toggle flips
|
||||
// polarity; the grid below edits each base token and the rest of the
|
||||
// palette is derived live in Rust on every change.
|
||||
//
|
||||
// There is deliberately NO save / save-as, NO delete, NO named-theme list
|
||||
// and NO import/export: the model is ONE implicit custom theme that
|
||||
// autosaves, and the reference has none of those affordances either.
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "custom"
|
||||
label: QbzSession.tr("Start from current theme", QbzSession.trRev)
|
||||
description: QbzSession.tr("Copy the colors of the currently applied theme into the editor as a starting point.", QbzSession.trRev)
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Use current colors", QbzSession.trRev)
|
||||
onClicked: {
|
||||
QbzShell.customSeedFromCurrent()
|
||||
customThemeEditor.closePicker()
|
||||
// The picture behind the two Wallpaper modes: the desktop's, or one of
|
||||
// the user's own (wallpaper_qt.rs).
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
label: QbzSession.tr("Background image", QbzSession.trRev)
|
||||
description: (root.doc.appBackgroundImage || "") !== ""
|
||||
? root.doc.appBackgroundImage
|
||||
: QbzSession.tr("The system wallpaper. Choose an image of your own instead.", QbzSession.trRev)
|
||||
Row {
|
||||
spacing: 8
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
text: QbzSession.tr("Choose image…", QbzSession.trRev)
|
||||
onClicked: QbzBridge.settingsPickBackgroundImage()
|
||||
}
|
||||
SettingsButton { kioskHost: root.kioskHost;
|
||||
visible: (root.doc.appBackgroundImage || "") !== ""
|
||||
text: QbzSession.tr("System wallpaper", QbzSession.trRev)
|
||||
onClicked: QbzBridge.settingsClearBackgroundImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingRow { kioskHost: root.kioskHost;
|
||||
visible: QbzShell.themeSlug === "custom"
|
||||
label: QbzSession.tr("Dark theme", QbzSession.trRev)
|
||||
description: QbzSession.tr("Set the overall light or dark polarity. Affects derived shades, borders and overlays.", QbzSession.trRev)
|
||||
QbzToggle { kioskHost: root.kioskHost;
|
||||
checked: customThemeEditor.isDark
|
||||
onToggled: function (v) { QbzShell.customToggleDark(v) }
|
||||
}
|
||||
}
|
||||
// NOT inside a SettingRow: that control hardcodes 52/64px and centres one
|
||||
// child, which would clip the ~250px picker. The reference keeps the grid
|
||||
// outside its own rows for the same reason.
|
||||
CustomThemeEditor { kioskHost: root.kioskHost;
|
||||
id: customThemeEditor
|
||||
visible: QbzShell.themeSlug === "custom"
|
||||
}
|
||||
|
||||
SettingsSpacer { }
|
||||
SettingsDivider { }
|
||||
|
||||
@@ -2188,6 +2188,15 @@ pub struct SettingsDoc {
|
||||
/// The user's own background image ("" = the desktop wallpaper).
|
||||
#[serde(rename = "appBackgroundImage")]
|
||||
pub app_background_image: String,
|
||||
/// Persisted fieldset state of the Appearance > Theme groups (default
|
||||
/// expanded): the Custom theme editor, the Auto theme rows, and the
|
||||
/// options of the selected dynamic background.
|
||||
#[serde(rename = "themeCustomCollapsed")]
|
||||
pub theme_custom_collapsed: bool,
|
||||
#[serde(rename = "themeAutoCollapsed")]
|
||||
pub theme_auto_collapsed: bool,
|
||||
#[serde(rename = "ambientOptionsCollapsed")]
|
||||
pub ambient_options_collapsed: bool,
|
||||
#[serde(rename = "autoThemeSources")]
|
||||
pub auto_theme_sources: Vec<String>,
|
||||
#[serde(rename = "autoThemeSourceIndex")]
|
||||
@@ -2748,6 +2757,9 @@ pub async fn publish_snapshot() {
|
||||
.position(|v| *v == pref_str("app_background", "off"))
|
||||
.unwrap_or(0) as i32,
|
||||
app_background_image: pref_str("app_background_image", ""),
|
||||
theme_custom_collapsed: pref_bool("theme_custom_collapsed", false),
|
||||
theme_auto_collapsed: pref_bool("theme_auto_collapsed", false),
|
||||
ambient_options_collapsed: pref_bool("ambient_options_collapsed", false),
|
||||
auto_theme_sources: AUTO_THEME_SOURCE_LABELS
|
||||
.iter()
|
||||
.map(|l| qbz_i18n::t(l))
|
||||
@@ -3689,6 +3701,19 @@ pub async fn settings_bool(runtime: &Arc<AppRuntime<LoggingAdapter>>, key: &str,
|
||||
save_pref("myqbz_collections_collapsed", serde_json::json!(value));
|
||||
Ok(Apply::None)
|
||||
}
|
||||
// Appearance > Theme fieldsets, read back from settingsJson.
|
||||
"theme-custom-collapsed" => {
|
||||
save_pref("theme_custom_collapsed", serde_json::json!(value));
|
||||
Ok(Apply::None)
|
||||
}
|
||||
"theme-auto-collapsed" => {
|
||||
save_pref("theme_auto_collapsed", serde_json::json!(value));
|
||||
Ok(Apply::None)
|
||||
}
|
||||
"ambient-options-collapsed" => {
|
||||
save_pref("ambient_options_collapsed", serde_json::json!(value));
|
||||
Ok(Apply::None)
|
||||
}
|
||||
"sidebar-playlist-collage" => {
|
||||
save_pref("sidebar_playlist_collage", serde_json::json!(value));
|
||||
// LIVE: the sidebar rows swap collage <-> list-music glyph off the
|
||||
@@ -4882,6 +4907,24 @@ mod local_tab_order_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod theme_fieldset_doc_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn the_settings_document_names_the_fieldset_states_for_qml() {
|
||||
let doc = SettingsDoc {
|
||||
theme_custom_collapsed: true,
|
||||
ambient_options_collapsed: true,
|
||||
..Default::default()
|
||||
};
|
||||
let json = serde_json::to_value(&doc).expect("settings document serializes");
|
||||
assert_eq!(json["themeCustomCollapsed"], true);
|
||||
assert_eq!(json["themeAutoCollapsed"], false);
|
||||
assert_eq!(json["ambientOptionsCollapsed"], true);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod exclusive_gate_tests {
|
||||
use super::*;
|
||||
|
||||
Reference in new issue
Block a user