/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. * This project including source code and documentation is protected by * copyright law, and remains the property of nymea GmbH. All rights, including * reproduction, publication, editing and translation, are reserved. The use of * this project is subject to the terms of a license agreement to be concluded * with nymea GmbH in accordance with the terms of use of nymea GmbH, available * under https://nymea.io/license * * GNU General Public License Usage * Alternatively, this project may be redistributed and/or modified under the * terms of the GNU General Public License as published by the Free Software * Foundation, GNU version 3. This project is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with * this project. If not, see . * * For any further details and any questions please contact us under * contact@nymea.io or see our FAQ/Licensing Information on * https://nymea.io/license/faq * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import Nymea 1.0 import QtQuick.Controls.Material 2.2 import "../components" MouseArea { id: root preventStealing: true onWheel: wheel.accepted = true readonly property int count: groupsGridView.count GridView { id: groupsGridView anchors.fill: parent anchors.margins: app.margins / 2 readonly property int minTileWidth: 172 readonly property int tilesPerRow: root.width / minTileWidth model: TagListModel { tagsProxy: TagsProxyModel { tags: engine.tagsManager.tags filterTagId: "group-.*" } } cellWidth: width / tilesPerRow cellHeight: cellWidth delegate: Item { id: groupDelegate width: groupsGridView.cellWidth height: groupsGridView.cellHeight Pane { anchors.fill: parent anchors.margins: app.margins / 2 Material.elevation: 2 padding: 0 DevicesProxy { id: devicesInGroup engine: _engine filterTagId: model.tagId filterTagValue: model.value } InterfacesProxy { id: controlsInGroup shownInterfaces: ["light", "simpleclosable", "mediacontroller"] devicesProxyFilter: devicesInGroup showStates: true showActions: true } InterfacesProxy { id: sensorsInGroup shownInterfaces: ["temperaturesensor", "lightsensor", "presencesensor"] devicesProxyFilter: devicesInGroup showStates: true } contentItem: ItemDelegate { leftPadding: 0 topPadding: 0 rightPadding: 0 bottomPadding: 0 onClicked: { pageStack.push(Qt.resolvedUrl("../grouping/GroupPage.qml"), {groupTag: model.tagId}) } contentItem: ColumnLayout { Rectangle { Layout.fillWidth: true Layout.preferredHeight: 30 color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .05) Label { anchors.fill: parent verticalAlignment: Text.AlignVCenter anchors { leftMargin: app.margins; rightMargin: app.margins } text: model.tagId.substring(6) elide: Text.ElideRight } } Item { Layout.fillHeight: true Layout.fillWidth: true ColorIcon { anchors.centerIn: parent height: app.iconSize * 2 width: height visible: controlsInGroup.count == 0 color: app.accentColor name: "../images/view-grid-symbolic.svg" } ColumnLayout { anchors.fill: parent Repeater { model: Math.min(controlsInGroup.count, parent.height / 50) delegate: Loader { id: controlLoader Layout.fillWidth: true Layout.leftMargin: app.margins / 2 Layout.rightMargin: app.margins / 2 property string interfaceName: controlsInGroup.get(index).name sourceComponent: { switch (interfaceName) { case "simpleclosable": return closableDelegate case "light": return lightDelegate case "mediacontroller": return mediaControllerDelegate } } Binding { target: controlLoader.item property: "devices" value: devicesInGroup } } } Item { Layout.fillHeight: true Layout.fillWidth: true } } } Rectangle { Layout.fillWidth: true Layout.preferredHeight: app.iconSize * 1.2 color: Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, 0.05) RowLayout { anchors.fill: parent Repeater { model: sensorsInGroup delegate: Row { height: parent.height ColorIcon { height: app.iconSize * .8 width: height name: app.interfaceToIcon(model.name) color: app.interfaceToColor(model.name) } DevicesProxy { id: innerProxy engine: _engine parentProxy: devicesInGroup shownInterfaces: [model.name] } Led { visible: ["presencesensor"].indexOf(model.name) >= 0 state: { var stateName = null switch (model.name) { case "presencesensor": stateName = "isPresent" break; } if (!stateName) { return "off"; } var ret = false; for (var i = 0; i < innerProxy.count; i++) { ret |= innerProxy.get(i).states.getState(innerProxy.get(i).deviceClass.stateTypes.findByName(stateName).id).value } return ret ? "on" : "off"; } } Label { height: parent.height verticalAlignment: Text.AlignVCenter text: { var stateName = null; switch (model.name) { case "temperaturesensor": stateName = "temperature"; break; case "lightsensor": stateName = "lightIntensity" break; } if (!stateName) { return ""; } var ret = 0 for (var i = 0; i < innerProxy.count; i++) { ret += innerProxy.get(i).states.getState(innerProxy.get(i).deviceClass.stateTypes.findByName(stateName).id).value } return (ret / innerProxy.count).toFixed(1) } } } } } } } } } } } Component { id: lightDelegate RowLayout { property var devices DevicesProxy { id: lights engine: _engine parentProxy: devices shownInterfaces: ["light"] } DevicesProxy { id: dimmableLights engine: _engine parentProxy: devices shownInterfaces: ["dimmablelight"] } Label { text: qsTr("Lighting") Layout.fillWidth: true Layout.preferredHeight: slider.height verticalAlignment: Text.AlignVCenter visible: dimmableLights.count == 0 } Slider { id: slider from: 0 to: 100 visible: dimmableLights.count > 0 value: { var median = 0 var count = 0; for (var i = 0; i < dimmableLights.count; i++) { var device = dimmableLights.get(i); var brightnessId = device.deviceClass.stateTypes.findByName("brightness").id median += device.states.getState(brightnessId).value count++ } return median / count; } Layout.fillWidth: true onPressedChanged: { for (var i = 0; i < dimmableLights.count; i++) { var device = dimmableLights.get(i); var brightnessId = device.deviceClass.actionTypes.findByName("brightness").id engine.deviceManager.executeAction(device.id, brightnessId, [{paramTypeId: brightnessId, value: value}]); } } } ColorIcon { Layout.preferredHeight: app.iconSize Layout.preferredWidth: app.iconSize name: isOn ? "../images/light-on.svg" : "../images/light-off.svg" color: isOn ? app.accentColor : keyColor property bool isOn: { for (var i = 0; i < lights.count; i++) { var device = lights.get(i) var powerId = device.deviceClass.stateTypes.findByName("power").id if (device.states.getState(powerId).value === true) { return true } } return false; } MouseArea { anchors.fill: parent onClicked: { for (var i = 0; i < lights.count; i++) { var device = lights.get(i) var powerId = device.deviceClass.stateTypes.findByName("power").id engine.deviceManager.executeAction(device.id, powerId, [{paramTypeId: powerId, value: !parent.isOn}]) } } } } } } Component { id: closableDelegate RowLayout { property var devices: null DevicesProxy { id: simpleClosables engine: _engine parentProxy: devices shownInterfaces: ["simpleclosable"] } DevicesProxy { id: closables engine: _engine parentProxy: devices shownInterfaces: ["closable"] } ItemDelegate { Layout.fillWidth: true Layout.preferredHeight: app.iconSize ColorIcon { height: parent.height width: height anchors.centerIn: parent name: Qt.resolvedUrl("../images/up.svg") } onClicked: { for (var i = 0; i < simpleClosables.count; i++) { var device = simpleClosables.get(i) var openId = device.deviceClass.actionTypes.findByName("open").id engine.deviceManager.executeAction(device.id, openId) } } } ItemDelegate { Layout.fillWidth: true Layout.preferredHeight: app.iconSize visible: closables.count > 0 ColorIcon { height: parent.height width: height anchors.centerIn: parent name: Qt.resolvedUrl("../images/media-playback-stop.svg") } onClicked: { for (var i = 0; i < closables.count; i++) { var device = closables.get(i) var openId = device.deviceClass.actionTypes.findByName("stop").id engine.deviceManager.executeAction(device.id, openId) } } } ItemDelegate { Layout.fillWidth: true Layout.preferredHeight: app.iconSize ColorIcon { height: parent.height width: height anchors.centerIn: parent name: Qt.resolvedUrl("../images/down.svg") } onClicked: { for (var i = 0; i < simpleClosables.count; i++) { var device = simpleClosables.get(i) var closeId = device.deviceClass.actionTypes.findByName("close").id engine.deviceManager.executeAction(device.id, closeId) } } } } } Component { id: mediaControllerDelegate MediaControls { property var devices: null iconSize: app.iconSize DevicesProxy { id: mediaControllers engine: _engine parentProxy: devices shownInterfaces: ["mediacontroller"] } // involve count in the statement to make the binding re-evaluate when the group is changed device: mediaControllers.count > 0 ? mediaControllers.get(0) : null } } }