feat: add nexus bluetooth device page
This commit is contained in:
parent
7489d369fb
commit
76b64ca214
5 changed files with 274 additions and 3 deletions
|
|
@ -5,6 +5,8 @@ Loader {
|
||||||
|
|
||||||
property Component sourceComp
|
property Component sourceComp
|
||||||
property bool isComplete
|
property bool isComplete
|
||||||
|
property int outAnimType: Anim.FastEffects
|
||||||
|
property int inAnimType: Anim.DefaultEffects
|
||||||
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
@ -25,7 +27,7 @@ Loader {
|
||||||
target: root
|
target: root
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
to: 0
|
to: 0
|
||||||
type: Anim.FastEffects
|
type: root.outAnimType
|
||||||
}
|
}
|
||||||
ScriptAction {
|
ScriptAction {
|
||||||
script: root.sourceComponent = root.sourceComp
|
script: root.sourceComponent = root.sourceComp
|
||||||
|
|
@ -34,7 +36,7 @@ Loader {
|
||||||
target: root
|
target: root
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
to: 1
|
to: 1
|
||||||
type: Anim.DefaultEffects
|
type: root.inAnimType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
|
|
@ -9,6 +10,7 @@ QtObject {
|
||||||
property bool searchOpen
|
property bool searchOpen
|
||||||
|
|
||||||
property string selectedWallpaperCategory
|
property string selectedWallpaperCategory
|
||||||
|
property BluetoothDevice selectedBtDevice
|
||||||
|
|
||||||
signal close
|
signal close
|
||||||
signal subPageOpened(idx: int)
|
signal subPageOpened(idx: int)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ pragma Singleton
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.modules.nexus.common
|
import qs.modules.nexus.common
|
||||||
import qs.modules.nexus.pages
|
import qs.modules.nexus.pages
|
||||||
|
import qs.modules.nexus.pages.bluetooth
|
||||||
import qs.modules.nexus.pages.wallandstyle
|
import qs.modules.nexus.pages.wallandstyle
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
|
@ -43,6 +44,9 @@ QtObject {
|
||||||
Component {
|
Component {
|
||||||
BluetoothPage {}
|
BluetoothPage {}
|
||||||
}
|
}
|
||||||
|
Component {
|
||||||
|
BtDeviceInfo {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,10 @@ PageBase {
|
||||||
inactiveOnColour: device.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
inactiveOnColour: device.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||||
label.fill: 0
|
label.fill: 0
|
||||||
|
|
||||||
onClicked: ; // TODO
|
onClicked: {
|
||||||
|
root.nState.selectedBtDevice = device.modelData;
|
||||||
|
root.nState.openSubPage(1); // Per device info page
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
260
modules/nexus/pages/bluetooth/BtDeviceInfo.qml
Normal file
260
modules/nexus/pages/bluetooth/BtDeviceInfo.qml
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
import Caelestia.Components
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.components.controls
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.nexus.common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property BluetoothDevice device: nState.selectedBtDevice
|
||||||
|
readonly property bool connected: device?.state === BluetoothDeviceState.Connected // qmllint disable unresolved-type
|
||||||
|
readonly property bool loading: device?.state === BluetoothDeviceState.Connecting || device?.state === BluetoothDeviceState.Disconnecting // qmllint disable unresolved-type
|
||||||
|
|
||||||
|
readonly property string statusText: {
|
||||||
|
if (!device)
|
||||||
|
return "";
|
||||||
|
let s = connected ? qsTr("Connected") : (device.bonded ? qsTr("Paired") : qsTr("Not paired"));
|
||||||
|
if (connected && device.batteryAvailable)
|
||||||
|
s += " • " + Math.round(device.battery * 100) + "%";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeviceChanged: {
|
||||||
|
// Auto close when device lost
|
||||||
|
if (!device)
|
||||||
|
nState.closeSubPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
title: device?.name ?? qsTr("Device")
|
||||||
|
isSubPage: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: root.cappedWidth
|
||||||
|
spacing: Tokens.spacing.extraSmall / 2
|
||||||
|
|
||||||
|
// Big buttons
|
||||||
|
ButtonRow {
|
||||||
|
Layout.bottomMargin: Tokens.spacing.large - parent.spacing
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.minimumWidth: Math.round(root.cappedWidth * 0.7)
|
||||||
|
spacing: Tokens.spacing.small
|
||||||
|
|
||||||
|
ButtonBase {
|
||||||
|
id: forgetBtn
|
||||||
|
|
||||||
|
fillWidth: true
|
||||||
|
shapeMorph: true
|
||||||
|
isRound: true
|
||||||
|
|
||||||
|
inactiveColour: Colours.palette.m3errorContainer
|
||||||
|
inactiveOnColour: Colours.palette.m3onErrorContainer
|
||||||
|
|
||||||
|
implicitWidth: forgetBtnLayout.implicitWidth + Tokens.padding.extraLarge * 2
|
||||||
|
implicitHeight: forgetBtnLayout.implicitHeight + Tokens.padding.medium * 2
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.device?.forget();
|
||||||
|
root.nState.closeSubPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: forgetBtnLayout
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: "delete"
|
||||||
|
color: forgetBtn.onColour
|
||||||
|
font: Tokens.font.icon.medium
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Forget")
|
||||||
|
color: forgetBtn.onColour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonBase {
|
||||||
|
id: connectBtn
|
||||||
|
|
||||||
|
fillWidth: true
|
||||||
|
shapeMorph: true
|
||||||
|
isRound: true
|
||||||
|
|
||||||
|
inactiveColour: Colours.palette.m3primaryContainer
|
||||||
|
inactiveOnColour: Colours.palette.m3onPrimaryContainer
|
||||||
|
stateLayer.disabled: root.loading
|
||||||
|
|
||||||
|
implicitWidth: connectBtnContent.implicitWidth + Tokens.padding.extraLarge * 2
|
||||||
|
implicitHeight: connectBtnContent.implicitHeight + Tokens.padding.medium * 2
|
||||||
|
|
||||||
|
onClicked: root.device.connected = !root.connected
|
||||||
|
|
||||||
|
AnimLoader {
|
||||||
|
id: connectBtnContent
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
sourceComp: root.loading ? loadingComp : textComp
|
||||||
|
outAnimType: Anim.SlowEffects
|
||||||
|
inAnimType: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loadingComp
|
||||||
|
|
||||||
|
LoadingIndicator {
|
||||||
|
implicitSize: connectBtn.height - Tokens.padding.large * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: textComp
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: root.connected ? "close" : "add"
|
||||||
|
color: connectBtn.inactiveOnColour
|
||||||
|
font: Tokens.font.icon.medium
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: root.connected ? qsTr("Disconnect") : qsTr("Connect")
|
||||||
|
color: connectBtn.inactiveOnColour
|
||||||
|
animate: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection group
|
||||||
|
ToggleRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
verticalPadding: Tokens.padding.large
|
||||||
|
first: true
|
||||||
|
text: qsTr("Trusted")
|
||||||
|
subtext: qsTr("Allow this device to connect automatically")
|
||||||
|
checked: root.device?.trusted ?? false
|
||||||
|
onToggled: {
|
||||||
|
if (root.device)
|
||||||
|
root.device.trusted = checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
verticalPadding: Tokens.padding.large
|
||||||
|
text: qsTr("Blocked")
|
||||||
|
subtext: qsTr("Prevent this device from connecting")
|
||||||
|
checked: root.device?.blocked ?? false
|
||||||
|
onToggled: {
|
||||||
|
if (root.device)
|
||||||
|
root.device.blocked = checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
verticalPadding: Tokens.padding.large
|
||||||
|
last: true
|
||||||
|
text: qsTr("Wake allowed")
|
||||||
|
subtext: qsTr("Allow this device to wake the system")
|
||||||
|
checked: root.device?.wakeAllowed ?? false
|
||||||
|
onToggled: {
|
||||||
|
if (root.device)
|
||||||
|
root.device.wakeAllowed = checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Information
|
||||||
|
ConnectedRect {
|
||||||
|
Layout.topMargin: Tokens.spacing.large - parent.spacing
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: batteryLayout.implicitHeight + Tokens.padding.large * 2
|
||||||
|
first: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: batteryLayout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: Tokens.padding.large
|
||||||
|
spacing: Tokens.spacing.small
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Tokens.spacing.medium
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("Battery")
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.device?.batteryAvailable ? Math.round(root.device.battery * 100) + "%" : qsTr("Unavailable")
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
active: root.device?.batteryAvailable ?? false
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: StyledProgressBar {
|
||||||
|
implicitHeight: Tokens.padding.medium
|
||||||
|
value: root.device.battery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: addrLayout.implicitHeight + Tokens.padding.large * 2
|
||||||
|
last: true
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: addrLayout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: Tokens.padding.large
|
||||||
|
spacing: Tokens.spacing.medium
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("Address")
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.device?.address ?? ""
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue