diff --git a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp index 69656d5d..b87817a1 100644 --- a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp @@ -303,7 +303,7 @@ void JsonRpcClient::sendRequest(const QVariantMap &request) { QVariantMap newRequest = request; newRequest.insert("token", m_token); -// qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); + qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); m_connection->sendData(QJsonDocument::fromVariant(newRequest).toJson(QJsonDocument::Compact) + "\n"); } diff --git a/libnymea-app-core/models/logsmodelng.cpp b/libnymea-app-core/models/logsmodelng.cpp index af341100..4258f407 100644 --- a/libnymea-app-core/models/logsmodelng.cpp +++ b/libnymea-app-core/models/logsmodelng.cpp @@ -173,6 +173,14 @@ QVariant LogsModelNg::maxValue() const return m_maxValue; } +LogEntry *LogsModelNg::get(int index) const +{ + if (index >= 0 && index < m_list.count()) { + return m_list.at(index); + } + return nullptr; +} + void LogsModelNg::logsReply(const QVariantMap &data) { // qDebug() << "logs reply" << data; diff --git a/libnymea-app-core/models/logsmodelng.h b/libnymea-app-core/models/logsmodelng.h index 120ea6ce..dd0a59c1 100644 --- a/libnymea-app-core/models/logsmodelng.h +++ b/libnymea-app-core/models/logsmodelng.h @@ -71,6 +71,8 @@ public: QVariant minValue() const; QVariant maxValue() const; + Q_INVOKABLE LogEntry *get(int index) const; + protected: virtual void fetchMore(const QModelIndex &parent = QModelIndex()) override; virtual bool canFetchMore(const QModelIndex &parent = QModelIndex()) const override; diff --git a/libnymea-common/types/eventtypes.h b/libnymea-common/types/eventtypes.h index 1f81857c..4fadf2c1 100644 --- a/libnymea-common/types/eventtypes.h +++ b/libnymea-common/types/eventtypes.h @@ -40,7 +40,7 @@ public: RoleDisplayName }; - EventTypes(QObject *parent = 0); + EventTypes(QObject *parent = nullptr); QList eventTypes(); diff --git a/libnymea-common/types/vendor.h b/libnymea-common/types/vendor.h index b4f25b23..ef2ec948 100644 --- a/libnymea-common/types/vendor.h +++ b/libnymea-common/types/vendor.h @@ -31,11 +31,11 @@ class Vendor : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name CONSTANT) - Q_PROPERTY(QString displayName READ displayName) + Q_PROPERTY(QString displayName READ displayName CONSTANT) Q_PROPERTY(QUuid id READ id CONSTANT) public: - Vendor(const QUuid &id = QUuid(), const QString &name = QString(), QObject *parent = 0); + Vendor(const QUuid &id = QUuid(), const QString &name = QString(), QObject *parent = nullptr); QUuid id() const; void setId(const QUuid &id); diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc index eac9c6ad..7c5b0ec3 100644 --- a/nymea-app/images.qrc +++ b/nymea-app/images.qrc @@ -153,5 +153,9 @@ ui/images/smartmeter.svg ui/images/radiator.svg ui/images/ev-charger.svg + ui/images/lighting/activate.svg + ui/images/lighting/concentrate.svg + ui/images/lighting/reading.svg + ui/images/lighting/relax.svg diff --git a/nymea-app/ui/EditDevicesPage.qml b/nymea-app/ui/EditDevicesPage.qml index c93a1a1e..3d45a51c 100644 --- a/nymea-app/ui/EditDevicesPage.qml +++ b/nymea-app/ui/EditDevicesPage.qml @@ -81,10 +81,11 @@ Page { device: deviceProxy.get(index) canDelete: true onClicked: { - pageStack.push(Qt.resolvedUrl("devicepages/ConfigureThingPage.qml"), {device: deviceProxy.get(index)}) + print("clicked:", model.id) + pageStack.push(Qt.resolvedUrl("devicepages/ConfigureThingPage.qml"), {device: device}) } onDeleteClicked: { - d.deviceToRemove = deviceProxy.get(index); + d.deviceToRemove = device; engine.deviceManager.removeDevice(d.deviceToRemove.id) } } diff --git a/nymea-app/ui/customviews/GenericTypeLogView.qml b/nymea-app/ui/customviews/GenericTypeLogView.qml index 954ecc0a..b617d82b 100644 --- a/nymea-app/ui/customviews/GenericTypeLogView.qml +++ b/nymea-app/ui/customviews/GenericTypeLogView.qml @@ -7,7 +7,7 @@ import "../components" Item { id: root - signal addRuleClicked(var value) + signal addRuleClicked(int index) property var logsModel: null @@ -66,7 +66,7 @@ Item { anchors.margins: app.margins name: "../images/magic.svg" } - onClicked: root.addRuleClicked(model.value) + onClicked: root.addRuleClicked(index) } onClicked: { if (swipe.complete) { diff --git a/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml b/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml index ea4b69a2..c828b9a8 100644 --- a/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml +++ b/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml @@ -46,7 +46,7 @@ DeviceListPageBase { property var deviceClass: engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); property var connectedStateType: deviceClass.stateTypes.findByName("connected"); - property var connectedState: device.states.getState(connectedStateType.id) + property var connectedState: connectedStateType ? device.states.getState(connectedStateType.id) : null property var powerStateType: deviceClass.stateTypes.findByName("power"); property var powerActionType: deviceClass.actionTypes.findByName("power"); @@ -66,7 +66,7 @@ DeviceListPageBase { rightPadding: 0 contentItem: ItemDelegate { id: contentItem - implicitHeight: itemDelegate.brightnessStateType && !itemDelegate.inline && nameRow.enabled ? nameRow.implicitHeight + sliderRow.implicitHeight : nameRow.implicitHeight + implicitHeight: nameRow.implicitHeight // gradient: Gradient { // GradientStop { position: 0.0; color: "transparent" } // GradientStop { position: 1.0; color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, 0.05) } @@ -75,6 +75,14 @@ DeviceListPageBase { topPadding: 0 + Rectangle { + anchors { left: parent.left; top: parent.top; bottom: parent.bottom } + width: app.margins / 2 + color: itemDelegate.connectedState !== null && itemDelegate.connectedState.value === false ? + "red" + : itemDelegate.colorStateType ? itemDelegate.colorState.value : "#00000000" + } + contentItem: ColumnLayout { spacing: 0 RowLayout { @@ -101,16 +109,18 @@ DeviceListPageBase { anchors.fill: icon radius: 1 samples: 17 - color: app.foregroundColor + color: app.backgroundColor source: icon } ColorIcon { id: icon anchors.fill: parent - color: itemDelegate.connectedState !== null && itemDelegate.connectedState.value === false ? - "red" - : itemDelegate.colorStateType ? itemDelegate.colorState.value : "#00000000" + color: app.accentColor +// anchors.margins: app.margins / 4 +// color: itemDelegate.connectedState !== null && itemDelegate.connectedState.value === false ? +// "red" +// : itemDelegate.colorStateType ? itemDelegate.colorState.value : "#00000000" name: itemDelegate.connectedState !== null && itemDelegate.connectedState.value === false ? "../images/dialog-warning-symbolic.svg" : itemDelegate.powerState.value === true ? "../images/light-on.svg" : "../images/light-off.svg" @@ -149,28 +159,6 @@ DeviceListPageBase { } } } - Item { - id: sliderRow - Layout.fillWidth: true - implicitHeight: outlineSlider.implicitHeight * .6 - Layout.preferredHeight: implicitHeight - - ThrottledSlider { - id: outlineSlider - anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter } - visible: nameRow.enabled && itemDelegate.brightnessStateType && !inlineSlider.visible - from: 0; to: 100 - value: itemDelegate.brightnessState ? itemDelegate.brightnessState.value : 0 - onMoved: { - var params = []; - var param1 = {}; - param1["paramTypeId"] = itemDelegate.brightnessActionType.paramTypes.get(0).id; - param1["value"] = value; - params.push(param1) - engine.deviceManager.executeAction(itemDelegate.device.id, itemDelegate.brightnessActionType.id, params) - } - } - } } onClicked: { enterPage(index, false) diff --git a/nymea-app/ui/devicepages/ButtonDevicePage.qml b/nymea-app/ui/devicepages/ButtonDevicePage.qml index 08e9184f..db2b2efd 100644 --- a/nymea-app/ui/devicepages/ButtonDevicePage.qml +++ b/nymea-app/ui/devicepages/ButtonDevicePage.qml @@ -10,6 +10,7 @@ DevicePageBase { GenericTypeLogView { anchors.fill: parent + id: logView logsModel: engine.jsonRpcClient.ensureServerVersion("1.10") ? logsModelNg : logsModel LogsModelNg { @@ -43,10 +44,12 @@ DevicePageBase { } onAddRuleClicked: { + var value = logView.logsModel.get(index).value + var typeId = logView.logsModel.get(index).typeId var rule = engine.ruleManager.createNewRule(); var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor(); eventDescriptor.deviceId = device.id; - var eventType = root.deviceClass.eventTypes.findByName("pressed"); + var eventType = root.deviceClass.eventTypes.getEventType(typeId); eventDescriptor.eventTypeId = eventType.id; rule.name = root.device.name + " - " + eventType.displayName; if (eventType.paramTypes.count === 1) { diff --git a/nymea-app/ui/devicepages/InputTriggerDevicePage.qml b/nymea-app/ui/devicepages/InputTriggerDevicePage.qml index bc331295..ebd7ff77 100644 --- a/nymea-app/ui/devicepages/InputTriggerDevicePage.qml +++ b/nymea-app/ui/devicepages/InputTriggerDevicePage.qml @@ -29,10 +29,12 @@ DevicePageBase { } onAddRuleClicked: { + var value = logView.logsModel.get(index).value + var typeId = logView.logsModel.get(index).typeId var rule = engine.ruleManager.createNewRule(); var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor(); eventDescriptor.deviceId = device.id; - var eventType = root.deviceClass.eventTypes.findByName("triggered"); + var eventType = root.deviceClass.eventTypes.getEventType(typeId); eventDescriptor.eventTypeId = eventType.id; rule.name = root.device.name + " - " + eventType.displayName; if (eventType.paramTypes.count === 1) { diff --git a/nymea-app/ui/devicepages/LightDevicePage.qml b/nymea-app/ui/devicepages/LightDevicePage.qml index aef70d86..62c645be 100644 --- a/nymea-app/ui/devicepages/LightDevicePage.qml +++ b/nymea-app/ui/devicepages/LightDevicePage.qml @@ -30,7 +30,7 @@ DevicePageBase { columns: app.landscape ? 2 : 1 AbstractButton { - Layout.preferredWidth: app.iconSize * 4 + Layout.preferredWidth: Math.max(app.iconSize * 4, parent.width / 5) Layout.preferredHeight: width Layout.leftMargin: app.margins Layout.rightMargin: app.landscape ? 0 : app.margins @@ -38,8 +38,18 @@ DevicePageBase { Layout.bottomMargin: app.landscape ? app.margins : 0 Layout.alignment: Qt.AlignCenter - ColorIcon { + Rectangle { anchors.fill: parent + color: "white" + border.color: root.powerState.value === true ? app.accentColor : bulbIcon.keyColor + border.width: 4 + radius: width / 2 + } + + ColorIcon { + id: bulbIcon + anchors.fill: parent + anchors.margins: app.margins * 1.5 name: root.powerState.value === true ? "../images/light-on.svg" : "../images/light-off.svg" color: root.powerState.value === true ? app.accentColor : keyColor } @@ -57,99 +67,161 @@ DevicePageBase { Layout.fillWidth: true visible: root.brightnessStateType - BrightnessSlider { - Layout.fillWidth: true + RowLayout { Layout.margins: app.margins - Layout.preferredHeight: 40 - brightness: root.brightnessState ? root.brightnessState.value : 0 - visible: root.brightnessStateType - onMoved: { - var params = [] - var param = {} - param["paramTypeId"] = root.brightnessActionType.paramTypes.get(0).id; - param["value"] = brightness; - params.push(param) - engine.deviceManager.executeAction(root.device.id, root.brightnessActionType.id, params); - } - } + spacing: app.margins - ColorPickerCt { - id: pickerCt - Layout.fillWidth: true - Layout.preferredHeight: 40 - Layout.margins: app.margins - ct: root.ctState ? root.ctState.value : 0 - visible: root.ctStateType - minCt: root.ctActionType ? root.ctActionType.paramTypes.findByName("colorTemperature").minValue : 0 - maxCt: root.ctActionType ? root.ctActionType.paramTypes.findByName("colorTemperature").maxValue : 0 + Repeater { + model: ListModel { + ListElement { name: "activate"; ct: "153"; bri: 100 } + ListElement { name: "concentrate"; ct: "233"; bri: 100 } + ListElement { name: "reading"; ct: "350"; bri: 100 } + ListElement { name: "relax"; ct: "480" ; bri: 55} + } + delegate: Pane { + Layout.fillWidth: true + Layout.preferredHeight: width + Material.elevation: 1 + padding: 0 + Image { + source: "../images/lighting/" + model.name + ".svg" + anchors.fill: parent + ItemDelegate { + anchors.fill: parent + onClicked: { + var params = []; + var param1 = {}; + param1["paramTypeId"] = root.ctActionType.paramTypes.get(0).id; + param1["value"] = model.ct; + params.push(param1) + engine.deviceManager.executeAction(root.device.id, root.ctActionType.id, params) + params = []; + param1 = {}; + param1["paramTypeId"] = root.brightnessActionType.paramTypes.get(0).id; + param1["value"] = model.bri; + params.push(param1) + engine.deviceManager.executeAction(root.device.id, root.brightnessActionType.id, params) + } + } + } - - touchDelegate: Rectangle { - height: pickerCt.height - width: 5 - color: app.foregroundColor - } - - property var lastSentTime: new Date() - onCtChanged: { - var currentTime = new Date(); - if (pressed && currentTime - lastSentTime > 200) { - setColorTemp(ct) - lastSentTime = currentTime } } + } - function setColorTemp(ct) { - var params = [] - var param = {} - param["paramTypeId"] = root.ctActionType.paramTypes.get(0).id; - param["value"] = ct; - params.push(param) - engine.deviceManager.executeAction(root.device.id, root.ctActionType.id, params); + Pane { + Layout.fillWidth: true + Layout.margins: app.margins + Layout.preferredHeight: 20 + Material.elevation: 1 + padding: 0 + + BrightnessSlider { + anchors.fill: parent + brightness: root.brightnessState ? root.brightnessState.value : 0 + visible: root.brightnessStateType + onMoved: { + var params = [] + var param = {} + param["paramTypeId"] = root.brightnessActionType.paramTypes.get(0).id; + param["value"] = brightness; + params.push(param) + engine.deviceManager.executeAction(root.device.id, root.brightnessActionType.id, params); + } } } - ColorPicker { - id: colorPicker + + Pane { Layout.fillWidth: true - Layout.preferredHeight: 80 Layout.margins: app.margins - visible: root.colorStateType + Layout.preferredHeight: 20 + Material.elevation: 1 + padding: 0 - color: root.colorState ? root.colorState.value : "white" - touchDelegate: Rectangle { - height: 15 - width: height - radius: height / 2 - color: app.foregroundColor + ColorPickerCt { + id: pickerCt + anchors.fill: parent + ct: root.ctState ? root.ctState.value : 0 + visible: root.ctStateType + minCt: root.ctActionType ? root.ctActionType.paramTypes.findByName("colorTemperature").minValue : 0 + maxCt: root.ctActionType ? root.ctActionType.paramTypes.findByName("colorTemperature").maxValue : 0 - Rectangle { - color: colorPicker.hovered || colorPicker.pressed ? "#11000000" : "transparent" - anchors.centerIn: parent - height: 30 + + touchDelegate: Rectangle { + height: pickerCt.height + width: 5 + color: app.foregroundColor + } + + property var lastSentTime: new Date() + onCtChanged: { + var currentTime = new Date(); + if (pressed && currentTime - lastSentTime > 200) { + setColorTemp(ct) + lastSentTime = currentTime + } + } + + function setColorTemp(ct) { + var params = [] + var param = {} + param["paramTypeId"] = root.ctActionType.paramTypes.get(0).id; + param["value"] = ct; + params.push(param) + engine.deviceManager.executeAction(root.device.id, root.ctActionType.id, params); + } + } + } + + Pane { + Layout.fillWidth: true + Layout.margins: app.margins + Layout.preferredHeight: 80 + Material.elevation: 1 + padding: 0 + + ColorPicker { + id: colorPicker + anchors.fill: parent + visible: root.colorStateType + + color: root.colorState ? root.colorState.value : "white" + touchDelegate: Rectangle { + height: 15 width: height - radius: width / 2 - Behavior on color { - ColorAnimation { - duration: 200 + radius: height / 2 + color: app.foregroundColor + + Rectangle { + color: colorPicker.hovered || colorPicker.pressed ? "#11000000" : "transparent" + anchors.centerIn: parent + height: 30 + width: height + radius: width / 2 + Behavior on color { + ColorAnimation { + duration: 200 + } } } } - } - property var lastSentTime: new Date() - onColorChanged: { - var currentTime = new Date(); - if (pressed && currentTime - lastSentTime > 200) { - var params = []; - var param1 = {}; - param1["paramTypeId"] = root.colorActionType.paramTypes.get(0).id; - param1["value"] = color; - params.push(param1) - engine.deviceManager.executeAction(root.device.id, root.colorActionType.id, params) - lastSentTime = currentTime + property var lastSentTime: new Date() + onColorChanged: { + var currentTime = new Date(); + if (pressed && currentTime - lastSentTime > 200) { + var params = []; + var param1 = {}; + param1["paramTypeId"] = root.colorActionType.paramTypes.get(0).id; + param1["value"] = color; + params.push(param1) + engine.deviceManager.executeAction(root.device.id, root.colorActionType.id, params) + lastSentTime = currentTime + } } } } + } } } diff --git a/nymea-app/ui/devicepages/StateLogPage.qml b/nymea-app/ui/devicepages/StateLogPage.qml index 35a7b62f..a3c2a5fe 100644 --- a/nymea-app/ui/devicepages/StateLogPage.qml +++ b/nymea-app/ui/devicepages/StateLogPage.qml @@ -78,10 +78,12 @@ Page { logsModel: engine.jsonRpcClient.ensureServerVersion("1.10") ? logsModelNg : logsModel onAddRuleClicked: { + var value = logView.logsModel.get(index).value + var typeId = logView.logsModel.get(index).typeId var rule = engine.ruleManager.createNewRule(); var stateEvaluator = rule.createStateEvaluator(); stateEvaluator.stateDescriptor.deviceId = device.id; - stateEvaluator.stateDescriptor.stateTypeId = root.stateType.id; + stateEvaluator.stateDescriptor.stateTypeId = typeId; stateEvaluator.stateDescriptor.value = value; stateEvaluator.stateDescriptor.valueOperator = StateDescriptor.ValueOperatorEquals; rule.setStateEvaluator(stateEvaluator); diff --git a/nymea-app/ui/images/lighting/activate.svg b/nymea-app/ui/images/lighting/activate.svg new file mode 100644 index 00000000..027b729d --- /dev/null +++ b/nymea-app/ui/images/lighting/activate.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/nymea-app/ui/images/lighting/concentrate.svg b/nymea-app/ui/images/lighting/concentrate.svg new file mode 100644 index 00000000..9e2d636b --- /dev/null +++ b/nymea-app/ui/images/lighting/concentrate.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/lighting/reading.svg b/nymea-app/ui/images/lighting/reading.svg new file mode 100644 index 00000000..8b993f16 --- /dev/null +++ b/nymea-app/ui/images/lighting/reading.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/lighting/relax.svg b/nymea-app/ui/images/lighting/relax.svg new file mode 100644 index 00000000..13b680ca --- /dev/null +++ b/nymea-app/ui/images/lighting/relax.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/nymea-app/ui/magic/DeviceRulesPage.qml b/nymea-app/ui/magic/DeviceRulesPage.qml index a817ab82..3ad724a3 100644 --- a/nymea-app/ui/magic/DeviceRulesPage.qml +++ b/nymea-app/ui/magic/DeviceRulesPage.qml @@ -46,8 +46,11 @@ Page { return; } rule = engine.ruleManager.createNewRule(); + d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule, initialDeviceToBeAdded: root.device}); + } else { + d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule}); } - d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule, initialDeviceToBeAdded: root.device}); + d.editRulePage.StackView.onRemoved.connect(function() { rule.destroy(); })