wactioncenter: bluetooth menu

This commit is contained in:
end-4
2025-11-22 21:55:47 +01:00
parent 7613bba393
commit 55961ae079
22 changed files with 451 additions and 69 deletions
@@ -0,0 +1,29 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.services.network
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.actionCenter
WChoiceButton {
id: root
property bool expanded: false
checked: expanded
clip: true
horizontalPadding: 12
verticalPadding: 6
animateChoiceHighlight: false
Behavior on implicitHeight {
animation: Looks.transition.resize.createObject(this)
}
onClicked: expanded = !expanded
}
@@ -0,0 +1,23 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.modules.waffle.looks
WButton {
id: root
implicitHeight: 40
implicitWidth: contentItem.implicitWidth + 30
color: "transparent"
contentItem: Item {
id: contentItem
anchors.centerIn: parent
implicitWidth: buttonText.implicitWidth
WText {
id: buttonText
anchors.centerIn: parent
color: root.pressed ? Looks.colors.fg : Looks.colors.fg1
text: root.text
}
}
}
@@ -0,0 +1,129 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import Quickshell.Bluetooth
import qs
import qs.services
import qs.services.network
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.actionCenter
Item {
id: root
Component.onCompleted: {
if (Bluetooth.defaultAdapter.enabled) Bluetooth.defaultAdapter.discovering = true;
}
Component.onDestruction: {
Bluetooth.defaultAdapter.discovering = false;
}
PageColumn {
anchors.fill: parent
BodyRectangle {
implicitHeight: 400
implicitWidth: 50
ColumnLayout {
anchors.fill: parent
anchors.margins: 4
spacing: 4
ColumnLayout {
implicitHeight: headerRow.implicitHeight
Layout.fillWidth: true
spacing: 0
RowLayout {
Layout.fillWidth: true
spacing: 0
HeaderRow {
id: headerRow
Layout.fillWidth: true
title: qsTr("Bluetooth")
}
WSwitch {
id: toggleSwitch
Layout.rightMargin: 12
checked: Bluetooth.defaultAdapter?.enabled ?? false
onCheckedChanged: {
if (Bluetooth.defaultAdapter) {
Bluetooth.defaultAdapter.enabled = checked;
if (checked) {
Bluetooth.defaultAdapter.discovering = true;
} else {
Bluetooth.defaultAdapter.discovering = false;
}
}
}
}
}
FadeLoader {
Layout.leftMargin: -4
Layout.rightMargin: -4
Layout.fillWidth: true
shown: Bluetooth.defaultAdapter?.discovering ?? false
visible: true
sourceComponent: WIndeterminateProgressBar {}
}
}
StyledListView {
id: listView
Layout.fillHeight: true
Layout.fillWidth: true
animateAppearance: false
contentHeight: contentLayout.implicitHeight
contentWidth: width
clip: true
spacing: 4
model: ScriptModel {
values: BluetoothStatus.friendlyDeviceList
}
delegate: BluetoothDeviceItem {
required property BluetoothDevice modelData
device: modelData
width: ListView.view.width
}
}
}
}
Separator {}
FooterRectangle {
FooterMoreButton {
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
}
text: qsTr("More Bluetooth settings")
onClicked: {
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "sidebarLeft", "toggle"]);
Quickshell.execDetached(["bash", "-c", Config.options.apps.bluetooth]);
}
}
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
enabled: !Bluetooth.defaultAdapter?.discovering && Bluetooth.defaultAdapter?.enabled
onClicked: {
Bluetooth.defaultAdapter.discovering = true;
}
contentItem: FluentIcon {
icon: "arrow-counterclockwise"
}
}
}
}
}
@@ -0,0 +1,92 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import qs
import qs.services
import qs.services.network
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.actionCenter
ExpandableChoiceButton {
id: root
required property BluetoothDevice device
contentItem: RowLayout {
id: contentItem
spacing: 20
// Device icon
FluentIcon {
Layout.topMargin: 4
Layout.bottomMargin: 4
Layout.alignment: Qt.AlignTop
icon: WIcons.bluetoothDeviceIcon(root?.device)
implicitSize: 18
}
ColumnLayout {
Layout.topMargin: 4
Layout.bottomMargin: 4
Layout.alignment: Qt.AlignTop
Layout.fillWidth: true
spacing: 1
Behavior on Layout.topMargin {
animation: Looks.transition.move.createObject(this)
}
WText {
// Network name
Layout.fillWidth: true
elide: Text.ElideRight
font.pixelSize: Looks.font.pixelSize.large
text: root.device?.name || Translation.tr("Unknown device")
}
WText { // Status
id: statusText
Layout.fillWidth: true
elide: Text.ElideRight
font.pixelSize: Looks.font.pixelSize.large
color: Looks.colors.subfg
visible: root.device?.connected || root.expanded
Behavior on opacity {
animation: Looks.transition.opacity.createObject(this)
}
text: {
if (!root.device?.paired)
return Translation.tr("Not connected");
let statusText = root.device?.connected ? Translation.tr("Connected") : Translation.tr("Paired");
if (!root.device?.batteryAvailable)
return statusText;
statusText += ` ${Math.round(root.device?.battery * 100)}%`;
return statusText;
}
}
WButton {
Layout.alignment: Qt.AlignRight
horizontalAlignment: Text.AlignHCenter
visible: root.expanded
checked: !(root.device?.connected ?? false)
colBackground: Looks.colors.bg2
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
implicitHeight: 30
implicitWidth: 148
text: root.device?.connected ? Translation.tr("Disconnect") : Translation.tr("Connect")
onClicked: {
if (root.device?.connected) {
root.device.disconnect();
} else {
root.device.connect();
}
}
}
}
}
}
@@ -10,6 +10,7 @@ import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.actionCenter.wifi
import qs.modules.waffle.actionCenter.bluetooth
DelegateChooser {
id: root
@@ -29,6 +30,9 @@ DelegateChooser {
toggleModel: BluetoothToggle {}
name: toggleModel.statusText
icon: WIcons.bluetoothIcon
menu: Component {
BluetoothControl {}
}
}
}
DelegateChoice {
@@ -11,30 +11,16 @@ import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.actionCenter
WChoiceButton {
ExpandableChoiceButton {
id: root
required property WifiAccessPoint wifiNetwork
property bool expanded: false
checked: expanded
clip: true
horizontalPadding: 12
verticalPadding: 6
animateChoiceHighlight: false
Behavior on implicitHeight {
animation: Looks.transition.resize.createObject(this)
}
onClicked: expanded = !expanded
contentItem: RowLayout {
id: contentItem
spacing: 12
FluentIcon { // Duotone hack
Layout.bottomMargin: 2
Layout.bottomMargin: 2
Layout.alignment: Qt.AlignTop
property int strength: root.wifiNetwork?.strength ?? 0
icon: "wifi-1"
@@ -14,8 +14,6 @@ import qs.modules.waffle.actionCenter
Item {
id: root
implicitWidth: 360
implicitHeight: 352
Component.onCompleted: {
Network.rescanWifi();
@@ -37,29 +35,31 @@ Item {
implicitHeight: headerRow.implicitHeight
Layout.fillWidth: true
spacing: 0
HeaderRow {
id: headerRow
RowLayout {
Layout.fillWidth: true
title: qsTr("Wi-Fi")
spacing: 0
HeaderRow {
id: headerRow
Layout.fillWidth: true
title: qsTr("Wi-Fi")
}
WSwitch {
id: toggleSwitch
Layout.rightMargin: 12
checked: Network.wifiStatus !== "disabled"
onCheckedChanged: {
Network.enableWifi(checked);
Network.rescanWifi();
}
}
}
FadeLoader {
Layout.leftMargin: -4
Layout.rightMargin: -4
Layout.fillWidth: true
shown: Network.wifiScanning
sourceComponent: StyledIndeterminateProgressBar {
id: progressBar
implicitHeight: 3
background: null
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: progressBar.width
height: progressBar.height
radius: progressBar.height / 2
}
}
}
visible: true
sourceComponent: WIndeterminateProgressBar {}
}
}
@@ -89,30 +89,29 @@ Item {
Separator {}
FooterRectangle {
WButton {
id: moreSettingsButton
FooterMoreButton {
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
}
implicitHeight: 40
implicitWidth: contentItem.implicitWidth + 30
color: "transparent"
text: qsTr("More Internet settings")
onClicked: {
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "sidebarLeft", "toggle"]);
Quickshell.execDetached(["bash", "-c", Config.options.apps.network]);
}
}
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
enabled: !Network.wifiScanning
contentItem: Item {
anchors.centerIn: parent
implicitWidth: buttonText.implicitWidth
WText {
id: buttonText
anchors.centerIn: parent
text: qsTr("More Internet settings")
color: moreSettingsButton.pressed ? Looks.colors.fg : Looks.colors.fg1
}
onClicked: {
Network.rescanWifi();
}
contentItem: FluentIcon {
icon: "arrow-counterclockwise"
}
}
}