diff --git a/README.md b/README.md index bd2ef13e..e3fcba32 100644 --- a/README.md +++ b/README.md @@ -661,7 +661,37 @@ default, you must create it manually. "enabled": false } ] - } + }, + "quickToggles": [ + { + "id": "wifi", + "enabled": true + }, + { + "id": "bluetooth", + "enabled": true + }, + { + "id": "mic", + "enabled": true + }, + { + "enabled": true, + "id": "settings" + }, + { + "id": "gameMode", + "enabled": true + }, + { + "id": "dnd", + "enabled": true + }, + { + "id": "vpn", + "enabled": true + } + ] } } ``` diff --git a/config/Config.qml b/config/Config.qml index 584aebab..6efe9600 100644 --- a/config/Config.qml +++ b/config/Config.qml @@ -334,7 +334,8 @@ Singleton { vpn: { enabled: utilities.vpn.enabled, provider: utilities.vpn.provider - } + }, + quickToggles: utilities.quickToggles }; } diff --git a/config/UtilitiesConfig.qml b/config/UtilitiesConfig.qml index cf464460..4d1dd6e8 100644 --- a/config/UtilitiesConfig.qml +++ b/config/UtilitiesConfig.qml @@ -32,4 +32,35 @@ JsonObject { property bool enabled: false property list provider: ["netbird"] } + + property list quickToggles: [ + { + id: "wifi", + enabled: true + }, + { + id: "bluetooth", + enabled: true + }, + { + id: "mic", + enabled: true + }, + { + id: "settings", + enabled: true + }, + { + id: "gameMode", + enabled: true + }, + { + id: "dnd", + enabled: true + }, + { + id: "vpn", + enabled: false + } + ] } diff --git a/modules/utilities/cards/Toggles.qml b/modules/utilities/cards/Toggles.qml index dd4a687b..d610586b 100644 --- a/modules/utilities/cards/Toggles.qml +++ b/modules/utilities/cards/Toggles.qml @@ -14,6 +14,30 @@ StyledRect { required property var visibilities required property Item popouts + readonly property var quickToggles: { + const seenIds = new Set(); + + return Config.utilities.quickToggles.filter(item => { + if (!item.enabled) + return false; + + if (seenIds.has(item.id)) { + return false; + } + + if (item.id === "vpn") { + return Config.utilities.vpn.provider.some(p => + typeof p === "object" ? (p.enabled === true) : false + ); + } + + seenIds.add(item.id); + return true; + }); + } + readonly property int splitIndex: Math.ceil(quickToggles.length / 2) + readonly property bool needExtraRow: quickToggles.length > 6 + Layout.fillWidth: true implicitHeight: layout.implicitHeight + Appearance.padding.large * 2 @@ -32,64 +56,97 @@ StyledRect { font.pointSize: Appearance.font.size.normal } - RowLayout { - Layout.alignment: Qt.AlignHCenter - spacing: Appearance.spacing.small + ToggleRow { + rowModel: root.needExtraRow ? root.quickToggles.slice(0, root.splitIndex) : root.quickToggles + } - Toggle { - icon: "wifi" - checked: Nmcli.wifiEnabled - onClicked: Nmcli.toggleWifi() - } + ToggleRow { + visible: root.needExtraRow + rowModel: root.needExtraRow ? root.quickToggles.slice(root.splitIndex) : [] + } + } - Toggle { - icon: "bluetooth" - checked: Bluetooth.defaultAdapter?.enabled ?? false - onClicked: { - const adapter = Bluetooth.defaultAdapter; - if (adapter) - adapter.enabled = !adapter.enabled; + component ToggleRow: RowLayout { + property var rowModel: [] + + Layout.fillWidth: true + spacing: Appearance.spacing.small + + Repeater { + model: parent.rowModel + + delegate: DelegateChooser { + role: "id" + + DelegateChoice { + roleValue: "wifi" + delegate: Toggle { + icon: "wifi" + checked: Nmcli.wifiEnabled + onClicked: Nmcli.toggleWifi() + } } - } - - Toggle { - icon: "mic" - checked: !Audio.sourceMuted - onClicked: { - const audio = Audio.source?.audio; - if (audio) - audio.muted = !audio.muted; + DelegateChoice { + roleValue: "bluetooth" + delegate: Toggle { + icon: "bluetooth" + checked: Bluetooth.defaultAdapter?.enabled ?? false + onClicked: { + const adapter = Bluetooth.defaultAdapter; + if (adapter) + adapter.enabled = !adapter.enabled; + } + } } - } - - Toggle { - icon: "settings" - inactiveOnColour: Colours.palette.m3onSurfaceVariant - toggle: false - onClicked: { - root.visibilities.utilities = false; - root.popouts.detach("network"); + DelegateChoice { + roleValue: "mic" + delegate: Toggle { + icon: "mic" + checked: !Audio.sourceMuted + onClicked: { + const audio = Audio.source?.audio; + if (audio) + audio.muted = !audio.muted; + } + } + } + DelegateChoice { + roleValue: "settings" + delegate: Toggle { + icon: "settings" + inactiveOnColour: Colours.palette.m3onSurfaceVariant + toggle: false + onClicked: { + root.visibilities.utilities = false; + root.popouts.detach("network"); + } + } + } + DelegateChoice { + roleValue: "gameMode" + delegate: Toggle { + icon: "gamepad" + checked: GameMode.enabled + onClicked: GameMode.enabled = !GameMode.enabled + } + } + DelegateChoice { + roleValue: "dnd" + delegate: Toggle { + icon: "notifications_off" + checked: Notifs.dnd + onClicked: Notifs.dnd = !Notifs.dnd + } + } + DelegateChoice { + roleValue: "vpn" + delegate: Toggle { + icon: "vpn_key" + checked: VPN.connected + enabled: !VPN.connecting + onClicked: VPN.toggle() + } } - } - - Toggle { - icon: "gamepad" - checked: GameMode.enabled - onClicked: GameMode.enabled = !GameMode.enabled - } - - Toggle { - icon: "notifications_off" - checked: Notifs.dnd - onClicked: Notifs.dnd = !Notifs.dnd - } - - Toggle { - icon: "vpn_key" - checked: VPN.connected - enabled: !VPN.connecting - visible: Config.utilities.vpn.provider.some(p => typeof p === "object" ? (p.enabled === true) : false) - onClicked: VPN.toggle() } } }