Feature: Extra functionablity to bluetooth actions
This commit is contained in:
@@ -127,6 +127,11 @@ Item {
|
||||
d.forget()
|
||||
}
|
||||
|
||||
function setTrusted(row, trusted) {
|
||||
const d = root.deviceForAddress(row.address)
|
||||
if (d) d.trusted = trusted
|
||||
}
|
||||
|
||||
readonly property bool anyConnected: root.connectedRows.length > 0
|
||||
|
||||
// Caps how tall the Paired/Available list gets before it scrolls
|
||||
@@ -203,8 +208,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// One device row. `showForget` hides the forget (x) button for
|
||||
// discovered-but-unpaired devices, which have nothing to forget yet.
|
||||
// One device row. `showForget` gates the whole trailing action cluster —
|
||||
// trust toggle, disconnect, forget — for discovered-but-unpaired devices,
|
||||
// which have none of those to act on yet (a plain click there pairs
|
||||
// instead, via activate()). For a paired/connected row, the row body
|
||||
// itself still connects/disconnects (activate()) same as before; the
|
||||
// actions below are the explicit, discoverable versions of that plus
|
||||
// the two this row previously had no way to reach at all.
|
||||
component DeviceRow: Rectangle {
|
||||
id: devRow
|
||||
required property var dev
|
||||
@@ -213,6 +223,27 @@ Item {
|
||||
width: parent ? parent.width : 0
|
||||
radius: 0
|
||||
implicitHeight: rowContent.implicitHeight + 12
|
||||
|
||||
// Which action icon (if any) the pointer is currently over — drives
|
||||
// both that icon's own hover color below and rowMouse's click
|
||||
// dispatch. Derived from rowMouse.mouseX/containsMouse rather than a
|
||||
// MouseArea on each icon: those icons live inside rowContent, which
|
||||
// sits underneath rowMouse in stacking order, so a nested MouseArea
|
||||
// there would just be shadowed by it (same reason
|
||||
// NetworkIndicator.qml's NetworkRow dispatches by position too).
|
||||
// Checked right-to-left since that's the order the icons are laid
|
||||
// out in, so an earlier icon's "from here to the row's right edge"
|
||||
// zone doesn't swallow the ones after it.
|
||||
readonly property string hoveredAction: {
|
||||
if (!rowMouse.containsMouse) return ""
|
||||
if (devRow.showForget && forgetIcon.visible
|
||||
&& rowMouse.mouseX >= devRow.mapFromItem(forgetIcon, 0, 0).x - 8) return "forget"
|
||||
if (devRow.showForget && trustIcon.visible
|
||||
&& rowMouse.mouseX >= devRow.mapFromItem(trustIcon, 0, 0).x - 8) return "trust"
|
||||
if (disconnectIcon.visible
|
||||
&& rowMouse.mouseX >= devRow.mapFromItem(disconnectIcon, 0, 0).x - 8) return "disconnect"
|
||||
return ""
|
||||
}
|
||||
// Hover checked first (same ordering as Volume.qml's DeviceRow):
|
||||
// hovering always shows a solid Colors.primary fill, even for an
|
||||
// already-connected row, so the primaryText used below never has to
|
||||
@@ -283,9 +314,91 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Each action below is a fixed-size slot with its own
|
||||
// hover-halo outline — offset outside the slot rather than drawn
|
||||
// on its own edge, same treatment as devRow's own outline above
|
||||
// and every other hoverable box in this file (ToggleSwitch,
|
||||
// DeviceRow itself, etc.) — instead of just the color swap the
|
||||
// row's own icons get.
|
||||
|
||||
// Disconnect without forgetting — same effect as clicking the
|
||||
// row body on a Connected row (activate() below calls
|
||||
// disconnectDevice too), just given its own explicit, always-
|
||||
// visible icon instead of relying on that being guessed.
|
||||
Item {
|
||||
id: disconnectIcon
|
||||
visible: devRow.showForget && devRow.dev.connected
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -3
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
border.color: Colors.foreground
|
||||
border.width: devRow.hoveredAction === "disconnect" ? 1 : 0
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "link_off"
|
||||
font.family: Appearance.iconFontFamilyRounded
|
||||
font.variableAxes: Appearance.iconFontAxes
|
||||
font.pixelSize: 14
|
||||
// Stays primaryText (dark) rather than switching to
|
||||
// Colors.primary while targeted — devRow's own fill is
|
||||
// already Colors.primary on hover, so that would've put
|
||||
// a primary-colored glyph on a primary-colored
|
||||
// background. The outline Rectangle above is what shows
|
||||
// which slot is targeted.
|
||||
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||
}
|
||||
}
|
||||
|
||||
// Trust toggle — full brightness when trusted, dimmed when not,
|
||||
// same "state via opacity" convention PowerButton.qml uses for
|
||||
// its disabled entries.
|
||||
Item {
|
||||
id: trustIcon
|
||||
visible: devRow.showForget
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -3
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
border.color: Colors.foreground
|
||||
border.width: devRow.hoveredAction === "trust" ? 1 : 0
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "verified_user"
|
||||
opacity: devRow.dev.trusted ? 1 : 0.4
|
||||
font.family: Appearance.iconFontFamilyRounded
|
||||
font.variableAxes: Appearance.iconFontAxes
|
||||
font.pixelSize: 14
|
||||
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: forgetIcon
|
||||
visible: devRow.showForget
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -3
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
border.color: Colors.foreground
|
||||
border.width: devRow.hoveredAction === "forget" ? 1 : 0
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "close"
|
||||
font.family: Appearance.iconFontFamilyRounded
|
||||
font.variableAxes: Appearance.iconFontAxes
|
||||
@@ -293,6 +406,7 @@ Item {
|
||||
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: rowMouse
|
||||
@@ -302,22 +416,16 @@ Item {
|
||||
height: rowContent.height + 12
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
// forgetIcon has no MouseArea of its own — nested inside
|
||||
// rowContent, which sits underneath this full-row area in
|
||||
// stacking order, so a separate MouseArea there would just be
|
||||
// shadowed (see the identical fix in NetworkIndicator.qml's
|
||||
// NetworkRow). Dispatch by click position against this single
|
||||
// area instead.
|
||||
onClicked: (mouse) => {
|
||||
if (devRow.showForget && forgetIcon.visible) {
|
||||
const forgetLeft = devRow.mapFromItem(forgetIcon, 0, 0).x
|
||||
if (mouse.x >= forgetLeft - 8) {
|
||||
root.forgetDevice(devRow.dev)
|
||||
return
|
||||
// Dispatches on devRow.hoveredAction rather than its own
|
||||
// MouseArea per icon — see that property's comment above.
|
||||
onClicked: {
|
||||
switch (devRow.hoveredAction) {
|
||||
case "forget": root.forgetDevice(devRow.dev); break
|
||||
case "trust": root.setTrusted(devRow.dev, !devRow.dev.trusted); break
|
||||
case "disconnect": root.disconnectDevice(devRow.dev); break
|
||||
default: devRow.activate()
|
||||
}
|
||||
}
|
||||
devRow.activate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +435,11 @@ Item {
|
||||
id: panel
|
||||
visible: false
|
||||
color: "transparent"
|
||||
readonly property int contentWidth: 244
|
||||
// Wider than the other panels' usual 244 — each device row now ends
|
||||
// in a row of three 20px action slots (disconnect/trust/forget)
|
||||
// instead of a single close icon, and the name column needs room to
|
||||
// not immediately start eliding against that.
|
||||
readonly property int contentWidth: 300
|
||||
readonly property int contentPadding: 16
|
||||
implicitWidth: contentWidth + contentPadding * 2
|
||||
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
||||
@@ -470,6 +582,42 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Paired — always shown in full, same as Connected above and
|
||||
// for the same reason: these are one click away from
|
||||
// reconnecting (root.connectDevice reconnects rather than
|
||||
// re-pairing whenever a row is already paired/bonded/trusted),
|
||||
// so they shouldn't be buried in the capped-height scroll area
|
||||
// below or hidden behind an active scan turning up other
|
||||
// nearby devices.
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 4
|
||||
visible: root.knownRows.length > 0
|
||||
|
||||
Text {
|
||||
text: "Paired Devices"
|
||||
font.family: Appearance.fontFamily
|
||||
font.pixelSize: Appearance.fontSizeSmall
|
||||
color: Colors.muted
|
||||
}
|
||||
Column {
|
||||
// Inset 3px on each side to match deviceListColumn
|
||||
// below, so DeviceRow's hover halo has room here too.
|
||||
x: 3
|
||||
width: parent.width - 6
|
||||
spacing: 2
|
||||
Repeater {
|
||||
model: root.knownRows
|
||||
DeviceRow {
|
||||
required property var modelData
|
||||
dev: modelData
|
||||
showForget: true
|
||||
onActivate: root.connectDevice(dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
visible: root.adapter !== null && root.adapter.enabled && root.deviceRows.length === 0
|
||||
@@ -479,9 +627,9 @@ Item {
|
||||
color: Colors.muted
|
||||
}
|
||||
|
||||
// Paired/Available — capped height, scrolls once there are
|
||||
// more devices than fit rather than growing the popup
|
||||
// indefinitely.
|
||||
// Available — freshly discovered, unpaired devices only.
|
||||
// Capped height, scrolls once there are more than fit rather
|
||||
// than growing the popup indefinitely.
|
||||
Flickable {
|
||||
id: deviceListFlick
|
||||
width: parent.width
|
||||
@@ -507,32 +655,6 @@ Item {
|
||||
bottomPadding: 3
|
||||
spacing: 6
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 4
|
||||
visible: root.knownRows.length > 0
|
||||
|
||||
Text {
|
||||
text: "Paired Devices"
|
||||
font.family: Appearance.fontFamily
|
||||
font.pixelSize: Appearance.fontSizeSmall
|
||||
color: Colors.muted
|
||||
}
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 2
|
||||
Repeater {
|
||||
model: root.knownRows
|
||||
DeviceRow {
|
||||
required property var modelData
|
||||
dev: modelData
|
||||
showForget: true
|
||||
onActivate: root.connectDevice(dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 4
|
||||
|
||||
Reference in New Issue
Block a user