styled list view

This commit is contained in:
Benjamin Palko 2025-08-01 23:21:29 -04:00
parent bac125abb0
commit 49ec4d8502
5 changed files with 94 additions and 82 deletions

View file

@ -10,7 +10,7 @@ import Quickshell.Widgets
StyledLabel { StyledLabel {
id: root id: root
property BluetoothDevice device required property BluetoothDevice modelData
RowLayout { RowLayout {
id: row id: row
@ -18,20 +18,20 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: root.device?.icon != undefined active: root.modelData?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 22 implicitSize: 22
source: Quickshell.iconPath(root.device.icon, "device-support-unknown-symbolic") source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: root.device.deviceName text: root.modelData.deviceName
} }
StyledButton { StyledButton {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
hoverEnabled: !root.device.pairing hoverEnabled: !root.modelData.pairing
color: containsMouse ? Theme.palette.primary : Theme.palette.base200 color: containsMouse ? Theme.palette.primary : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Pair' text: 'Pair'
@ -41,8 +41,8 @@ StyledLabel {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
root.device.trusted = true; root.modelData.trusted = true;
root.device.pair(); root.modelData.pair();
} }
} }
} }

View file

@ -30,7 +30,8 @@ StyledPopupWindow {
} }
Switch { Switch {
checked: Bluetooth.defaultAdapter.enabled checkable: !!Bluetooth.defaultAdapter
checked: Bluetooth.defaultAdapter?.enabled ?? false
onClicked: Bluetooth.defaultAdapter.enabled = checked onClicked: Bluetooth.defaultAdapter.enabled = checked
} }
} }
@ -42,7 +43,8 @@ StyledPopupWindow {
} }
Switch { Switch {
checked: Bluetooth.defaultAdapter.discovering checkable: !!Bluetooth.defaultAdapter
checked: Bluetooth.defaultAdapter?.discovering ?? false
onClicked: Bluetooth.defaultAdapter.discovering = checked onClicked: Bluetooth.defaultAdapter.discovering = checked
} }
} }
@ -64,29 +66,29 @@ StyledPopupWindow {
text: "Connected Devices" text: "Connected Devices"
} }
ColumnLayout { StyledListView {
Loader { id: list1
active: repeater1.count == 0 Layout.fillWidth: true
sourceComponent: StyledText { spacing: 8
font.italic: true implicitHeight: 20 + Math.min(40 * count, 160)
text: "No devices connected..." header: Loader {
} active: list1.count == 0
} sourceComponent: Loader {
Repeater { active: list1.count == 0
id: repeater1 sourceComponent: StyledText {
model: ScriptModel { font.italic: true
values: Bluetooth.devices.values.filter(device => device.state == BluetoothDeviceState.Connected) text: "No devices connected..."
}
delegate: Loader {
id: connectedDeviceLoader
required property var modelData
Layout.fillWidth: true
active: modelData != null
sourceComponent: ConnectedDevice {
device: connectedDeviceLoader.modelData
} }
} }
} }
clip: true
model: ScriptModel {
values: Bluetooth.devices.values.filter(device => device.state == BluetoothDeviceState.Connected)
}
delegate: ConnectedDevice {
anchors.left: parent.left
anchors.right: parent.right
}
} }
StyledText { StyledText {
@ -96,28 +98,25 @@ StyledPopupWindow {
text: "Paired Devices" text: "Paired Devices"
} }
ColumnLayout { StyledListView {
Loader { id: list2
active: repeater2.count == 0 Layout.fillWidth: true
spacing: 8
implicitHeight: 20 + Math.min(40 * count, 160)
header: Loader {
active: list2.count == 0
sourceComponent: StyledText { sourceComponent: StyledText {
font.italic: true font.italic: true
text: "No paired devices..." text: "No paired devices..."
} }
} }
Repeater { clip: true
id: repeater2 model: ScriptModel {
model: ScriptModel { values: Bluetooth.defaultAdapter.devices.values.filter(device => device.bonded && device.state == BluetoothDeviceState.Disconnected)
values: Bluetooth.devices.values.filter(device => device.bonded && device.state == BluetoothDeviceState.Disconnected) }
} delegate: PairedDevice {
delegate: Loader { anchors.left: parent.left
id: pairedDeviceLoader anchors.right: parent.right
required property var modelData
Layout.fillWidth: true
active: modelData != null
sourceComponent: PairedDevice {
device: pairedDeviceLoader.modelData
}
}
} }
} }
@ -128,28 +127,25 @@ StyledPopupWindow {
text: "Available Devices" text: "Available Devices"
} }
ColumnLayout { StyledListView {
Loader { id: list3
active: repeater3.count == 0 Layout.fillWidth: true
spacing: 8
clip: true
implicitHeight: 20 + Math.min(40 * count, 160)
header: Loader {
active: list3.count == 0
sourceComponent: StyledText { sourceComponent: StyledText {
font.italic: true font.italic: true
text: Bluetooth.defaultAdapter.discovering ? "No devices found..." : "Scan to find devices..." text: Bluetooth.defaultAdapter.discovering ? "No devices found..." : "Scan to find devices..."
} }
} }
Repeater { model: ScriptModel {
id: repeater3 values: Bluetooth.devices.values.filter(device => !device.bonded && device.deviceName != "")
model: ScriptModel { }
values: Bluetooth.devices.values.filter(device => !device.bonded && device.deviceName != "") delegate: AvailableDevice {
} anchors.left: parent.left
delegate: Loader { anchors.right: parent.right
id: availableDeviceLoader
required property var modelData
Layout.fillWidth: true
active: modelData != null
sourceComponent: AvailableDevice {
device: availableDeviceLoader.modelData
}
}
} }
} }
} }

View file

@ -11,7 +11,7 @@ import Quickshell.Widgets
StyledLabel { StyledLabel {
id: root id: root
required property BluetoothDevice device required property BluetoothDevice modelData
RowLayout { RowLayout {
id: row id: row
@ -19,19 +19,19 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: root.device?.icon != undefined active: root.modelData?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 22 implicitSize: 22
source: Quickshell.iconPath(root.device.icon, "device-support-unknown-symbolic") source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: root.device.deviceName text: root.modelData.deviceName
} }
Loader { Loader {
active: root.device.batteryAvailable active: root.modelData.batteryAvailable
sourceComponent: RowLayout { sourceComponent: RowLayout {
StyledText { StyledText {
id: icon id: icon
@ -42,11 +42,11 @@ StyledLabel {
states: [ states: [
State { State {
name: "full" name: "full"
when: root.device.battery > 0.66 when: root.modelData.battery > 0.66
}, },
State { State {
name: "medium" name: "medium"
when: root.device.battery > 0.33 when: root.modelData.battery > 0.33
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryFull text: Icons.batteryFull
@ -55,7 +55,7 @@ StyledLabel {
}, },
State { State {
name: "low" name: "low"
when: root.device.battery > 0.10 when: root.modelData.battery > 0.10
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryFull text: Icons.batteryFull
@ -64,7 +64,7 @@ StyledLabel {
}, },
State { State {
name: "critical" name: "critical"
when: root.device.battery > 0.10 when: root.modelData.battery > 0.10
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryWarning text: Icons.batteryWarning
@ -85,10 +85,10 @@ StyledLabel {
font.pixelSize: 12 font.pixelSize: 12
} }
onClicked: { onClicked: {
if (root.device.state != BluetoothDeviceState.Connected) { if (root.modelData.state != BluetoothDeviceState.Connected) {
return; return;
} }
root.device.connected = false; root.modelData.connected = false;
} }
} }
} }

View file

@ -10,7 +10,7 @@ import Quickshell.Widgets
StyledLabel { StyledLabel {
id: root id: root
required property BluetoothDevice device required property BluetoothDevice modelData
RowLayout { RowLayout {
id: row id: row
@ -18,21 +18,21 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: root.device?.icon != undefined active: root.modelData?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 22 implicitSize: 22
source: Quickshell.iconPath(root.device.icon, "device-support-unknown-symbolic") source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: root.device.deviceName text: root.modelData.deviceName
} }
RowLayout { RowLayout {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
StyledButton { StyledButton {
hoverEnabled: root.device.state == BluetoothDeviceState.Disconnected hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected
color: containsMouse ? Theme.palette.primary : Theme.palette.base200 color: containsMouse ? Theme.palette.primary : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Connect' text: 'Connect'
@ -42,12 +42,12 @@ StyledLabel {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
root.device.connect(); root.modelData.connect();
} }
} }
StyledButton { StyledButton {
hoverEnabled: root.device.state == BluetoothDeviceState.Disconnected hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected
color: containsMouse ? Theme.palette.error : Theme.palette.base200 color: containsMouse ? Theme.palette.error : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Unpair' text: 'Unpair'
@ -57,7 +57,7 @@ StyledLabel {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
root.device.forget(); root.modelData.forget();
} }
} }
} }

View file

@ -0,0 +1,16 @@
import QtQuick
ListView {
id: root
maximumFlickVelocity: 3000
rebound: Transition {
NumberAnimation {
properties: "x,y"
duration: 400
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.2, 0, 0, 1, 1, 1]
}
}
}