226 lines
8.1 KiB
QML
226 lines
8.1 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Item {
|
|
id: haSettings
|
|
|
|
property var settings: null
|
|
|
|
readonly property var daemon: (typeof PluginService !== "undefined" && PluginService.pluginInstances) ? PluginService.pluginInstances["gameBar"] : null
|
|
readonly property var service: daemon ? daemon.homeService : null
|
|
readonly property var entityList: service ? service.entityList : []
|
|
|
|
property string filterText: ""
|
|
|
|
// Read straight from the daemon's (reactive) plugin data. Caching this in a
|
|
// local list loses the saved picks, because PluginSettings.loadValue() still
|
|
// returns the default while pluginService is being injected - and the next
|
|
// pick would then save that empty list over the stored one.
|
|
readonly property var selectedIds: {
|
|
const data = service ? service.pluginData : null;
|
|
const stored = data ? data.haEntities : null;
|
|
if (Array.isArray(stored))
|
|
return stored;
|
|
|
|
const fallback = settings ? settings.loadValue("haEntities", []) : [];
|
|
return Array.isArray(fallback) ? fallback : [];
|
|
}
|
|
|
|
readonly property var filteredEntities: {
|
|
const query = filterText.trim().toLowerCase();
|
|
const list = haSettings.entityList;
|
|
if (query === "")
|
|
return list;
|
|
|
|
return list.filter(entity => {
|
|
const name = (entity.attributes && entity.attributes.friendly_name) ? entity.attributes.friendly_name : "";
|
|
return entity.entity_id.toLowerCase().includes(query) || name.toLowerCase().includes(query);
|
|
});
|
|
}
|
|
|
|
readonly property string statusText: {
|
|
if (!service)
|
|
return "Plugin daemon not running";
|
|
if (!service.configured)
|
|
return "Enter a URL and token, then refresh";
|
|
if (service.loading)
|
|
return "Contacting Home Assistant…";
|
|
if (service.lastError !== "")
|
|
return service.lastError;
|
|
if (service.everLoaded)
|
|
return entityList.length + " entities · " + selectedIds.length + " picked";
|
|
return "Not loaded yet";
|
|
}
|
|
|
|
function isSelected(entityId) {
|
|
return haSettings.selectedIds.indexOf(entityId) !== -1;
|
|
}
|
|
|
|
function setSelected(entityId, selected) {
|
|
const next = haSettings.selectedIds.slice();
|
|
const index = next.indexOf(entityId);
|
|
if (selected && index === -1)
|
|
next.push(entityId);
|
|
else if (!selected && index !== -1)
|
|
next.splice(index, 1);
|
|
|
|
if (settings)
|
|
settings.saveValue("haEntities", next);
|
|
}
|
|
|
|
implicitHeight: column.implicitHeight
|
|
height: implicitHeight
|
|
|
|
Component.onCompleted: {
|
|
if (service && service.configured && !service.everLoaded)
|
|
service.refresh();
|
|
}
|
|
|
|
Column {
|
|
id: column
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
spacing: Theme.spacingS
|
|
|
|
StyledText {
|
|
text: "Home Assistant"
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
font.weight: Font.Medium
|
|
color: Theme.surfaceText
|
|
}
|
|
|
|
StyledText {
|
|
width: parent.width
|
|
text: "Pick the entities you want in the Home widget. The access token is stored in plugin_settings.json."
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
|
|
Row {
|
|
width: parent.width
|
|
spacing: Theme.spacingS
|
|
|
|
StyledText {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: Math.round(parent.width * 0.3)
|
|
text: "Status"
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
}
|
|
|
|
StyledText {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: parent.width - Math.round(parent.width * 0.3) - refreshButton.width - parent.spacing * 2
|
|
text: haSettings.statusText
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: (haSettings.service && haSettings.service.lastError !== "") ? Theme.error : Theme.surfaceText
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
DankButton {
|
|
id: refreshButton
|
|
|
|
text: "Refresh"
|
|
iconName: "refresh"
|
|
enabled: haSettings.service !== null && haSettings.service.configured
|
|
onClicked: haSettings.service.refresh()
|
|
}
|
|
}
|
|
|
|
DankTextField {
|
|
width: parent.width
|
|
placeholderText: "Filter entities (e.g. light, kitchen)"
|
|
leftIconName: "search"
|
|
showClearButton: true
|
|
text: haSettings.filterText
|
|
onTextChanged: haSettings.filterText = text
|
|
visible: haSettings.entityList.length > 0
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 280
|
|
radius: Theme.cornerRadius
|
|
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
|
border.color: Theme.outlineMedium
|
|
border.width: Theme.layerOutlineWidth
|
|
visible: haSettings.entityList.length > 0
|
|
|
|
DankListView {
|
|
id: entityListView
|
|
|
|
anchors.fill: parent
|
|
anchors.margins: Theme.spacingS
|
|
clip: true
|
|
spacing: 2
|
|
model: haSettings.filteredEntities
|
|
|
|
delegate: Rectangle {
|
|
id: entityRow
|
|
|
|
required property var modelData
|
|
|
|
readonly property bool picked: haSettings.isSelected(modelData.entity_id)
|
|
|
|
width: entityListView.width
|
|
height: 44
|
|
radius: Theme.cornerRadius
|
|
color: picked ? Theme.primarySelected : (rowArea.containsMouse ? Theme.surfaceHover : "transparent")
|
|
|
|
Column {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: Theme.spacingS
|
|
anchors.right: pickToggle.left
|
|
anchors.rightMargin: Theme.spacingS
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: 0
|
|
|
|
StyledText {
|
|
width: parent.width
|
|
text: (entityRow.modelData.attributes && entityRow.modelData.attributes.friendly_name) ? entityRow.modelData.attributes.friendly_name : entityRow.modelData.entity_id
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: entityRow.picked ? Font.Medium : Font.Normal
|
|
color: Theme.surfaceText
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
StyledText {
|
|
width: parent.width
|
|
text: entityRow.modelData.entity_id + " · " + entityRow.modelData.state
|
|
font.pixelSize: Theme.fontSizeSmall - 1
|
|
color: Theme.surfaceVariantText
|
|
elide: Text.ElideRight
|
|
}
|
|
}
|
|
|
|
DankToggle {
|
|
id: pickToggle
|
|
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: Theme.spacingS
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
hideText: true
|
|
checked: entityRow.picked
|
|
onToggled: isChecked => haSettings.setSelected(entityRow.modelData.entity_id, isChecked)
|
|
}
|
|
|
|
MouseArea {
|
|
id: rowArea
|
|
|
|
anchors.fill: parent
|
|
anchors.rightMargin: pickToggle.width + Theme.spacingM
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: haSettings.setSelected(entityRow.modelData.entity_id, !entityRow.picked)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|