From ebe24abd8e8ca435d87f622e8f1fd5b2ab6ec207 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 1 Oct 2018 14:43:52 +0200 Subject: [PATCH] improve sensors page --- libnymea-app-core/models/interfacesproxy.cpp | 2 +- nymea-app/resources.qrc | 3 + nymea-app/ui/NewDeviceWizard.qml | 2 +- nymea-app/ui/Nymea.qml | 2 +- nymea-app/ui/customviews/WeatherView.qml | 51 ++++++-- .../ui/devicelistpages/DeviceListPageBase.qml | 37 ++++++ .../devicelistpages/GenericDeviceListPage.qml | 35 +---- .../devicelistpages/LightsDeviceListPage.qml | 44 +++---- .../devicelistpages/SensorsDeviceListPage.qml | 122 ++++++++++++++++++ .../devicelistpages/WeatherDeviceListPage.qml | 81 ++++++++++++ .../ui/devicepages/WeatherDevicePage.qml | 6 + .../ui/mainviews/DevicesPageDelegate.qml | 6 + 12 files changed, 326 insertions(+), 65 deletions(-) create mode 100644 nymea-app/ui/devicelistpages/DeviceListPageBase.qml create mode 100644 nymea-app/ui/devicelistpages/SensorsDeviceListPage.qml create mode 100644 nymea-app/ui/devicelistpages/WeatherDeviceListPage.qml diff --git a/libnymea-app-core/models/interfacesproxy.cpp b/libnymea-app-core/models/interfacesproxy.cpp index 972bfded..ce4a85ea 100644 --- a/libnymea-app-core/models/interfacesproxy.cpp +++ b/libnymea-app-core/models/interfacesproxy.cpp @@ -58,8 +58,8 @@ void InterfacesProxy::setShowStates(bool showStates) bool InterfacesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_UNUSED(source_parent) - qDebug() << "filterAcceptsRow"; QString interfaceName = m_interfaces->get(source_row)->name(); + qDebug() << "filterAcceptsRow" << interfaceName << m_shownInterfaces; if (!m_shownInterfaces.isEmpty()) { if (!m_shownInterfaces.contains(interfaceName)) { return false; diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index df6573e2..753acd11 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -250,5 +250,8 @@ ui/devicepages/NotificationsDevicePage.qml ui/components/BrightnessSlider.qml ui/devicepages/LightDevicePage.qml + ui/devicelistpages/SensorsDeviceListPage.qml + ui/devicelistpages/WeatherDeviceListPage.qml + ui/devicelistpages/DeviceListPageBase.qml diff --git a/nymea-app/ui/NewDeviceWizard.qml b/nymea-app/ui/NewDeviceWizard.qml index b72b000f..1e670f70 100644 --- a/nymea-app/ui/NewDeviceWizard.qml +++ b/nymea-app/ui/NewDeviceWizard.qml @@ -120,7 +120,7 @@ Page { print("should setup", deviceClass.name, deviceClass.setupMethod, deviceClass.createMethods, deviceClass["discoveryParamTypes"].count) } - swipe.enabled: deviceClass.createMethods.indexOf("CreateMethodUser") !== -1 + swipe.enabled: true// deviceClass.createMethods.indexOf("CreateMethodUser") !== -1 swipe.right: MouseArea { height: deviceClassDelegate.height width: height diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index e78c6866..6bcbc5cc 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -369,7 +369,7 @@ ApplicationWindow { } else if (interfaceList.indexOf("garagegate") >= 0 ) { page = "GarageGateDevicePage.qml"; } else if (interfaceList.indexOf("light") >= 0) { - page = "ColorLightDevicePage.qml"; + page = "LightDevicePage.qml"; } else if (interfaceList.indexOf("extendedshutter") >= 0 ) { page = "ShutterDevicePage.qml"; } else if (interfaceList.indexOf("extendedawning") >= 0) { diff --git a/nymea-app/ui/customviews/WeatherView.qml b/nymea-app/ui/customviews/WeatherView.qml index d92b089a..ad072d7c 100644 --- a/nymea-app/ui/customviews/WeatherView.qml +++ b/nymea-app/ui/customviews/WeatherView.qml @@ -19,6 +19,9 @@ CustomViewBase { readonly property var humidityStateType: deviceClass.stateTypes ? deviceClass.stateTypes.findByName("humidity") : null readonly property var humidityState: humidityStateType && device.states ? device.states.getState(humidityStateType.id) : null + readonly property var pressureStateType: deviceClass.stateTypes ? deviceClass.stateTypes.findByName("pressure") : null + readonly property var pressureState: pressureStateType && device.states ? device.states.getState(pressureStateType.id) : null + readonly property var windDirectionStateType: deviceClass.stateTypes ? deviceClass.stateTypes.findByName("windDirection") : null readonly property var windDirectionState: windDirectionStateType && device.states ? device.states.getState(windDirectionStateType.id) : null @@ -33,12 +36,38 @@ CustomViewBase { RowLayout { Layout.fillWidth: true - Label { - text: (temperatureState ? Math.round(temperatureState.value * 10) / 10 : "N/A") + " °" + Item { Layout.fillWidth: true Layout.preferredWidth: (parent.width - mainImage.width) / 2 - font.pixelSize: app.largeFont - horizontalAlignment: Text.AlignHCenter + + GridLayout { + anchors.centerIn: parent + columns: 2 + ColorIcon { + name: "../images/sensors/temperature.svg" + Layout.preferredWidth: app.iconSize + Layout.preferredHeight: width + color: app.interfaceToColor("temperaturesensor") + } + Label { + text: (temperatureState ? Math.round(temperatureState.value * 10) / 10 : "N/A") + " °" + Layout.fillWidth: true + font.pixelSize: app.largeFont + horizontalAlignment: Text.AlignHCenter + } + ColorIcon { + name: "../images/weathericons/humidity.svg" + Layout.preferredWidth: app.iconSize + Layout.preferredHeight: width + color: app.interfaceToColor("humiditysensor") + } + Label { + text: (humidityState ? humidityState.value : "N/A") + " %" + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + } + } + } ColorIcon { @@ -47,21 +76,23 @@ CustomViewBase { Layout.preferredHeight: app.largeFont * 4 name: weatherConditionState ? "../images/weathericons/weather-" + weatherConditionState.value + ".svg" : "" } - ColumnLayout { + + Item { Layout.fillWidth: true Layout.preferredWidth: (parent.width - mainImage.width) / 2 - RowLayout { + GridLayout { + columns: 2 + anchors.centerIn: parent ColorIcon { - name: "../images/weathericons/humidity.svg" + name: "../images/sensors/pressure.svg" width: app.iconSize height: width + color: app.interfaceToColor("pressuresensor") } Label { - text: (humidityState ? humidityState.value : "N/A") + " %" + text: (pressureState ? pressureState.value : "N/A") + " %" } - } - RowLayout { ColorIcon { name: "../images/weathericons/wind.svg" width: app.iconSize diff --git a/nymea-app/ui/devicelistpages/DeviceListPageBase.qml b/nymea-app/ui/devicelistpages/DeviceListPageBase.qml new file mode 100644 index 00000000..1e1f649c --- /dev/null +++ b/nymea-app/ui/devicelistpages/DeviceListPageBase.qml @@ -0,0 +1,37 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.1 +import Nymea 1.0 +import "../components" + +Page { + id: root + + property alias shownInterfaces: devicesProxyInternal.shownInterfaces + property alias hiddenInterfaces: devicesProxyInternal.hiddenInterfaces + + Component.onCompleted: { + if (devicesProxyInternal.count === 1) { + enterPage(0, true) + } + } + + property var devicesProxy: devicesProxyInternal + + function enterPage(index, replace) { + var device = devicesProxy.get(index); + var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); + var page = app.interfaceListToDevicePage(deviceClass.interfaces); + if (replace) { + pageStack.replace(Qt.resolvedUrl("../devicepages/" + page), {device: devicesProxy.get(index)}) + } else { + pageStack.push(Qt.resolvedUrl("../devicepages/" + page), {device: devicesProxy.get(index)}) + } + } + + DevicesProxy { + id: devicesProxyInternal + devices: Engine.deviceManager.devices + } +} diff --git a/nymea-app/ui/devicelistpages/GenericDeviceListPage.qml b/nymea-app/ui/devicelistpages/GenericDeviceListPage.qml index 4d2756a0..a62398f3 100644 --- a/nymea-app/ui/devicelistpages/GenericDeviceListPage.qml +++ b/nymea-app/ui/devicelistpages/GenericDeviceListPage.qml @@ -5,50 +5,27 @@ import Nymea 1.0 import "../components" import "../delegates" -Page { - id: subPage - property alias shownInterfaces: devicesProxy.shownInterfaces - property alias hiddenInterfaces: devicesProxy.hiddenInterfaces - - Component.onCompleted: { - if (devicesProxy.count == 1) { - enterPage(0, true) - } - } +DeviceListPageBase { + id: root header: GuhHeader { text: { - if (subPage.shownInterfaces.length === 1) { - return qsTr("My %1").arg(app.interfaceToString(subPage.shownInterfaces[0])) - } else if (subPage.shownInterfaces.length > 1 || subPage.hiddenInterfaces.length > 0) { + if (root.shownInterfaces.length === 1) { + return qsTr("My %1").arg(app.interfaceToString(root.shownInterfaces[0])) + } else if (root.shownInterfaces.length > 1 || root.hiddenInterfaces.length > 0) { return qsTr("My things") } return qsTr("All my things") } onBackPressed: { - print("popping") pageStack.pop() } } - function enterPage(index, replace) { - var device = devicesProxy.get(index); - var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); - var page = app.interfaceListToDevicePage(deviceClass.interfaces); - if (replace) { - pageStack.replace(Qt.resolvedUrl("../devicepages/" + page), {device: devicesProxy.get(index)}) - } else { - pageStack.push(Qt.resolvedUrl("../devicepages/" + page), {device: devicesProxy.get(index)}) - } - } - ListView { anchors.fill: parent - model: DevicesProxy { - id: devicesProxy - devices: Engine.deviceManager.devices - } + model: root.devicesProxy delegate: ThingDelegate { width: parent.width device: Engine.deviceManager.devices.getDevice(model.id); diff --git a/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml b/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml index fe25cfde..e6bc0927 100644 --- a/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml +++ b/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml @@ -1,11 +1,12 @@ import QtQuick 2.5 import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 import QtQuick.Layouts 1.1 import Nymea 1.0 import "../components" -Page { - property alias shownInterfaces: devicesProxy.shownInterfaces +DeviceListPageBase { + header: GuhHeader { text: qsTr("Lights") onBackPressed: pageStack.pop() @@ -31,12 +32,10 @@ Page { ListView { anchors.fill: parent - model: DevicesProxy { - id: devicesProxy - devices: Engine.deviceManager.devices - } + model: devicesProxy + spacing: app.margins - delegate: ItemDelegate { + delegate: Pane { id: itemDelegate width: parent.width @@ -59,24 +58,26 @@ Page { property var colorStateType: deviceClass.stateTypes.findByName("color"); property var colorState: colorStateType ? device.states.getState(colorStateType.id) : null + Material.elevation: 1 topPadding: 0 bottomPadding: 0 leftPadding: 0 rightPadding: 0 - contentItem: Rectangle { + contentItem: ItemDelegate { id: contentItem - implicitHeight: itemDelegate.brightnessStateType && !itemDelegate.inline && enabled ? nameRow.implicitHeight + sliderRow.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) } - } + implicitHeight: itemDelegate.brightnessStateType && !itemDelegate.inline && nameRow.enabled ? nameRow.implicitHeight + sliderRow.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) } + // } - enabled: itemDelegate.connectedState === null || itemDelegate.connectedState.value === true - ColumnLayout { - anchors { left: parent.left; right: parent.right; margins: app.margins } + topPadding: 0 + + contentItem: ColumnLayout { spacing: 0 RowLayout { + enabled: itemDelegate.connectedState === null || itemDelegate.connectedState.value === true id: nameRow z: 2 // make sure the switch in here is on top of the slider, given we cheated a bit and made them overlap spacing: app.margins @@ -133,7 +134,7 @@ Page { ThrottledSlider { id: outlineSlider anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter } - visible: contentItem.enabled && itemDelegate.brightnessStateType && !inlineSlider.visible + visible: nameRow.enabled && itemDelegate.brightnessStateType && !inlineSlider.visible from: 0; to: 100 value: itemDelegate.brightnessState ? itemDelegate.brightnessState.value : 0 onMoved: { @@ -147,12 +148,9 @@ Page { } } } - } - - onClicked: { - var device = devicesProxy.get(index); - var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) - pageStack.push(Qt.resolvedUrl("../devicepages/LightDevicePage.qml"), {device: devicesProxy.get(index)}) + onClicked: { + enterPage(index, false) + } } } } diff --git a/nymea-app/ui/devicelistpages/SensorsDeviceListPage.qml b/nymea-app/ui/devicelistpages/SensorsDeviceListPage.qml new file mode 100644 index 00000000..91e7f880 --- /dev/null +++ b/nymea-app/ui/devicelistpages/SensorsDeviceListPage.qml @@ -0,0 +1,122 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.1 +import Nymea 1.0 +import "../components" + +DeviceListPageBase { + id: root + + header: GuhHeader { + text: qsTr("Sensors") + onBackPressed: pageStack.pop() + } + + ListView { + anchors.fill: parent + model: root.devicesProxy + + delegate: ItemDelegate { + id: itemDelegate + width: parent.width + + property bool inline: width > 500 + + property var device: devicesProxy.get(index); + property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); + + bottomPadding: index === ListView.view.count - 1 ? topPadding : 0 + contentItem: Pane { + id: contentItem + Material.elevation: 2 + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + + contentItem: ItemDelegate { + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + contentItem: ColumnLayout { + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: app.mediumFont + app.margins + color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .05) + RowLayout { + anchors { verticalCenter: parent.verticalCenter; left: parent.left; right: parent.right; margins: app.margins } + Label { + Layout.fillWidth: true + text: model.name + elide: Text.ElideRight + } + ColorIcon { + Layout.preferredHeight: app.iconSize * .5 + Layout.preferredWidth: height + name: "../images/battery/battery-020.svg" + visible: itemDelegate.deviceClass.interfaces.indexOf("battery") >= 0 && itemDelegate.device.states.getState(itemDelegate.deviceClass.stateTypes.findByName("batteryCritical").id).value === true + } + ColorIcon { + Layout.preferredHeight: app.iconSize * .5 + Layout.preferredWidth: height + name: "../images/dialog-warning-symbolic.svg" + visible: itemDelegate.deviceClass.interfaces.indexOf("connectable") >= 0 && itemDelegate.device.states.getState(itemDelegate.deviceClass.stateTypes.findByName("connected").id).value === false + color: "red" + } + } + + } + GridLayout { + id: dataGrid + columns: Math.floor(contentItem.width / 120) + Layout.margins: app.margins + Repeater { + model: ListModel { + ListElement { interfaceName: "temperaturesensor"; stateName: "temperature" } + ListElement { interfaceName: "humiditysensor"; stateName: "humidity" } + ListElement { interfaceName: "moisturesensor"; stateName: "moisture" } + ListElement { interfaceName: "pressuresensor"; stateName: "pressure" } + ListElement { interfaceName: "lightsensor"; stateName: "lightIntensity" } + ListElement { interfaceName: "conductivitysensor"; stateName: "conductivity" } + } + + delegate: RowLayout { + id: sensorValueDelegate + visible: itemDelegate.deviceClass.interfaces.indexOf(model.interfaceName) >= 0 + Layout.preferredWidth: contentItem.width / dataGrid.columns + + property var stateType: itemDelegate.deviceClass.stateTypes.findByName(model.stateName) + property var stateValue: stateType ? itemDelegate.device.states.getState(stateType.id) : null + + ColorIcon { + Layout.preferredHeight: app.iconSize * .8 + Layout.preferredWidth: height + Layout.alignment: Qt.AlignVCenter + color: app.interfaceToColor(model.interfaceName) + name: app.interfaceToIcon(model.interfaceName) + } + + Label { + Layout.fillWidth: true + text: sensorValueDelegate.stateValue + ? "%1 %2".arg(sensorValueDelegate.stateValue.value).arg(sensorValueDelegate.stateType.unitString) + : "" + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + font.pixelSize: app.smallFont + } + } + } + } + + } + onClicked: { + enterPage(index, false) + } + } + } + } + } +} diff --git a/nymea-app/ui/devicelistpages/WeatherDeviceListPage.qml b/nymea-app/ui/devicelistpages/WeatherDeviceListPage.qml new file mode 100644 index 00000000..5711e57e --- /dev/null +++ b/nymea-app/ui/devicelistpages/WeatherDeviceListPage.qml @@ -0,0 +1,81 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.1 +import QtQuick.Layouts 1.1 +import Nymea 1.0 +import "../components" +import "../customviews" + +DeviceListPageBase { + id: root + + header: GuhHeader { + text: qsTr("Weather") + onBackPressed: pageStack.pop() + } + + ListView { + anchors.fill: parent + model: root.devicesProxy + + delegate: ItemDelegate { + id: itemDelegate + width: parent.width + + property bool inline: width > 500 + + property var device: devicesProxy.get(index); + property var deviceClass: Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); + + bottomPadding: index === ListView.view.count - 1 ? topPadding : 0 + contentItem: Pane { + id: contentItem + Material.elevation: 2 + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + + contentItem: ItemDelegate { + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + contentItem: ColumnLayout { + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: app.mediumFont + app.margins + color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .05) + RowLayout { + anchors { verticalCenter: parent.verticalCenter; left: parent.left; right: parent.right; margins: app.margins } + Label { + Layout.fillWidth: true + text: model.name + elide: Text.ElideRight + } + ColorIcon { + Layout.preferredHeight: app.iconSize * .5 + Layout.preferredWidth: height + name: "../images/dialog-warning-symbolic.svg" + visible: itemDelegate.deviceClass.interfaces.indexOf("connectable") >= 0 && itemDelegate.device.states.getState(itemDelegate.deviceClass.stateTypes.findByName("connected").id).value === false + color: "red" + } + } + } + + WeatherView { + Layout.fillWidth: true + device: itemDelegate.device + deviceClass: itemDelegate.deviceClass + } + } + onClicked: { + var device = devicesProxy.get(index); + var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) + pageStack.push(Qt.resolvedUrl("../devicepages/WeatherDevicePage.qml"), {device: devicesProxy.get(index)}) + } + } + } + } + } +} diff --git a/nymea-app/ui/devicepages/WeatherDevicePage.qml b/nymea-app/ui/devicepages/WeatherDevicePage.qml index 8354c579..6a7c7543 100644 --- a/nymea-app/ui/devicepages/WeatherDevicePage.qml +++ b/nymea-app/ui/devicepages/WeatherDevicePage.qml @@ -32,6 +32,12 @@ DevicePageBase { deviceClass: root.deviceClass interfaceName: "humiditysensor" } + SensorView { + Layout.fillWidth: true + device: root.device + deviceClass: root.deviceClass + interfaceName: "pressuresensor" + } } } } diff --git a/nymea-app/ui/mainviews/DevicesPageDelegate.qml b/nymea-app/ui/mainviews/DevicesPageDelegate.qml index 91143d00..38034476 100644 --- a/nymea-app/ui/mainviews/DevicesPageDelegate.qml +++ b/nymea-app/ui/mainviews/DevicesPageDelegate.qml @@ -16,6 +16,12 @@ MainPageTile { onClicked: { var page; switch (model.name) { + case "sensor": + page = "SensorsDeviceListPage.qml" + break; + case "weather": + page = "WeatherDeviceListPage.qml" + break; case "light": page = "LightsDeviceListPage.qml" break;