import QtQuick 2.5 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.2 import Nymea 1.0 import "../components" import "../delegates" Page { id: root property Thing thing: null header: NymeaHeader { text: thing ? thing.name : "" backButtonVisible: true onBackPressed: pageStack.pop() } ListView { id: flickable anchors.fill: parent clip: true SwipeDelegateGroup {} section.property: "type" section.delegate: ListSectionHeader { text: { switch (parseInt(section)) { case ThingModel.TypeStateType: return qsTr("States") case ThingModel.TypeEventType: return qsTr("Events") } } } model: ThingModel { thing: root.thing showActions: false } delegate: SwipeDelegate { id: delegate width: parent.width readonly property StateType stateType: model.type === ThingModel.TypeStateType ? root.thing.thingClass.stateTypes.getStateType(model.id) : null readonly property EventType eventType: model.type === ThingModel.TypeEventType ? root.thing.thingClass.eventTypes.getEventType(model.id) : null Layout.fillWidth: true bottomPadding: 0 contentItem: Loader { id: inlineLoader Layout.fillWidth: true Layout.preferredHeight: Style.smallDelegateHeight sourceComponent: { switch (model.type) { case ThingModel.TypeStateType: return stateComponent; case ThingModel.TypeEventType: return eventComponent; } } Binding { target: inlineLoader.item when: model.type === ThingModel.TypeStateType property: "stateType" value: delegate.stateType } Binding { target: inlineLoader.item when: model.type === ThingModel.TypeEventType property: "eventType" value: delegate.eventType } } } } Component { id: stateComponent RowLayout { id: stateDelegate property StateType stateType: null readonly property State thingState: stateType ? root.thing.states.getState(stateType.id) : null Label { Layout.fillWidth: true Layout.minimumWidth: parent.width / 2 text: stateDelegate.stateType.displayName elide: Text.ElideRight } Loader { id: stateDelegateLoader Layout.fillWidth: true } Label { visible: text.length > 0 && stateDelegate.stateType.unit !== Types.UnitUnixTime text: Types.toUiUnit(stateDelegate.stateType.unit) } Component.onCompleted: updateLoader() onStateTypeChanged: updateLoader(); function updateLoader() { if (stateDelegate.stateType == null) { return; } var sourceComp; switch (stateDelegate.stateType.type.toLowerCase()) { case "string": sourceComp = "LabelDelegate.qml"; break; case "stringlist": sourceComp = "ListDelegate.qml"; break; case "bool": sourceComp = "LedDelegate.qml"; break; case "int": case "uint": case "double": if (stateDelegate.stateType.unit === Types.UnitUnixTime) { sourceComp = "DateTimeDelegate.qml"; } else { sourceComp = "NumberLabelDelegate.qml"; } break; case "color": sourceComp = "ColorDelegate.qml"; break; } if (!sourceComp) { sourceComp = "LabelDelegate.qml"; print("GenericThingPage: unhandled entry", stateDelegate.stateType.displayName) } var minValue = stateDelegate.stateType.minValue !== undefined ? stateDelegate.stateType.minValue : stateDelegate.stateType.type.toLowerCase() === "uint" ? 0 : -2000000000; // As per QML spec var maxValue = stateDelegate.stateType.maxValue !== undefined ? stateDelegate.stateType.maxValue : 2000000000; print("pushing delegate for", stateDelegate.stateType.name, "from:", minValue, "to:", maxValue, "possible:", stateDelegate.stateType.possibleValuesDisplayNames) stateDelegateLoader.setSource("../delegates/statedelegates/" + sourceComp, { value: root.thing.states.getState(stateType.id).value, possibleValues: stateDelegate.stateType.possibleValues, possibleValuesDisplayNames: stateDelegate.stateType.possibleValuesDisplayNames, from: minValue, to: maxValue, unit: stateDelegate.stateType.unit, writable: false, stateType: stateDelegate.stateType }) } Binding { target: stateDelegateLoader.item property: "value" value: stateDelegate.thingState.value } Binding { target: stateDelegateLoader.item.hasOwnProperty("from") ? stateDelegateLoader.item : null property: "from" value: stateDelegate.thingState.minValue } Binding { target: stateDelegateLoader.item.hasOwnProperty("to") ? stateDelegateLoader.item : null property: "to" value: stateDelegate.thingState.maxValue } Binding { target: stateDelegateLoader.item.hasOwnProperty("possibleValues") ? stateDelegateLoader.item : null property: "possibleValues" value: stateDelegate.thingState.possibleValues } Binding { target: stateDelegateLoader.item.hasOwnProperty("possibleValuesDisplayNames") ? stateDelegateLoader.item : null property: "possibleValuesDisplayNames" value: { print("updating displayNames", stateDelegate.thingState.possibleValues) var ret = [] for (var i = 0; i < stateDelegate.thingState.possibleValues.length; i++) { var possibleValue = stateDelegate.thingState.possibleValues[i] var idx = stateDelegate.stateType.possibleValues.indexOf(possibleValue) print("value:", possibleValue, idx) if (idx >= 0) { ret.push(stateDelegate.stateType.possibleValuesDisplayNames[idx]) } else { ret.push(possibleValue) } } return ret } } Binding { target: stateDelegateLoader.item.hasOwnProperty("unit") ? stateDelegateLoader.item : null property: "unit" value: stateDelegate.stateType.unit } } } Component { id: eventComponent RowLayout { id: eventComponentItem property EventType eventType: null Label { Layout.fillWidth: true text: eventComponentItem.eventType.displayName } Rectangle { id: flashlight Layout.preferredHeight: Style.iconSize * .8 Layout.preferredWidth: height color: "lightgray" radius: width / 2 border.color: Style.foregroundColor border.width: 1 SequentialAnimation on color { id: flashlightAnimation running: false ColorAnimation { to: "lightgreen"; duration: 100 } ColorAnimation { to: "lightgray"; duration: 500 } } } Connections { target: root.thing onEventTriggered: { if (eventTypeId === eventComponentItem.eventType.id) { flashlightAnimation.start(); } } } } } }