import QtQuick import qs.config import qs.services Item { id: root property bool expanded: false signal toggleExpanded implicitHeight: content.implicitHeight Column { id: content width: parent.width spacing: 6 ControlSectionHeader { width: parent.width label: "Home" action: HomeAssistant.entities.length > 0 ? HomeAssistant.entities.length + " accessories " + (root.expanded ? "⌃" : "›") : "Retry" actionEnabled: HomeAssistant.phase !== "loading" onActionTriggered: { if (HomeAssistant.entities.length > 0) root.toggleExpanded(); else HomeAssistant.refresh(); } } Rectangle { id: homeCard width: parent.width height: visible ? homeGrid.implicitHeight + 20 : 0 visible: HomeAssistant.entities.length > 0 radius: Theme.cardRadius + 2 color: Theme.alpha(Theme.accent, 0.045) border.width: 1 border.color: Theme.alpha(Theme.accent, 0.12) Grid { id: homeGrid anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.margins: 10 columns: 4 spacing: 7 Repeater { model: HomeAssistant.visibleEntities HomeTile { required property var modelData width: (homeGrid.width - homeGrid.spacing * 3) / 4 entity: modelData busy: HomeAssistant.busyEntityId === modelData.id onActivated: HomeAssistant.toggleEntity(modelData.id) } } } } Rectangle { width: parent.width height: visible ? 66 : 0 visible: HomeAssistant.entities.length === 0 radius: Theme.cardRadius color: Theme.alpha(Theme.fg, 0.05) border.width: 1 border.color: Theme.alpha(Theme.fg, 0.045) Text { id: stateIcon anchors.left: parent.left anchors.leftMargin: 12 anchors.verticalCenter: parent.verticalCenter text: HomeAssistant.phase === "loading" ? "\u{F0772}" : "\u{F02DC}" color: HomeAssistant.phase === "loading" ? Theme.accent : Theme.fgDim font.family: Theme.fontMono font.pixelSize: 16 } Column { anchors.left: stateIcon.right anchors.leftMargin: 11 anchors.right: openHome.left anchors.rightMargin: 10 anchors.verticalCenter: parent.verticalCenter spacing: 3 Text { width: parent.width text: root.emptyTitle() color: Theme.fg elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSize font.weight: Font.DemiBold } Text { width: parent.width text: root.emptyDetail() color: Theme.fgDim elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } } Rectangle { id: openHome anchors.right: parent.right anchors.rightMargin: 10 anchors.verticalCenter: parent.verticalCenter width: 48 height: 28 radius: 9 visible: HomeAssistant.phase !== "loading" color: openMouse.containsMouse ? Theme.alpha(Theme.accent, 0.20) : Theme.alpha(Theme.accent, 0.11) Text { anchors.centerIn: parent text: "Open" color: Theme.accent font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall font.weight: Font.Medium } MouseArea { id: openMouse anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: HomeAssistant.open() } } } Rectangle { width: parent.width height: visible ? 30 : 0 visible: HomeAssistant.stale radius: 9 color: Theme.alpha(Theme.warn, 0.08) Text { anchors.left: parent.left anchors.leftMargin: 10 anchors.verticalCenter: parent.verticalCenter text: "Showing the last known state" color: Theme.warn font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } Text { anchors.right: parent.right anchors.rightMargin: 10 anchors.verticalCenter: parent.verticalCenter text: "Retry" color: Theme.accent font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall font.weight: Font.Medium MouseArea { anchors.fill: parent anchors.margins: -6 cursorShape: Qt.PointingHandCursor onClicked: HomeAssistant.refresh() } } } Section { width: parent.width expanded: root.expanded && HomeAssistant.entities.length > 0 ScrollColumn { width: parent.width maxHeight: 270 spacing: 2 Repeater { model: HomeAssistant.entities Rectangle { id: entityRow required property var modelData width: parent.width height: 44 radius: 10 color: entityMouse.containsMouse ? Theme.alpha(Theme.fg, 0.09) : "transparent" Text { id: entityGlyph anchors.left: parent.left anchors.leftMargin: 11 anchors.verticalCenter: parent.verticalCenter text: "\u{F0335}" color: entityRow.modelData.active ? Theme.warn : Theme.fgDim font.family: Theme.fontMono font.pixelSize: 14 } Column { anchors.left: entityGlyph.right anchors.leftMargin: 10 anchors.right: entityState.left anchors.rightMargin: 8 anchors.verticalCenter: parent.verticalCenter spacing: 2 Text { width: parent.width text: entityRow.modelData.name color: Theme.fg elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSize } Text { width: parent.width text: !entityRow.modelData.available ? "Unavailable" : entityRow.modelData.state color: Theme.fgMuted elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } } Text { id: entityState anchors.right: parent.right anchors.rightMargin: 11 anchors.verticalCenter: parent.verticalCenter text: HomeAssistant.busyEntityId === entityRow.modelData.id ? "Working" : (entityRow.modelData.active ? "On" : "Off") color: entityRow.modelData.active ? Theme.warn : Theme.fgMuted font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall font.weight: Font.DemiBold } MouseArea { id: entityMouse anchors.fill: parent enabled: entityRow.modelData.available && HomeAssistant.busyEntityId === "" hoverEnabled: true cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor onClicked: HomeAssistant.toggleEntity(entityRow.modelData.id) } } } } } } function emptyTitle(): string { if (HomeAssistant.phase === "loading") return "Loading your home"; if (HomeAssistant.lastError === "authentication-required") return "Authentication required"; if (HomeAssistant.lastError === "not-configured") return "Home Assistant is not configured"; return "Home Assistant is unavailable"; } function emptyDetail(): string { if (HomeAssistant.phase === "loading") return "Reading configured favourites"; if (HomeAssistant.lastError === "authentication-required") return "Update the long-lived access token"; if (HomeAssistant.lastError === "not-configured") return "Add a URL, token and favourites"; return "Check the connection and retry"; } }