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
+25 -2
View File
@@ -80,6 +80,29 @@ duplicate_categories="$(sort <<<"$category_ids" | uniq -d)"
[[ -z "$duplicate_categories" ]] \
|| fail "these category ids are declared twice: $(tr '\n' ' ' <<<"$duplicate_categories")"
# ── Retired ids still land on a real page ────────────────────────────────────
# Old Vicinae commands, shell history and muscle memory keep handing over page
# ids that no longer exist, and resolve() consults the retired map before
# anything else. An entry aimed at a leaf that has itself since been renamed
# sends every one of those callers to Home without saying so, and an entry that
# names a live leaf shadows the real page.
retired_block="$(sed -n '/property var retired:/,/})/p' "$routes")"
retired_pairs="$(grep -oE '"[a-z-]+"[[:space:]]*:[[:space:]]*"[a-z-]+"' <<<"$retired_block" || true)"
retired_count=0
while read -r pair; do
[[ -n "$pair" ]] || continue
retired_id="$(sed -E 's/"([a-z-]+)".*/\1/' <<<"$pair")"
retired_target="$(sed -E 's/.*"([a-z-]+)"$/\1/' <<<"$pair")"
retired_count=$((retired_count + 1))
if ! grep -qx "$retired_target" <<<"$leaves"; then
fail "the retired id \"$retired_id\" resolves to \"$retired_target\", which is not a leaf, so everyone still holding it silently lands on Home"
fi
if grep -qx "$retired_id" <<<"$leaves"; then
fail "\"$retired_id\" is listed as retired and is also a live leaf, so resolve() answers with the retired target instead of the page itself"
fi
done <<<"$retired_pairs"
# ── Every leaf resolves everywhere ───────────────────────────────────────────
while read -r page; do
[[ -n "$page" ]] || continue
@@ -130,5 +153,5 @@ while read -r page_file; do
|| fail "$type_name.qml exists but nothing in SettingsShell instantiates it"
done < <(find "$settings_dir" -maxdepth 1 -name '*Page.qml')
printf 'settings nav contract: PASS (%d categories, %d leaves)\n' \
"$(grep -c . <<<"$category_ids")" "$(grep -c . <<<"$leaves")"
printf 'settings nav contract: PASS (%d categories, %d leaves, %d retired ids)\n' \
"$(grep -c . <<<"$category_ids")" "$(grep -c . <<<"$leaves")" "$retired_count"