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:
@@ -0,0 +1,163 @@
|
||||
// One light on the My Home page: power square, name, state, and a brightness
|
||||
// slider when the light dims. The slider is Control Center's — one dimmer
|
||||
// implementation everywhere, covered by home-brightness-slider-contract.
|
||||
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.modules.quicksettings
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
// A catalog entity: { id, sourceName, name, state, available, active,
|
||||
// dimmable, brightnessPct }.
|
||||
property var entity: ({})
|
||||
// Whether this light sits in the first four favorites, and therefore in
|
||||
// Control Center.
|
||||
property bool featured: false
|
||||
|
||||
readonly property string entityId: String(root.entity.id ?? "")
|
||||
readonly property bool busy: HomeAssistant.isBusy(root.entityId)
|
||||
readonly property int pending: HomeAssistant.pendingFor(root.entityId)
|
||||
readonly property string entityError: HomeAssistant.errorFor(root.entityId)
|
||||
readonly property bool showsSlider: root.entity.dimmable === true && root.entity.available === true
|
||||
|
||||
radius: 14
|
||||
color: Theme.alpha(Theme.fg, 0.05)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.fg, 0.07)
|
||||
implicitHeight: header.implicitHeight + (showsSlider ? 36 : 0)
|
||||
+ (entityError !== "" ? errorLine.implicitHeight + 4 : 0) + 22
|
||||
|
||||
Row {
|
||||
id: header
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 11
|
||||
spacing: 11
|
||||
|
||||
Rectangle {
|
||||
id: power
|
||||
|
||||
width: 30
|
||||
height: 29
|
||||
radius: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: root.entity.active === true
|
||||
? Theme.alpha(Theme.warn, 0.16)
|
||||
: Theme.alpha(Theme.fg, 0.07)
|
||||
border.width: 1
|
||||
border.color: root.entity.active === true
|
||||
? Theme.alpha(Theme.warn, 0.4)
|
||||
: Theme.alpha(Theme.fg, 0.09)
|
||||
opacity: root.entity.available === true && !root.busy ? 1 : 0.45
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "\u{F0335}"
|
||||
color: root.entity.active === true ? Theme.warn : Theme.fgDim
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 14
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: root.entity.available === true && !root.busy
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: HomeAssistant.toggleEntity(root.entityId)
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: (root.entity.active === true ? "Turn off " : "Turn on ")
|
||||
+ String(root.entity.name ?? root.entity.sourceName ?? "")
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - power.width - parent.spacing
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: String(root.entity.name ?? root.entity.sourceName ?? "")
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
font.weight: Font.DemiBold
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.featured
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: featuredCaption.implicitWidth + 16
|
||||
height: 19
|
||||
radius: Theme.pillRadius
|
||||
color: Theme.alpha(Theme.accent, 0.1)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.accent, 0.2)
|
||||
|
||||
Text {
|
||||
id: featuredCaption
|
||||
anchors.centerIn: parent
|
||||
text: "Control Center"
|
||||
color: Theme.accent
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 9
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: {
|
||||
if (root.entity.available !== true)
|
||||
return "Unavailable";
|
||||
if (root.entity.active !== true)
|
||||
return "Off";
|
||||
const pct = root.pending >= 0 ? root.pending : Number(root.entity.brightnessPct ?? 0);
|
||||
return root.entity.dimmable === true ? "On · " + pct + "%" : "On";
|
||||
}
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HomeBrightnessSlider {
|
||||
visible: root.showsSlider
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 11
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 11
|
||||
anchors.top: header.bottom
|
||||
accessibleName: String(root.entity.name ?? root.entity.sourceName ?? "Light") + " brightness"
|
||||
value: root.pending >= 0 ? root.pending : Number(root.entity.brightnessPct ?? 0)
|
||||
onCommitted: value => HomeAssistant.setBrightness(root.entityId, value)
|
||||
}
|
||||
|
||||
Text {
|
||||
id: errorLine
|
||||
visible: root.entityError !== ""
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 11
|
||||
text: root.entityError === "unreachable"
|
||||
? "Home Assistant did not respond"
|
||||
: "That change did not apply"
|
||||
color: Theme.warn
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user