plasma-homeassistant/package/contents/ui/ConfigItems.qml

236 lines
7.0 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kcmutils as KCM
import "../code/model.mjs" as Model
import "components"
import "."
KCM.ScrollViewKCM {
property string cfg_items
property alias cfg_autoBackupFile: autoBackupFileField.text
property ListModel items: ListModel { dynamicRoles: true }
property var services: ({})
property var entities: ({})
property bool busy: true
property Client ha
header: Kirigami.InlineMessage {
Layout.fillWidth: true
text: ha?.errorString
visible: !!text
type: Kirigami.MessageType.Error
}
footer: ColumnLayout {
RowLayout {
enabled: !busy
Button {
icon.name: 'list-add'
text: i18n("Add")
onClicked: openDialog(new Model.ConfigEntity())
Layout.fillWidth: true
}
Button {
icon.name: 'application-menu'
down: backupMenu.visible
onClicked: backupMenu.visible = !backupMenu.visible
}
}
ColumnLayout {
id: backupMenu
visible: false
RowLayout {
Button {
icon.name: 'document-import'
text: i18n("Import")
onClicked: file.open().then(data => {
setItems(data)
save()
})
Layout.fillWidth: true
}
Button {
icon.name: 'document-export'
text: i18n("Export")
onClicked: file.save(cfg_items)
enabled: !!items.count
Layout.fillWidth: true
}
}
RowLayout {
Label {
text: i18n("Auto backup")
}
Kirigami.ActionTextField {
id: autoBackupFileField
readOnly: true
onPressed: file.select().then(file => cfg_autoBackupFile = file)
Layout.fillWidth: true
rightActions: [
Kirigami.Action {
visible: !!cfg_autoBackupFile
icon.name: 'edit-clear'
onTriggered: cfg_autoBackupFile = null
}
]
}
}
File {
id: file
defaultSuffix: "hapi"
nameFilters: ["Home Aassistant Plasma Items (*.hapi)"]
}
}
}
view: ListView {
id: itemList
model: Object.keys(entities).length ? items : []
delegate: EntityListItem {}
moveDisplaced: Transition {
NumberAnimation { properties: "y"; duration: Kirigami.Units.longDuration }
}
BusyIndicator {
anchors.centerIn: parent
visible: busy
}
}
Component.onCompleted: {
setItems(cfg_items)
ha = ClientFactory.getClient(this, plasmoid.configuration.url)
ha.readyChanged.connect(fetchData)
}
function setItems(data) {
items.append(JSON.parse(data))
}
function fetchData() {
if (!ha?.ready) return
return Promise.all([ha.getStates(), ha.getServices()])
.then(([e, s]) => {
entities = arrayToObject(e, 'entity_id')
services = s
busy = false
}).catch(() => busy = false)
}
component EntityListItem: Item { // Wrapper for ListItemDragHandle
width: ListView.view.width
implicitHeight: listItem.height
ItemDelegate {
id: listItem
down: false
width: parent.width
readonly property var entity: entities[model.entity_id]
contentItem: RowLayout {
Kirigami.ListItemDragHandle {
listItem: listItem
listView: itemList
onMoveRequested: (oldIndex, newIndex) => items.move(oldIndex, newIndex, 1)
onDropped: save()
}
DynamicIcon {
name: model.icon || listItem.entity?.attributes.icon || ''
Layout.preferredWidth: parent.height
Layout.preferredHeight: parent.height
}
Kirigami.TitleSubtitle {
title: model.name || listItem.entity?.attributes.friendly_name || 'Unknown'
subtitle: model.entity_id
Layout.fillWidth: true
}
ToolButton {
icon.name: 'edit-entry'
onClicked: openDialog(new Model.ConfigEntity(model), index)
}
ToolButton {
icon.name: 'delete'
onClicked: removeItem(index)
}
}
}
}
Component {
id: dialogComponent
Kirigami.Dialog {
id: dialog
property int index
property var item
signal itemAccepted(int index, var item)
readonly property bool acceptable: !!itemForm.item?.entity_id
padding: Kirigami.Units.largeSpacing
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
onRejected: close()
onAccepted: itemAccepted(index, item) || close()
Component.onCompleted: standardButton(Kirigami.Dialog.Ok).enabled = Qt.binding(() => acceptable)
ConfigItem {
id: itemForm
item: dialog.item
}
}
}
function openDialog(data, index = -1) {
const dialog = dialogComponent.createObject(parent, {
index: index,
item: data,
title: data.name || data.entity_id || i18n('New')
})
dialog.open()
dialog.onItemAccepted.connect((index, item) => {
if (~index) {
return updateItem(item, index)
}
return addItem(item)
})
dialog.closed.connect(dialog.destroy)
}
function save() {
const array = []
for (let i = 0; i < items.count; i++) {
array.push(items.get(i))
}
cfg_items = JSON.stringify(array, (key, value) => value || undefined)
}
function removeItem(index) {
if (index >= items.length || index < 0) return
items.remove(index)
save()
}
function addItem(item) {
items.append(item)
save()
}
function updateItem(item, index) {
if (index >= items.length || index < 0) return
items.set(index, item)
save()
}
function arrayToObject(array, key) {
return array.reduce((o, e) => (o[e[key]] = e,o), {})
}
function saveConfig() {
if (cfg_autoBackupFile) {
file.write(cfg_autoBackupFile, cfg_items)
}
}
}