controlcenter: connected button group component

This commit is contained in:
ATMDA 2025-11-17 10:23:32 -05:00
parent 2c91bde795
commit 3f3f3a7d78
2 changed files with 202 additions and 61 deletions

View file

@ -0,0 +1,141 @@
import ".."
import qs.components
import qs.components.controls
import qs.components.effects
import qs.services
import qs.config
import QtQuick
import QtQuick.Layouts
StyledRect {
id: root
property var options: [] // Array of {label: string, propertyName: string, onToggled: function}
property var rootItem: null // The root item that contains the properties we want to bind to
Layout.fillWidth: true
implicitHeight: buttonRow.implicitHeight + Appearance.padding.large * 2
radius: Appearance.rounding.normal
color: Colours.layer(Colours.palette.m3surfaceContainer, 2)
clip: true
Behavior on implicitHeight {
Anim {}
}
RowLayout {
id: buttonRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Appearance.padding.large
spacing: Appearance.spacing.small
Repeater {
id: repeater
model: root.options
delegate: TextButton {
id: button
required property int index
required property var modelData
Layout.fillWidth: true
text: modelData.label
property bool isChecked: false
// Initialize from root property
Component.onCompleted: {
if (root.rootItem && modelData.propertyName) {
isChecked = root.rootItem[modelData.propertyName];
}
}
checked: isChecked
toggle: false
type: TextButton.Tonal
// Listen for property changes on rootItem
Connections {
target: root.rootItem
enabled: root.rootItem !== null && modelData.propertyName !== undefined
function onShowAudioChanged() {
if (modelData.propertyName === "showAudio") {
button.isChecked = root.rootItem.showAudio;
}
}
function onShowMicrophoneChanged() {
if (modelData.propertyName === "showMicrophone") {
button.isChecked = root.rootItem.showMicrophone;
}
}
function onShowKbLayoutChanged() {
if (modelData.propertyName === "showKbLayout") {
button.isChecked = root.rootItem.showKbLayout;
}
}
function onShowNetworkChanged() {
if (modelData.propertyName === "showNetwork") {
button.isChecked = root.rootItem.showNetwork;
}
}
function onShowBluetoothChanged() {
if (modelData.propertyName === "showBluetooth") {
button.isChecked = root.rootItem.showBluetooth;
}
}
function onShowBatteryChanged() {
if (modelData.propertyName === "showBattery") {
button.isChecked = root.rootItem.showBattery;
}
}
function onShowLockStatusChanged() {
if (modelData.propertyName === "showLockStatus") {
button.isChecked = root.rootItem.showLockStatus;
}
}
}
// Match utilities Toggles radius styling
// Each button has full rounding (not connected) since they have spacing
radius: stateLayer.pressed ? Appearance.rounding.small / 2 : internalChecked ? Appearance.rounding.small : Appearance.rounding.normal
// Match utilities Toggles inactive color
inactiveColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
// Adjust width similar to utilities toggles
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? Appearance.padding.large : internalChecked ? Appearance.padding.smaller : 0)
onClicked: {
if (modelData.onToggled) {
modelData.onToggled(!checked);
}
}
Behavior on Layout.preferredWidth {
Anim {
duration: Appearance.anim.durations.expressiveFastSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
}
}
Behavior on radius {
Anim {
duration: Appearance.anim.durations.expressiveFastSpatial
easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial
}
}
}
}
}
}

View file

@ -336,67 +336,67 @@ Item {
id: statusIconsSection id: statusIconsSection
title: qsTr("Status Icons") title: qsTr("Status Icons")
SwitchRow { ConnectedButtonGroup {
label: qsTr("Show audio") rootItem: root
checked: root.showAudio
onToggled: checked => {
root.showAudio = checked;
root.saveConfig();
}
}
SwitchRow { options: [
label: qsTr("Show microphone") {
checked: root.showMicrophone label: qsTr("Audio"),
onToggled: checked => { propertyName: "showAudio",
root.showMicrophone = checked; onToggled: function(checked) {
root.saveConfig(); root.showAudio = checked;
} root.saveConfig();
} }
},
SwitchRow { {
label: qsTr("Show keyboard layout") label: qsTr("Mic"),
checked: root.showKbLayout propertyName: "showMicrophone",
onToggled: checked => { onToggled: function(checked) {
root.showKbLayout = checked; root.showMicrophone = checked;
root.saveConfig(); root.saveConfig();
} }
} },
{
SwitchRow { label: qsTr("KB"),
label: qsTr("Show network") propertyName: "showKbLayout",
checked: root.showNetwork onToggled: function(checked) {
onToggled: checked => { root.showKbLayout = checked;
root.showNetwork = checked; root.saveConfig();
root.saveConfig(); }
} },
} {
label: qsTr("Network"),
SwitchRow { propertyName: "showNetwork",
label: qsTr("Show bluetooth") onToggled: function(checked) {
checked: root.showBluetooth root.showNetwork = checked;
onToggled: checked => { root.saveConfig();
root.showBluetooth = checked; }
root.saveConfig(); },
} {
} label: qsTr("BT"),
propertyName: "showBluetooth",
SwitchRow { onToggled: function(checked) {
label: qsTr("Show battery") root.showBluetooth = checked;
checked: root.showBattery root.saveConfig();
onToggled: checked => { }
root.showBattery = checked; },
root.saveConfig(); {
} label: qsTr("Battery"),
} propertyName: "showBattery",
onToggled: function(checked) {
SwitchRow { root.showBattery = checked;
label: qsTr("Show lock status") root.saveConfig();
checked: root.showLockStatus }
onToggled: checked => { },
root.showLockStatus = checked; {
root.saveConfig(); label: qsTr("Lock"),
} propertyName: "showLockStatus",
onToggled: function(checked) {
root.showLockStatus = checked;
root.saveConfig();
}
}
]
} }
} }