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 bool isComplete
|
||||
property int outAnimType: Anim.FastEffects
|
||||
property int inAnimType: Anim.DefaultEffects
|
||||
|
||||
asynchronous: true
|
||||
Component.onCompleted: {
|
||||
|
|
@ -25,7 +27,7 @@ Loader {
|
|||
target: root
|
||||
property: "opacity"
|
||||
to: 0
|
||||
type: Anim.FastEffects
|
||||
type: root.outAnimType
|
||||
}
|
||||
ScriptAction {
|
||||
script: root.sourceComponent = root.sourceComp
|
||||
|
|
@ -34,7 +36,7 @@ Loader {
|
|||
target: root
|
||||
property: "opacity"
|
||||
to: 1
|
||||
type: Anim.DefaultEffects
|
||||
type: root.inAnimType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Bluetooth
|
||||
|
||||
QtObject {
|
||||
property ShellScreen screen
|
||||
|
|
@ -9,6 +10,7 @@ QtObject {
|
|||
property bool searchOpen
|
||||
|
||||
property string selectedWallpaperCategory
|
||||
property BluetoothDevice selectedBtDevice
|
||||
|
||||
signal close
|
||||
signal subPageOpened(idx: int)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ pragma Singleton
|
|||
import QtQuick
|
||||
import qs.modules.nexus.common
|
||||
import qs.modules.nexus.pages
|
||||
import qs.modules.nexus.pages.bluetooth
|
||||
import qs.modules.nexus.pages.wallandstyle
|
||||
|
||||
QtObject {
|
||||
|
|
@ -43,6 +44,9 @@ QtObject {
|
|||
Component {
|
||||
BluetoothPage {}
|
||||
}
|
||||
Component {
|
||||
BtDeviceInfo {}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -155,7 +155,10 @@ PageBase {
|
|||
inactiveOnColour: device.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||
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