270 lines
13 KiB
Markdown
270 lines
13 KiB
Markdown
# Panama Control Center design
|
|
|
|
## Summary
|
|
|
|
Panama will expand the existing top-right Quick Settings popover into a complete
|
|
Control Center. Wi-Fi, Bluetooth, Focus, Caffeine, Night Light, audio, account,
|
|
settings, and power remain in place. Home Assistant favourites and lightweight
|
|
iPhone continuity join that same surface instead of creating separate windows
|
|
or permanent bar widgets.
|
|
|
|
The approved visual direction is **A · Continuity Card**, integrated into the
|
|
Control Center. The panel keeps Panama's Prism glass and Tokyo Night Moon
|
|
language, grows to 430 logical pixels, and begins two pixels below the bar. Home
|
|
is a first-class control section; KDE Connect is deliberately smaller because
|
|
the paired iPhone exposes only a useful subset of KDE Connect.
|
|
|
|
## Goals
|
|
|
|
- Make the top-right popover feel like a complete desktop Control Center rather
|
|
than a small collection of connectivity toggles.
|
|
- Toggle the existing Home Assistant favourites without opening a browser.
|
|
- Preserve the user's seven enabled Home Assistant lights and use Home
|
|
Assistant friendly names and live states.
|
|
- Show the paired iPhone's real reachability and expose Send File, Send
|
|
Clipboard, and Ring actions.
|
|
- Represent phone transfers in Ongoing while active and as quiet recent
|
|
exchanges after completion.
|
|
- Keep credentials, Home Assistant responses, clipboard contents, and local
|
|
file paths out of Git and shell logs.
|
|
- Leave BlueBubbles as the messaging implementation rather than manufacturing
|
|
an inferior KDE Connect messaging surface.
|
|
|
|
## Non-goals
|
|
|
|
- Panama will not add SMS or iMessage controls. BlueBubbles already owns that
|
|
experience.
|
|
- Panama will not show an iPhone battery percentage until the device reports a
|
|
real value. The current KDE Connect battery interface returns `-1`.
|
|
- Panama will not expose remote input, device locking, remote commands, or phone
|
|
notifications when the paired iPhone does not advertise those capabilities.
|
|
- Panama will not become a full Home Assistant dashboard or entity editor.
|
|
- Panama will not store a Home Assistant token in tracked files, QML, fixtures,
|
|
process arguments, or logs.
|
|
- The first release does not pair or unpair KDE Connect devices inside Panama.
|
|
KDE Connect's own pairing UI remains the safe handoff.
|
|
|
|
## Verified system state
|
|
|
|
KDE Connect currently reports one paired iPhone.
|
|
Its live D-Bus object exposes clipboard, find-my-phone, ping, share, and battery
|
|
plugins. The battery plugin has no value, and the remote-input object exposes no
|
|
callable control methods. Panama must derive action visibility from advertised
|
|
capabilities rather than from generic KDE Connect marketing claims.
|
|
|
|
The existing GNOME Home Assistant extension points to the user's Home Assistant
|
|
instance and has seven enabled light entities: all lights, kitchen lights, two
|
|
individual lights, bedroom, living room, and hall. It stores the long-lived
|
|
access token in Secret Service under `token_string=user_token`; it does not keep
|
|
the token in dconf.
|
|
|
|
## Interaction model
|
|
|
|
Clicking the existing right-side status cluster or pressing `Super+S` opens the
|
|
same Control Center. No new global shortcut is added.
|
|
|
|
The resting panel is ordered by frequency and scope:
|
|
|
|
1. Wi-Fi, Bluetooth, Caffeine, and Night Light toggle grid.
|
|
2. Focus and audio controls.
|
|
3. Home favourites.
|
|
4. Phone continuity.
|
|
5. User, Panama Settings, and power footer.
|
|
|
|
The panel starts two logical pixels beneath the bar instead of using the current
|
|
double bar-gap offset. It stays right-aligned and retains outside-click and
|
|
Escape dismissal. Its content scrolls when an expanded device list exceeds the
|
|
usable monitor height; the layer-shell window itself never extends beyond the
|
|
work area.
|
|
|
|
Only one detail section is expanded at a time. Wi-Fi, Bluetooth, sink, source,
|
|
Home, and Phone all participate in the existing `expandedSection` state so the
|
|
panel remains predictable.
|
|
|
|
## Home section
|
|
|
|
The resting Home card shows the first four enabled favourites in their saved
|
|
order. Each tile contains a domain-appropriate glyph, a friendly name, and a
|
|
plain state such as `On`, `Off`, or `Unavailable`. Enabled lights use a quiet
|
|
amber light treatment; Panama blue remains reserved for desktop selection and
|
|
focus.
|
|
|
|
Clicking a toggleable tile calls Home Assistant and temporarily disables only
|
|
that tile. The state is refreshed from Home Assistant after the request rather
|
|
than being permanently changed optimistically. Success is reflected visually
|
|
without a toast or Signal Glass event. A failure restores the last known state
|
|
and displays a concise inline error inside the Home section.
|
|
|
|
The trailing `N accessories` action expands a full list of configured
|
|
favourites inside the Control Center. No unconfigured Home Assistant entity is
|
|
shown. An `Open Home Assistant` action launches the configured base URL.
|
|
|
|
If Home Assistant is unreachable, Panama retains the last good states for the
|
|
current shell session, marks them stale, and offers Retry. If no URL or token is
|
|
available, the section becomes one setup row rather than disappearing or
|
|
breaking the rest of Control Center.
|
|
|
|
## Phone section
|
|
|
|
The Phone card follows approved mock A at a smaller scale:
|
|
|
|
- device silhouette, friendly name, and `Nearby on Wi-Fi` or `Not nearby`;
|
|
- Send File, Send Clipboard, and Ring as compact icon actions;
|
|
- one recent transfer row only when a real exchange occurred in the current
|
|
shell session; and
|
|
- a Device Settings handoff to Panama Settings connectivity controls.
|
|
|
|
The bar adds a small phone glyph only while at least one paired phone is
|
|
reachable. It is status, not a second click target; the existing status cluster
|
|
continues to open Control Center.
|
|
|
|
Send File opens a graphical file chooser. Confirming a file starts a KDE
|
|
Connect share process. Canceling the chooser has no side effect and produces no
|
|
event. The action accepts regular local files only; URLs and directories are
|
|
not inferred from arbitrary text.
|
|
|
|
Send Clipboard tells KDE Connect to send the current clipboard through its own
|
|
clipboard plugin. Panama never reads, stores, previews, or logs clipboard text
|
|
for this action. Ring invokes find-my-phone only when that plugin is advertised.
|
|
|
|
Phone actions are disabled while the device is unreachable. Connection and
|
|
disconnection remain ambient Status Events under the existing global curation
|
|
policy. A completed transfer may appear as a quiet recent row and an important
|
|
Signal Glass event; canceling or failing a transfer produces a concise warning.
|
|
Ring and clipboard success do not produce global events.
|
|
|
|
## Architecture
|
|
|
|
### KDE Connect service
|
|
|
|
Add `services/KdeConnect.qml` as the shell-facing state owner. It exposes the
|
|
paired devices, preferred phone, reachability, advertised actions, current
|
|
transfer, and recent exchange. It supervises small allow-listed helper
|
|
commands; UI components never assemble shell command strings.
|
|
|
|
Add `scripts/panama-kdeconnect` with a JSON contract:
|
|
|
|
- `status` reports paired devices, reachability, type, and supported actions;
|
|
- `send-file DEVICE FILE` validates a regular file and shares it;
|
|
- `send-clipboard DEVICE` invokes the KDE Connect clipboard plugin; and
|
|
- `ring DEVICE` invokes find-my-phone.
|
|
|
|
The helper uses `kdeconnect-cli` and the session D-Bus service. It emits no
|
|
certificate fingerprints, IP addresses, clipboard contents, or file contents.
|
|
Status refreshes when Control Center opens and on a low-frequency fallback
|
|
timer. The existing `DeviceEvents.qml` reads this service instead of launching
|
|
its own independent KDE Connect probe.
|
|
|
|
Transfer state is contributed to `Ongoing.qml`. A running share shows filename,
|
|
device name, and a Cancel action when the child process can still be stopped.
|
|
No fake percentage is shown because KDE Connect's public CLI does not provide
|
|
reliable byte progress for this device.
|
|
|
|
### Home Assistant bridge
|
|
|
|
Add `scripts/panama-home-assistant`, a small local bridge with four commands:
|
|
|
|
- `probe` reports configuration and API availability without entity details;
|
|
- `snapshot` returns only configured favourites and normalized state;
|
|
- `toggle ENTITY_ID` calls the Home Assistant service for an allow-listed
|
|
configured entity; and
|
|
- `open` launches the configured Home Assistant URL.
|
|
|
|
Configuration resolution is intentionally layered:
|
|
|
|
1. `PANAMA_HOME_ASSISTANT_URL`, `PANAMA_HOME_ASSISTANT_TOKEN`, and optional
|
|
`PANAMA_HOME_ASSISTANT_ENTITIES` from the gitignored `config/bash/env`;
|
|
2. the existing GNOME extension's `hass-url` and enabled-entity dconf values;
|
|
3. the existing Secret Service item with `token_string=user_token`.
|
|
|
|
This preserves the current working setup without copying a token. Explicit
|
|
Panama environment variables can replace the compatibility fallbacks later.
|
|
The bridge sends the token only in the Home Assistant Authorization header and
|
|
redacts request failures before returning them to QML.
|
|
|
|
Add `services/HomeAssistant.qml` to own normalized entities, loading and stale
|
|
state, per-entity busy state, and inline errors. It refreshes when Control
|
|
Center opens, after a toggle, and at a bounded interval while the panel is
|
|
visible. It does not continuously poll while the panel is closed.
|
|
|
|
### Control Center components
|
|
|
|
Keep `QuickSettings.qml` as the only layer-shell window and
|
|
`QuickSettingsPanel.qml` as composition. Add focused presentation components
|
|
under `modules/quicksettings/`:
|
|
|
|
- `ControlSectionHeader.qml` for consistent quiet labels and trailing actions;
|
|
- `HomeControls.qml` and `HomeTile.qml`;
|
|
- `PhoneControls.qml`; and
|
|
- `RecentExchange.qml`.
|
|
|
|
The panel width becomes a named Control Center geometry token rather than
|
|
changing the shared popover width used by unrelated surfaces. Existing Wi-Fi,
|
|
Bluetooth, audio, Focus, Caffeine, Night Light, footer, keyboard focus, and
|
|
outside-click behavior remain intact.
|
|
|
|
## Security and privacy
|
|
|
|
- The existing Secret Service token remains the preferred compatibility
|
|
source; no migration requires printing or copying it.
|
|
- Environment configuration is allowed only in the already gitignored
|
|
`config/bash/env` file.
|
|
- Helpers never echo tokens, Authorization headers, clipboard text, entity
|
|
response bodies, IP addresses, or full local file paths to logs.
|
|
- Home Assistant commands accept only entity IDs present in the configured
|
|
favourites snapshot.
|
|
- KDE Connect device IDs and file paths are passed as separate process
|
|
arguments, never interpolated into a shell command.
|
|
- A user click is required for every Home toggle, phone ring, clipboard send,
|
|
file chooser, and file transfer.
|
|
|
|
## Failure behavior
|
|
|
|
- KDE Connect absent: Phone shows `KDE Connect unavailable` with a Settings
|
|
handoff; Control Center remains usable.
|
|
- Paired phone offline: identity remains visible, actions disable, and no
|
|
repeated disconnect toast is emitted.
|
|
- File chooser canceled: no error and no history entry.
|
|
- Transfer failed: Ongoing clears, recent history does not claim success, and a
|
|
concise warning is shown.
|
|
- Home Assistant unavailable: last good state remains visibly stale and Retry
|
|
is offered.
|
|
- Invalid or expired token: Home shows `Authentication required` without
|
|
exposing the response body.
|
|
- One malformed entity is omitted without suppressing healthy favourites.
|
|
|
|
## Testing and verification
|
|
|
|
Focused automated coverage will prove:
|
|
|
|
1. KDE Connect status normalization and capability filtering through synthetic
|
|
command fixtures.
|
|
2. File validation, allow-listed device actions, canceled chooser behavior, and
|
|
transfer lifecycle without sending a real file.
|
|
3. Home Assistant configuration precedence, response normalization,
|
|
allow-listed toggles, authentication redaction, stale-state retention, and
|
|
malformed-entity isolation against a local fake API.
|
|
4. Control Center structure, exclusive detail expansion, Home/Phone empty and
|
|
failure states, Ongoing contribution, status glyph visibility, and the
|
|
two-pixel top attachment through contract tests.
|
|
5. Fresh Quickshell construction with no QML errors or warnings and valid
|
|
Hyprland configuration.
|
|
6. A live read-only smoke test that reports only the paired/reachable phone
|
|
count, supported-action names, Home Assistant availability, and configured
|
|
entity count.
|
|
7. Visual captures of resting, expanded Home, phone offline, transfer active,
|
|
and Home Assistant failure states.
|
|
|
|
A real Ring, clipboard send, Home light toggle, or file transfer is not part of
|
|
automated verification because each changes an external device. Those final
|
|
checks require an explicit user action from the finished Control Center.
|
|
|
|
## Documentation updates
|
|
|
|
- Update `config/dot/hypr/DESKTOP-PARITY.md` to mark Home Assistant favourites
|
|
and KDE Connect phone integration live.
|
|
- Document Control Center behavior, credential resolution, and iOS limitations
|
|
in `config/dot/hypr/README.md`.
|
|
- Keep BlueBubbles listed as the messaging application and KDE Connect as the
|
|
continuity/file-transfer layer.
|