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:
@@ -43,6 +43,12 @@ Singleton {
|
||||
readonly property int pairedCount: root.devices.filter(device => device.paired).length
|
||||
readonly property var phoneActions: root.preferredPhone?.actions ?? []
|
||||
|
||||
// Vitals are null whenever the phone is away or the plugin is off, which is
|
||||
// the normal state rather than an error -- consumers show nothing, not a
|
||||
// zero. `?? null` keeps `undefined` from leaking out as a distinct case.
|
||||
readonly property var phoneBattery: root.preferredPhone?.battery ?? null
|
||||
readonly property var phoneSignal: root.preferredPhone?.signal ?? null
|
||||
|
||||
function supports(action: string): bool {
|
||||
return root.phoneActions.indexOf(action) >= 0;
|
||||
}
|
||||
@@ -53,13 +59,44 @@ Singleton {
|
||||
statusProc.running = true;
|
||||
}
|
||||
|
||||
// The helper emits `battery` and `signal` as either null or a complete
|
||||
// object. These rebuild them anyway so a partial payload -- an old helper,
|
||||
// a field that arrived as a string -- becomes null rather than a card
|
||||
// rendering "undefined%".
|
||||
function normalizeBattery(value: var): var {
|
||||
if (!value || typeof value.charge !== "number" || value.charge < 0)
|
||||
return null;
|
||||
return {
|
||||
charge: Math.round(value.charge),
|
||||
charging: value.charging === true
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSignal(value: var): var {
|
||||
if (!value || typeof value.strength !== "number" || value.strength < 0)
|
||||
return null;
|
||||
return {
|
||||
networkType: String(value.networkType ?? ""),
|
||||
strength: Math.round(value.strength)
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeDevice(device: var): var {
|
||||
return Object.assign({}, device, {
|
||||
battery: root.normalizeBattery(device.battery),
|
||||
signal: root.normalizeSignal(device.signal)
|
||||
});
|
||||
}
|
||||
|
||||
function consumeStatus(text: string): void {
|
||||
if (root.fixtureMode)
|
||||
return;
|
||||
try {
|
||||
const result = JSON.parse(text);
|
||||
root.available = result.available === true;
|
||||
root.devices = Array.isArray(result.devices) ? result.devices : [];
|
||||
root.devices = Array.isArray(result.devices)
|
||||
? result.devices.map(device => root.normalizeDevice(device))
|
||||
: [];
|
||||
root.lastError = String(result.error ?? "");
|
||||
} catch (error) {
|
||||
root.available = false;
|
||||
@@ -188,13 +225,19 @@ Singleton {
|
||||
root.available = true;
|
||||
root.lastError = "";
|
||||
root.recentExchange = null;
|
||||
// Vitals track reachability the way the helper's do: the plugin objects
|
||||
// only exist for a phone that is actually there, so the offline fixture
|
||||
// carries nulls and the reachable ones carry readable values.
|
||||
const reachable = name !== "offline";
|
||||
root.devices = [{
|
||||
id: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
name: "Fixture iPhone",
|
||||
type: "phone",
|
||||
paired: true,
|
||||
reachable: name !== "offline",
|
||||
actions: ["clipboard", "ping", "ring", "share"]
|
||||
reachable: reachable,
|
||||
actions: ["clipboard", "ping", "ring", "share"],
|
||||
battery: reachable ? { charge: 82, charging: true } : null,
|
||||
signal: reachable ? { networkType: "LTE", strength: 3 } : null
|
||||
}];
|
||||
root.transferActive = name === "transfer";
|
||||
root.transferFileName = name === "transfer" ? "Fixture document.pdf" : "";
|
||||
|
||||
Reference in New Issue
Block a user