Expose the shell's remaining UI-only toggles over IPC
Every toggle you could only reach by mouse or panel hotkey is now scriptable through omarchy-shell: - omarchy.bluetooth toggleBluetooth — the radio (was right-click / B) - omarchy.network toggleNetwork — Wi-Fi on/off (was W in the panel) - omarchy.tailscale toggleTailscale — the connection as one call, matching the widget's right-click, instead of separate up/down - omarchy.clock toggleWeekStart — calendar week start (was W) - shell toggleBarTransparency — the bar background (was manage UI only) Bluetooth and network follow the power/monitor pattern: manageIpc: false so the panel owns the target's single IpcHandler and can extend it past the inherited lifecycle methods. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2cff67fa45
commit
f54edbeba8
@@ -100,6 +100,7 @@ individual plugins (`bar`, `image-selector`, …).
|
||||
| `call <id> <method> <arg>` | call an already-loaded plugin |
|
||||
| `rescanPlugins` | re-walk plugin dirs and hot-reload plugin code |
|
||||
| `reloadConfig` | reload shell.json |
|
||||
| `toggleBarTransparency` | flip the bar background between solid and transparent |
|
||||
| `setPluginEnabled <id> <"true"\|…>` | flip enabled bit (`ok` / `unknown`) |
|
||||
| `enablePlugin <id> <placementJson>` | enable and place in one mutation |
|
||||
| `moveBarWidget <id> <placementJson>` | move a configured widget |
|
||||
|
||||
@@ -12,6 +12,9 @@ Panel {
|
||||
id: root
|
||||
moduleName: "omarchy.bluetooth"
|
||||
ipcTarget: "omarchy.bluetooth"
|
||||
// manageIpc: false so this panel can own the single IpcHandler the target
|
||||
// permits — needed for the toggleBluetooth method below.
|
||||
manageIpc: false
|
||||
|
||||
// Address -> "connecting" | "disconnecting" | "forgetting".
|
||||
// The actual Bluetooth sequencing lives in bin/omarchy-bluetooth-device;
|
||||
@@ -515,6 +518,17 @@ Panel {
|
||||
adapter.enabled = !adapter.enabled
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "omarchy.bluetooth"
|
||||
|
||||
function open() { root.open() }
|
||||
function close() { root.close() }
|
||||
function show() { root.open() }
|
||||
function hide() { root.close() }
|
||||
function toggle() { root.toggle() }
|
||||
function toggleBluetooth() { root.toggleBluetooth() }
|
||||
}
|
||||
|
||||
BarIconButton {
|
||||
id: button
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -73,6 +73,10 @@ BarWidget {
|
||||
if (panelLoader.item) panelLoader.item.toggle()
|
||||
}
|
||||
|
||||
function toggleWeekStart() {
|
||||
if (panelLoader.item) panelLoader.item.toggleWeekStart()
|
||||
}
|
||||
|
||||
// The clock fills more slot than it paints a mark for, at both
|
||||
// orientations: horizontally it is a text label in a padded slot, so the
|
||||
// dot takes the label width; vertically it is a stack of icon-sized lines,
|
||||
@@ -127,6 +131,7 @@ BarWidget {
|
||||
|
||||
function refresh(): void { root.broadcast("refresh") }
|
||||
function cycleFormat(): void { root.cycleFormat() }
|
||||
function toggleWeekStart(): void { root.toggleWeekStart() }
|
||||
function open(): void { root.open() }
|
||||
function close(): void { root.close() }
|
||||
function show(): void { root.open() }
|
||||
|
||||
@@ -12,6 +12,9 @@ Panel {
|
||||
id: root
|
||||
moduleName: "omarchy.network"
|
||||
ipcTarget: "omarchy.network"
|
||||
// manageIpc: false so this panel can own the single IpcHandler the target
|
||||
// permits — needed for the toggleNetwork method below.
|
||||
manageIpc: false
|
||||
|
||||
// Centralized close so callers can't forget to drop the passphrase prompt.
|
||||
function close() {
|
||||
@@ -214,6 +217,17 @@ Panel {
|
||||
Qt.callLater(function() { root.refresh(true) })
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "omarchy.network"
|
||||
|
||||
function open() { root.open() }
|
||||
function close() { root.close() }
|
||||
function show() { root.open() }
|
||||
function hide() { root.close() }
|
||||
function toggle() { root.toggle() }
|
||||
function toggleNetwork() { root.toggleNetwork() }
|
||||
}
|
||||
|
||||
function activateHeader() {
|
||||
if (headerIndex === qrHeaderIndex) showWifiQr()
|
||||
else if (headerIndex === toggleHeaderIndex) toggleNetwork()
|
||||
|
||||
@@ -373,6 +373,7 @@ Panel {
|
||||
function refresh(): string { tailscale.refresh(); return "ok" }
|
||||
function up(): string { tailscale.loginOrUp(); return "ok" }
|
||||
function down(): string { tailscale.down(); return "ok" }
|
||||
function toggleTailscale(): string { tailscale.toggleTailscale(); return "ok" }
|
||||
function status(): string { return tailscale.statusText }
|
||||
}
|
||||
|
||||
|
||||
@@ -896,6 +896,14 @@ ShellRoot {
|
||||
return "ok"
|
||||
}
|
||||
|
||||
function toggleBarTransparency(): string {
|
||||
if (shell.bar && typeof shell.bar.toggleTransparency === "function") {
|
||||
shell.bar.toggleTransparency()
|
||||
return "ok"
|
||||
}
|
||||
return "no-bar"
|
||||
}
|
||||
|
||||
function setPluginEnabled(id: string, enabled: string): string {
|
||||
return shell.pluginRegistry.setEnabled(id, enabled === "true") ? "ok" : "unknown"
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ run_node_test <<'JS'
|
||||
const fs = require('fs')
|
||||
const bar = requireFromRoot('shell/plugins/bar/BarModel.js')
|
||||
const barSource = fs.readFileSync(root + '/shell/plugins/bar/Bar.qml', 'utf8')
|
||||
const shellSource = fs.readFileSync(root + '/shell/shell.qml', 'utf8')
|
||||
|
||||
assert(/function toggleBarTransparency\(\): string \{[\s\S]*?shell\.bar\.toggleTransparency\(\)/.test(shellSource), 'shell exposes the bar transparency toggle over IPC')
|
||||
|
||||
// The center section declares two arrangements and shows one; the hidden one
|
||||
// must not build its modules or every center widget exists twice.
|
||||
|
||||
@@ -9,7 +9,12 @@ grep -q '^ConditionPathIsDirectory=/sys/class/bluetooth$' "$ROOT/default/systemd
|
||||
pass "bt-agent is skipped on machines without Bluetooth hardware"
|
||||
|
||||
run_node_test <<'JS'
|
||||
const fs = require('fs')
|
||||
const bluetooth = requireFromRoot('shell/plugins/panels/bluetooth/Model.js')
|
||||
const panelSource = fs.readFileSync(root + '/shell/plugins/panels/bluetooth/Panel.qml', 'utf8')
|
||||
|
||||
assert(/IpcHandler[\s\S]*?function toggleBluetooth\(\) \{ root\.toggleBluetooth\(\) \}/.test(panelSource), 'bluetooth exposes the radio toggle over IPC')
|
||||
assert(/manageIpc: false/.test(panelSource), 'bluetooth owns its IPC handler so it can extend the target methods')
|
||||
|
||||
assert(bluetooth.isUuidLike('0000110b-0000-1000-8000-00805f9b34fb'), 'bluetooth detects UUID-like names')
|
||||
assert(bluetooth.isAddressLike('AA:BB:CC:DD:EE:FF'), 'bluetooth detects address-like names')
|
||||
|
||||
@@ -147,6 +147,7 @@ assert(/ipcTarget: "omarchy\.clock"/.test(panelSource), 'calendar panel register
|
||||
assert(/manageIpc: false/.test(panelSource), 'calendar panel leaves the IPC target to the bar widget')
|
||||
assert(/anchorItem: root\.anchorItem/.test(panelSource), 'calendar panel anchors to the host widget button')
|
||||
assert(/function toggleWeekStart\(\)/.test(panelSource), 'calendar panel exposes a week start toggle')
|
||||
assert(/function toggleWeekStart\(\): void \{ root\.toggleWeekStart\(\) \}/.test(widgetSource), 'clock exposes the week start toggle over IPC')
|
||||
assert(/setting\("weekStartDay", null\)/.test(panelSource) && /persistSettings\(\{ weekStartDay:/.test(panelSource), 'calendar reads and writes the week start as weekStartDay')
|
||||
assert(/updateEntryInline/.test(panelSource), 'calendar panel persists the week start to shell.json')
|
||||
assert(/function moveMonth\(delta\)/.test(panelSource), 'calendar panel steps between months')
|
||||
|
||||
@@ -5,7 +5,12 @@ set -euo pipefail
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
run_node_test <<'JS'
|
||||
const fs = require('fs')
|
||||
const network = requireFromRoot('shell/plugins/panels/network/Model.js')
|
||||
const panelSource = fs.readFileSync(root + '/shell/plugins/panels/network/Panel.qml', 'utf8')
|
||||
|
||||
assert(/IpcHandler[\s\S]*?function toggleNetwork\(\) \{ root\.toggleNetwork\(\) \}/.test(panelSource), 'network exposes the Wi-Fi radio toggle over IPC')
|
||||
assert(/manageIpc: false/.test(panelSource), 'network owns its IPC handler so it can extend the target methods')
|
||||
|
||||
assertDeepEqual(
|
||||
network.parseNetworkStatus('wifi\tCafe WiFi\t78\t5200\n'),
|
||||
|
||||
@@ -5,7 +5,11 @@ set -euo pipefail
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
run_node_test <<'JS'
|
||||
const fs = require('fs')
|
||||
const tailscale = requireFromRoot('shell/plugins/panels/tailscale/Model.js')
|
||||
const panelSource = fs.readFileSync(root + '/shell/plugins/panels/tailscale/Panel.qml', 'utf8')
|
||||
|
||||
assert(/function toggleTailscale\(\): string \{ tailscale\.toggleTailscale\(\); return "ok" \}/.test(panelSource), 'tailscale exposes the connection toggle over IPC')
|
||||
|
||||
assertDeepEqual(
|
||||
tailscale.filterIPv4(['100.64.0.1', 'fd7a:115c:a1e0::1', '192.168.1.2']),
|
||||
|
||||
Reference in New Issue
Block a user