Add BlueBubbles to Phone controls
This commit is contained in:
@@ -10,11 +10,14 @@ Item {
|
|||||||
signal toggleExpanded
|
signal toggleExpanded
|
||||||
|
|
||||||
readonly property var phone: KdeConnect.preferredPhone
|
readonly property var phone: KdeConnect.preferredPhone
|
||||||
|
// Keep the four slots stable. The KDE actions can become unavailable when
|
||||||
|
// the phone disconnects, but the layout should not shift beneath Messages.
|
||||||
readonly property var actionModels: [
|
readonly property var actionModels: [
|
||||||
{ id: "share", glyph: "\u{F0142}", label: "Send file" },
|
{ id: "share", glyph: "\u{F0142}", label: "Send file" },
|
||||||
{ id: "clipboard", glyph: "\u{F014C}", label: "Clipboard" },
|
{ id: "clipboard", glyph: "\u{F014C}", label: "Clipboard" },
|
||||||
{ id: "ring", glyph: "\u{F009A}", label: "Ring" }
|
{ id: "ring", glyph: "\u{F009A}", label: "Ring" },
|
||||||
].filter(item => KdeConnect.supports(item.id))
|
{ id: "messages", glyph: "\u{F0365}", label: "Messages" }
|
||||||
|
]
|
||||||
|
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
|
|
||||||
@@ -120,9 +123,8 @@ Item {
|
|||||||
Grid {
|
Grid {
|
||||||
id: actionsGrid
|
id: actionsGrid
|
||||||
width: parent.width
|
width: parent.width
|
||||||
columns: Math.max(1, root.actionModels.length)
|
columns: 4
|
||||||
spacing: 7
|
spacing: 7
|
||||||
visible: root.actionModels.length > 0
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.actionModels
|
model: root.actionModels
|
||||||
@@ -160,10 +162,17 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
id: actionMouse
|
id: actionMouse
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: KdeConnect.phoneReachable && !KdeConnect.transferActive
|
enabled: actionButton.modelData.id === "messages"
|
||||||
|
? SystemSettings.bluebubblesAvailable
|
||||||
|
: KdeConnect.phoneReachable
|
||||||
|
&& !KdeConnect.transferActive
|
||||||
|
&& KdeConnect.supports(actionButton.modelData.id)
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
activeFocusOnTab: enabled
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
onClicked: root.invoke(actionButton.modelData.id)
|
onClicked: root.invoke(actionButton.modelData.id)
|
||||||
|
Keys.onReturnPressed: root.invoke(actionButton.modelData.id)
|
||||||
|
Keys.onSpacePressed: root.invoke(actionButton.modelData.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +188,16 @@ Item {
|
|||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
visible: !SystemSettings.bluebubblesAvailable
|
||||||
|
text: "BlueBubbles is not installed"
|
||||||
|
color: Theme.fgMuted
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: KdeConnect.lastError !== ""
|
visible: KdeConnect.lastError !== ""
|
||||||
@@ -254,6 +273,10 @@ Item {
|
|||||||
KdeConnect.sendClipboard();
|
KdeConnect.sendClipboard();
|
||||||
else if (action === "ring")
|
else if (action === "ring")
|
||||||
KdeConnect.ring();
|
KdeConnect.ring();
|
||||||
|
else if (action === "messages") {
|
||||||
|
if (SystemSettings.bluebubblesAvailable && SystemSettings.openApplication("bluebubbles"))
|
||||||
|
ShellState.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function localPath(selectedUrl: url): string {
|
function localPath(selectedUrl: url): string {
|
||||||
|
|||||||
@@ -90,6 +90,18 @@ for component in ControlSectionHeader HomeBrightnessSlider HomeControls HomeTile
|
|||||||
|| fail "$component is missing"
|
|| fail "$component is missing"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
[[ "$(rg -c 'id: "(share|clipboard|ring|messages)"' "$quicksettings_path/PhoneControls.qml")" -eq 4 ]] \
|
||||||
|
|| fail 'Phone controls do not expose four stable action models'
|
||||||
|
rg -Fq 'columns: 4' "$quicksettings_path/PhoneControls.qml" \
|
||||||
|
|| fail 'Phone actions are not arranged in four equal columns'
|
||||||
|
if rg -Fq '.filter(' "$quicksettings_path/PhoneControls.qml"; then
|
||||||
|
fail 'Phone action columns change when a KDE capability is unavailable'
|
||||||
|
fi
|
||||||
|
rg -Fq 'SystemSettings.bluebubblesAvailable' "$quicksettings_path/PhoneControls.qml" \
|
||||||
|
|| fail 'Messages action is not independently enabled by BlueBubbles'
|
||||||
|
rg -Fq 'KdeConnect.phoneReachable' "$quicksettings_path/PhoneControls.qml" \
|
||||||
|
|| fail 'KDE action reachability behavior is missing'
|
||||||
|
|
||||||
[[ -f "$quicksettings_path/qmldir" ]] \
|
[[ -f "$quicksettings_path/qmldir" ]] \
|
||||||
|| fail 'quick-settings module manifest is missing'
|
|| fail 'quick-settings module manifest is missing'
|
||||||
rg -Fq 'HomeBrightnessSlider 1.0 HomeBrightnessSlider.qml' \
|
rg -Fq 'HomeBrightnessSlider 1.0 HomeBrightnessSlider.qml' \
|
||||||
|
|||||||
Executable
+58
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
phone_controls="$project_root/config/dot/quickshell/modules/quicksettings/PhoneControls.qml"
|
||||||
|
system_settings="$project_root/config/dot/quickshell/services/SystemSettings.qml"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf 'Phone Messages contract: %s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -f "$phone_controls" ]] || fail 'Phone controls component is missing'
|
||||||
|
[[ -f "$system_settings" ]] || fail 'System settings service is missing'
|
||||||
|
|
||||||
|
# This is a static contract only: it starts no shell, sends no IPC, and never
|
||||||
|
# evaluates the launch branch. Its only Flatpak use is source-text inspection.
|
||||||
|
|
||||||
|
rg -Fq '"bluebubbles": ["flatpak", "run", "app.bluebubbles.BlueBubbles"]' "$system_settings" \
|
||||||
|
|| fail 'BlueBubbles does not use the fixed Flatpak argument vector'
|
||||||
|
rg -Fq 'readonly property bool bluebubblesAvailable: root.bluebubblesDetected' "$system_settings" \
|
||||||
|
|| fail 'BlueBubbles availability is not exposed independently'
|
||||||
|
rg -Fq 'command: ["flatpak", "info", "app.bluebubbles.BlueBubbles"]' "$system_settings" \
|
||||||
|
|| fail 'BlueBubbles installed-state probe is missing'
|
||||||
|
|
||||||
|
for action in share clipboard ring messages; do
|
||||||
|
rg -Fq "id: \"$action\"" "$phone_controls" \
|
||||||
|
|| fail "Phone actions do not include $action"
|
||||||
|
done
|
||||||
|
|
||||||
|
if rg -Fq '.filter(' "$phone_controls"; then
|
||||||
|
fail 'Phone actions are filtered instead of keeping four stable columns'
|
||||||
|
fi
|
||||||
|
rg -Fq 'columns: 4' "$phone_controls" \
|
||||||
|
|| fail 'Phone actions do not use four equal columns'
|
||||||
|
rg -Fq 'root.actionModels.length - 1' "$phone_controls" \
|
||||||
|
|| fail 'Phone action widths are not calculated from the fixed model count'
|
||||||
|
rg -Fq 'SystemSettings.bluebubblesAvailable' "$phone_controls" \
|
||||||
|
|| fail 'Messages enablement does not read BlueBubbles availability'
|
||||||
|
rg -Fq 'KdeConnect.phoneReachable' "$phone_controls" \
|
||||||
|
|| fail 'KDE action reachability semantics are missing'
|
||||||
|
rg -Fq 'KdeConnect.supports(actionButton.modelData.id)' "$phone_controls" \
|
||||||
|
|| fail 'KDE action capability semantics are missing'
|
||||||
|
rg -Fq 'else if (action === "messages")' "$phone_controls" \
|
||||||
|
|| fail 'Messages has no independent invocation branch'
|
||||||
|
rg -Fq 'SystemSettings.openApplication("bluebubbles")' "$phone_controls" \
|
||||||
|
|| fail 'Messages does not use the allow-listed BlueBubbles launcher'
|
||||||
|
rg -Fq 'BlueBubbles is not installed' "$phone_controls" \
|
||||||
|
|| fail 'Missing BlueBubbles has no quiet explanatory row'
|
||||||
|
|
||||||
|
# A static negative guard keeps the Messages branch from accidentally inheriting
|
||||||
|
# KDE Connect reachability, transfer, or plugin conditions.
|
||||||
|
messages_branch="$(sed -n '/else if (action === "messages")/,/^ }/p' "$phone_controls")"
|
||||||
|
printf '%s\n' "$messages_branch" | rg -Fq 'KdeConnect.' \
|
||||||
|
&& fail 'Messages is coupled to KDE Connect'
|
||||||
|
|
||||||
|
printf 'Phone Messages contract: PASS\n'
|
||||||
Reference in New Issue
Block a user