Files
qbz/crates/qbz-qt/qml/settings/PlaybackSettings.qml
T
vicrodh 83999fc552 feat(qbz-qt): rebuild Settings 1:1 against Slint
The pane was written fast and had drifted both ways: four whole sections were
a placeholder reading "not ported to the Qt frontend yet", and what was there
carried rows and copy Slint does not have — an invented custom-theme info row,
made-up "Restart to apply" descriptions, dividers Integrations never had, and
two buttons forked inline instead of using the shared control.

Every section is real now, in Slint's order and grouping, with Slint's labels
and control types: Audio, Playback, Appearance, Offline, Local Library,
Blacklist, Integrations, Developer, and the sandbox section that only appears
on a Flatpak or Snap install. Local Library brings the folder table and the
Plex panel — 856 lines of Slint with no counterpart here until now — wired to
the Plex store that landed earlier this round. Its PIN auth flow is not ported,
so the manual server-url and token path is what this exposes.

The rule the round was run under: a row whose key is not in settings_qt's
dispatch renders and does nothing, so it is either wired or not shipped.
"Share logs" was exactly that — present since the port began, inert — and now
opens the on-disk log.

The directory is per-section files under a thin composition root rather than
one growing file, and the sub-nav's bottom spacer stops being arithmetic over a
hardcoded row count, which broke the moment anyone added a section.

cc
2026-07-28 17:21:44 -06:00

150 lines
6.2 KiB
QML

// Settings > Playback — the QML port of crates/qbz-ui/ui/settings/
// PlaybackSettings.slint. 1:1 group order, labels, descriptions and gating;
// every control rides the settingsJson document and the settings invokables.
import QtQuick
import com.blitzfc.qbz
import "../controls"
import "../theme"
Column {
id: root
property var doc: ({})
QbzTheme { id: theme }
spacing: 4
// ============================ PLAYBACK ===============================
GroupHeader { text: QbzSession.tr("PLAYBACK", QbzSession.trRev) }
SettingRow {
label: QbzSession.tr("Continue playback after track ends", QbzSession.trRev)
description: QbzSession.tr("Keep playing the rest of the album or playlist instead of stopping.", QbzSession.trRev)
QbzToggle {
checked: root.doc.continuePlayback === true
onToggled: function (v) { QbzBridge.settingsBool("continue-playback", v) }
}
}
SettingRow {
label: QbzSession.tr("Show track playing context", QbzSession.trRev)
description: QbzSession.tr("Display the context-stack icon in the player.", QbzSession.trRev)
QbzToggle {
checked: root.doc.showContextIcon === true
onToggled: function (v) { QbzBridge.settingsBool("show-context-icon", v) }
}
}
SettingRow {
label: QbzSession.tr("Gapless playback", QbzSession.trRev)
description: QbzSession.tr("Play consecutive same-format tracks without a gap.", QbzSession.trRev)
// Disabled while Streaming only is on — gapless needs the local cache.
rowEnabled: root.doc.streamingOnly !== true
QbzToggle {
checked: root.doc.gapless === true
enabled: root.doc.streamingOnly !== true
onToggled: function (v) { QbzBridge.settingsBool("gapless", v) }
}
}
SettingsSpacer { }
SettingsDivider { }
SettingsSpacer { }
// ============================= SESSION ===============================
GroupHeader { text: QbzSession.tr("SESSION", QbzSession.trRev) }
SettingRow {
label: QbzSession.tr("Restore session on startup", QbzSession.trRev)
description: QbzSession.tr("Restore the queue and current track on the next launch.", QbzSession.trRev)
QbzToggle {
checked: root.doc.persistSession === true
onToggled: function (v) { QbzBridge.settingsBool("persist-session", v) }
}
}
SettingRow {
label: QbzSession.tr("Resume playback position", QbzSession.trRev)
description: QbzSession.tr("Also seek back to where the saved track left off.", QbzSession.trRev)
rowEnabled: root.doc.persistSession === true
QbzToggle {
checked: root.doc.resumePosition === true
enabled: root.doc.persistSession === true
onToggled: function (v) { QbzBridge.settingsBool("resume-position", v) }
}
}
SettingRow {
label: QbzSession.tr("Auto-connect Qobuz Connect on startup", QbzSession.trRev)
description: QbzSession.tr("Choose whether Qobuz Connect activates automatically when QBZ launches.", QbzSession.trRev)
QbzSelect {
menuWidth: 240
options: root.doc.qconnectStartupModes || []
currentIndex: root.doc.qconnectStartupIndex || 0
onSelected: function (i) { QbzBridge.settingsSelect("qconnect-startup", i) }
}
}
SettingRow {
label: QbzSession.tr("Qobuz Connect device name", QbzSession.trRev)
description: QbzSession.tr("The name other Qobuz Connect apps see for this device. Applies on the next connection.", QbzSession.trRev)
QbzLineEdit {
width: 240
text: root.doc.qconnectDeviceName || ""
placeholder: root.doc.qconnectDeviceNameDefault || ""
onCommitted: function (s) { QbzBridge.settingsString("qconnect-device-name", s) }
}
}
SettingsSpacer { }
SettingsDivider { }
SettingsSpacer { }
// ============================ STREAMING ==============================
GroupHeader { text: QbzSession.tr("STREAMING", QbzSession.trRev) }
SettingRow {
label: QbzSession.tr("Stream uncached tracks", QbzSession.trRev)
description: QbzSession.tr("Start uncached tracks via streaming instead of waiting for the full download.", QbzSession.trRev)
QbzToggle {
checked: root.doc.streamUncached === true
onToggled: function (v) { QbzBridge.settingsBool("stream-uncached", v) }
}
}
SettingRow {
visible: root.doc.streamUncached === true
label: QbzSession.tr("Initial buffer size", QbzSession.trRev)
description: QbzSession.tr("Seconds of audio buffered before streaming playback starts.", QbzSession.trRev)
Row {
spacing: 12
QbzSlider {
width: 160
anchors.verticalCenter: parent.verticalCenter
minimum: 1
maximum: 10
value: root.doc.bufferSeconds || 1
onChanged: function (v) { QbzBridge.settingsSlider("buffer-seconds", v) }
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: (root.doc.bufferSeconds || 1) + QbzSession.tr("s", QbzSession.trRev)
color: theme.textSecondary
font.pixelSize: theme.fontBody
font.weight: theme.weightMedium
}
}
}
SettingRow {
label: QbzSession.tr("Streaming only", QbzSession.trRev)
description: QbzSession.tr("Skip writing tracks to the local cache while streaming.", QbzSession.trRev)
QbzToggle {
checked: root.doc.streamingOnly === true
onToggled: function (v) { QbzBridge.settingsBool("streaming-only", v) }
}
}
SettingRow {
label: QbzSession.tr("When quality retries fail", QbzSession.trRev)
description: QbzSession.tr("What to do when every quality tier for a track is unavailable.", QbzSession.trRev)
QbzSelect {
menuWidth: 240
options: root.doc.retryBehaviors || []
currentIndex: root.doc.retryBehaviorIndex || 0
onSelected: function (i) { QbzBridge.settingsSelect("retry-behavior", i) }
}
}
}