import QtQuick import qs.config Rectangle { id: root required property var entity property bool busy: false property int pendingBrightness: -1 property string actionError: "" signal powerRequested signal brightnessRequested(int value) readonly property int confirmedBrightness: root.clamp(root.entity.brightnessPct ?? 0) readonly property int displayedBrightness: brightnessSlider.previewValue readonly property bool powerEnabled: root.entity.available && !root.busy readonly property bool dimmerEnabled: root.entity.available && root.entity.dimmable && !root.busy implicitHeight: 124 radius: 14 color: { if (root.entity.active) return Theme.alpha(Theme.warn, powerArea.containsMouse ? 0.145 : 0.095); return Theme.alpha(Theme.fg, powerArea.containsMouse ? 0.078 : 0.045); } border.width: 1 border.color: { if (root.activeFocus) return Theme.alpha(Theme.accent, 0.72); if (root.entity.active) return Theme.alpha(Theme.warn, 0.17); return Theme.alpha(Theme.fg, 0.065); } activeFocusOnTab: root.powerEnabled Behavior on color { ColorAnimation { duration: Theme.durFast } } Behavior on border.color { ColorAnimation { duration: Theme.durFast } } Keys.onSpacePressed: { if (root.powerEnabled) root.powerRequested(); } Keys.onReturnPressed: { if (root.powerEnabled) root.powerRequested(); } Rectangle { id: bulb anchors.left: parent.left anchors.leftMargin: 13 anchors.top: parent.top anchors.topMargin: 13 width: 30 height: 30 radius: 10 color: root.entity.active ? Theme.alpha(Theme.warn, 0.16) : Theme.alpha(Theme.fg, 0.065) Text { anchors.centerIn: parent text: root.busy ? "\u{F0772}" : "\u{F0335}" color: root.entity.active ? Theme.warn : Theme.fgDim font.family: Theme.fontMono font.pixelSize: 15 } } Text { anchors.right: parent.right anchors.rightMargin: 13 anchors.verticalCenter: bulb.verticalCenter text: root.entity.dimmable ? root.displayedBrightness + "%" : "—" color: root.entity.active || root.pendingBrightness >= 0 ? Theme.warn : Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall font.weight: Font.DemiBold font.features: Theme.tabularFigures } Text { id: aliasLabel anchors.left: parent.left anchors.leftMargin: 13 anchors.right: parent.right anchors.rightMargin: 13 anchors.top: bulb.bottom anchors.topMargin: 8 text: root.entity.name color: Theme.fg elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSize font.weight: Font.DemiBold } Text { anchors.left: aliasLabel.left anchors.right: aliasLabel.right anchors.top: aliasLabel.bottom anchors.topMargin: 2 text: root.secondaryText() color: root.actionError !== "" ? Theme.warn : (root.entity.active ? Theme.warn : Theme.fgMuted) elide: Text.ElideRight font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall } MouseArea { id: powerArea anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.bottom: brightnessSlider.top anchors.bottomMargin: 1 enabled: root.powerEnabled hoverEnabled: true cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor onPressed: root.forceActiveFocus() onClicked: root.powerRequested() } HomeBrightnessSlider { id: brightnessSlider anchors.left: parent.left anchors.leftMargin: 13 anchors.right: parent.right anchors.rightMargin: 13 anchors.bottom: parent.bottom anchors.bottomMargin: 5 value: root.pendingBrightness >= 0 ? root.pendingBrightness : root.confirmedBrightness enabled: root.dimmerEnabled accessibleName: root.entity.name + " brightness" onCommitted: value => root.brightnessRequested(value) } function clamp(candidate: real): int { return Math.max(0, Math.min(100, Math.round(candidate))); } function secondaryText(): string { if (root.actionError !== "") return root.errorText(root.actionError); if (!root.entity.available) return "Unavailable"; if (root.busy && root.pendingBrightness >= 0) return "Setting " + root.pendingBrightness + "%"; if (root.busy) return "Updating"; return root.entity.active ? "On" : "Off"; } function errorText(code: string): string { if (code === "authentication-required") return "Authentication required"; if (code === "entity-not-discovered") return "Light is unavailable"; return "Couldn’t update light"; } }