Merge Home & Phone into a three-tab Home that knows your house

Home is now Overview | My Home | Phone. Overview leads with quick-action
tiles (focus, Do Not Disturb, health, snapshots, storage), keeps the
findings card — updates fold in, the reclaim-space prompt is gone on
purpose — and adds glance cards, the next calendar event, and weather.

My Home groups every light by Home Assistant area: the helper gained an
`areas` command (one REST template render, no websocket), and the rooms
degrade to a flat list on setups without areas. The favorites editor and
connection card moved intact. Phone gains a vitals strip — battery and
cell signal read from KDE Connect's plugin D-Bus objects, where absence
is data, not an error — beside ring, clipboard, send-a-file, and the
BlueBubbles handoff.

The retired home-phone id resolves to my-home forever via a new alias
map in SettingsRoutes (with a hasOwnProperty guard so prototype names
cannot leak into settingsPage). Storage no longer claims 0 B free — the
old page read a field the disks helper never emitted.

Contracts updated alongside; per the new workflow, the full suite runs
once at the end of the redesign (see the test backlog note).

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-23 22:06:18 -04:00
parent 5490fd285d
commit 7578348db1
40 changed files with 2578 additions and 703 deletions
+1 -1
View File
@@ -345,7 +345,7 @@ Found on **Appearance**.
## weather
Found on **Home**.
Found on **Home Overview**.
| Setting | Default | What it does |
|---|---|---|
@@ -0,0 +1,109 @@
# Home category redesign — Overview | My Home | Phone
Approved 2026-08-23 (mock B, "Rooms & Tabs"). Home absorbs Home & Phone and becomes a
three-tab category. Phase-2 feature picks: rooms grouping, phone vitals, Today card.
The reclaim-space prompt is removed. Deferred with reserved slots: Assist command box,
phone notification inbox, scenes/climate/cameras, now-playing, HA todos.
## Taxonomy
`SettingsRoutes` home category gains tabs; the `home-phone` category is deleted:
```
{ page: "home", label: "Home", tabs: [
{ page: "home", label: "Overview" },
{ page: "my-home", label: "My Home" },
{ page: "phone", label: "Phone" }
] }
```
`home` doubles as category id and first tab (the applications/users/privacy pattern).
New leaf ids `my-home`, `phone`. A new alias map in `SettingsRoutes.resolve()` sends
the retired `home-phone` id to `my-home` so muscle memory, old Vicinae commands, and
`panama-action settings-page home-phone` keep landing correctly. In-repo callers are
updated to the new ids anyway: `HomeControls.qml`, `panama-doctor`'s HA-warning target,
`Health.qml`'s `settingsTargets`.
## Pages
**HomePage.qml (Overview) — rebuilt.** Greeting header and weather lede stay. Then:
- A five-tile quick-action grid (new `HomeQuickTile.qml`): Focus session (start/end),
Do Not Disturb (live toggle state), Health (→ `services`), Snapshots (→ `snapshots`),
Storage (→ `storage`). Fixed set, per the phase decision.
- "This machine": the existing findings array unchanged (firewall exposure, security
advisories, reboot-needed, health attention) plus the "Install N updates" row folded
in as a finding when `Updates.total > 0`. The reclaim-space row is gone entirely.
- Two glance cards linking into the sibling tabs: My Home ("2 lights on · Living Room,
Kitchen") and Phone ("iPhone · 82% · nearby"), each `openSettings("my-home"/"phone")`.
- "Today": `CalendarAgenda.nextEvent` with Join/Open; hidden when nothing upcoming or
no calendar. Zero new plumbing — the service already streams.
- "Weather": the existing card, unchanged.
- The old Focus card and "Right now" containers card are retired (tiles and the System
category cover them).
**MyHomePage.qml (new, `objectName: "my-home-page"`).** Absorbs the Home-Assistant half
of HomePhonePage:
- "Rooms" card: every catalog light grouped by HA area, rendered as interactive tiles
(new `HomeLightTile.qml`: power square, name, state, brightness track for dimmables,
"Control Center" pill on the first four favorites). Toggle → `HomeAssistant.toggleEntity`,
brightness → `setBrightness` (commit-on-release, like `HomeBrightnessSlider`). Falls
back to a single flat "Lights" section when areas are unavailable.
- "Accessories" card: the existing favorites editor (`HomeFavoriteCard` grid — alias,
reorder, remove, Control Center badge) and the existing Available-lights search
(`AvailableLightRow`), moved intact.
- "Home Assistant" card: the existing connection card (URL, token, save/clear, refresh,
open) moved intact.
- Exposes `pageDiagnostics` (same shape as HomePhonePage's plus `rooms` summary);
the IPC key in `settings status` renames `homePhone``myHome`.
**PhonePage.qml (new, `objectName: "phone-page"`).**
- Vitals strip: three stat blocks — Battery (% + charging), Signal (type + strength),
Reachability — from the extended KdeConnect service. A stat whose datum is absent
(unpaired, plugin missing) shows an em-dash, never an error.
- "Reach it" card: Ring, Send clipboard, Send file (FileDialog, the quicksettings
pattern) via existing service functions; transfer progress/cancel as in Control Center.
- "Messages" card: BlueBubbles status + open (moved from HomePhonePage).
- "Device" card: pairing/plugins handoff to `connectivity` (as Control Center does).
`HomePhonePage.qml` is deleted. `HomeFavoriteCard`/`AvailableLightRow` survive under
MyHomePage.
## Service contracts (pages are written against these; helpers implement them)
**`panama-home-assistant areas` (new command).** REST-only: `POST /api/template`
rendering a Jinja template that emits `[{ "id", "name", "entities": [...] }]` via
`areas()` / `area_name()` / `area_entities()` / `tojson`. Same redacted error codes as
the other commands. `HomeAssistant.qml` gains `areas: []` (fetched with refresh) and
`rooms: [{ id, name, lights: [entity] }]` — catalog lights joined to areas, un-areaed
lights in a trailing "Other" bucket; empty `areas``rooms` is one unnamed bucket.
**`panama-kdeconnect status` (extended).** Per reachable paired device, read via
`busctl get-property` from the plugin objects (paths exist only when paired+reachable —
absence is data, not an error): `battery: { charge: int, charging: bool } | null` from
`org.kde.kdeconnect.device.battery`, `signal: { networkType: string, strength: 0-4 } | null`
from `...device.connectivity_report`. `KdeConnect.qml` surfaces `phoneBattery`,
`phoneSignal` (null when absent). Unit tests extend the two bridge test files' fake
busctl/CLI fixtures.
## Blast radius owned by this change
- `SettingsShell.qml`: `my-home`/`phone` cases + components; `homePhoneDiagnostics`
plumbing renamed and repointed at MyHomePage (`SettingsWindow.qml`, `shell.qml`
status JSON key `myHome`).
- `SettingsSearch.qml`: `home-phone` extraEntries re-pointed (`my-home` for Home
Assistant entries, `phone` for phone entries); new entries for rooms, phone battery,
ring, clipboard, Today.
- Generators re-run: Vicinae commands (`settings-home-phone``settings-my-home` +
`settings-phone`; `home` still skipped so Overview adds no command), `docs/settings.md`.
- Contracts: `home-phone-settings-contract` rewritten as `my-home-settings-contract`
(+ phone coverage), `control-center-contract` (Manage target), `health-ui-contract` /
`panama-doctor-contract` (settings target), nav/jump/search/gnome-handoff/
panama-commands re-verified against the new route table. `home-preferences-contract`
and `phone-messages-contract` unchanged.
- Docs: settings README, manual chapter 05 (Home description), Welcome comment
(fourteen categories).
## Non-goals (reserved slots, later phases)
Assist box, notification mirror/reply, scenes, climate, cameras, now-playing, todos,
HA WebSocket `--watch` streaming, customizable quick actions.
@@ -0,0 +1,29 @@
# Settings redesign — deferred test runs
No contract is executed while the settings redesign is in flight: many are live
harnesses that open windows, drive overlays, and run display transactions on
the real desktop. Everything below runs **once, at the end of the redesign,
with Gabriel's go-ahead**, and failures get fixed then.
## The run
- `panama test` — the full suite (162 contracts at last count; the top-level
README's count line must match the final number).
## Known items to verify or investigate at the end
- `quickshell/welcome-contract` — failed once ("the welcome screen did not
open") during a full-suite run storming the live session; passed in
isolation minutes earlier after the Welcome.qml comment edit. Suspected
contention flake, not a regression. Confirm.
- `setup/readme-contract` — counts contracts; keep the README number in sync
as later phases add contracts (phase 2 added `phone-page-contract`).
- Phase 2 additions already written and passing when last run:
`my-home-settings-contract` (renamed from `home-phone-settings-contract`),
`phone-page-contract`, extended `home_assistant_bridge_test.py` and
`kdeconnect_bridge_test.py`.
- Each later phase (Appearance, …) appends its new/changed contracts here
instead of running them.
## Phase 3 (Appearance) — append below