Merge PR #398: Improve garage door views
This commit is contained in:
commit
dc83ff345f
@ -263,7 +263,7 @@ void DeviceManager::getVendorsResponse(const QVariantMap ¶ms)
|
||||
|
||||
void DeviceManager::getSupportedDevicesResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
// qDebug() << "DeviceClass received:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented));
|
||||
qDebug() << "DeviceClass received:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented));
|
||||
if (params.value("params").toMap().keys().contains("deviceClasses")) {
|
||||
QVariantList deviceClassList = params.value("params").toMap().value("deviceClasses").toList();
|
||||
foreach (QVariant deviceClassVariant, deviceClassList) {
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
Engine::Engine(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_jsonRpcClient(new JsonRpcClient(this)),
|
||||
m_deviceManager(new DeviceManager(m_jsonRpcClient, this)),
|
||||
m_thingManager(new DeviceManager(m_jsonRpcClient, this)),
|
||||
m_ruleManager(new RuleManager(m_jsonRpcClient, this)),
|
||||
m_scriptManager(new ScriptManager(m_jsonRpcClient, this)),
|
||||
m_logManager(new LogManager(m_jsonRpcClient, this)),
|
||||
@ -53,7 +53,7 @@ Engine::Engine(QObject *parent) :
|
||||
|
||||
connect(m_jsonRpcClient, &JsonRpcClient::connectedChanged, this, &Engine::onConnectedChanged);
|
||||
|
||||
connect(m_deviceManager, &DeviceManager::fetchingDataChanged, this, &Engine::onDeviceManagerFetchingChanged);
|
||||
connect(m_thingManager, &DeviceManager::fetchingDataChanged, this, &Engine::onDeviceManagerFetchingChanged);
|
||||
|
||||
connect(AWSClient::instance(), &AWSClient::devicesFetched, this, [this]() {
|
||||
if (m_jsonRpcClient->connected() && m_jsonRpcClient->cloudConnectionState() == JsonRpcClient::CloudConnectionStateConnected) {
|
||||
@ -74,7 +74,12 @@ Engine::Engine(QObject *parent) :
|
||||
|
||||
DeviceManager *Engine::deviceManager() const
|
||||
{
|
||||
return m_deviceManager;
|
||||
return m_thingManager;
|
||||
}
|
||||
|
||||
DeviceManager *Engine::thingManager() const
|
||||
{
|
||||
return m_thingManager;
|
||||
}
|
||||
|
||||
RuleManager *Engine::ruleManager() const
|
||||
@ -131,20 +136,20 @@ void Engine::deployCertificate()
|
||||
void Engine::onConnectedChanged()
|
||||
{
|
||||
qDebug() << "Engine: connected changed:" << m_jsonRpcClient->connected();
|
||||
m_deviceManager->clear();
|
||||
m_thingManager->clear();
|
||||
m_ruleManager->clear();
|
||||
m_tagsManager->clear();
|
||||
if (m_jsonRpcClient->connected()) {
|
||||
qDebug() << "Engine: inital setup required:" << m_jsonRpcClient->initialSetupRequired() << "auth required:" << m_jsonRpcClient->authenticationRequired();
|
||||
if (!m_jsonRpcClient->initialSetupRequired() && !m_jsonRpcClient->authenticationRequired()) {
|
||||
m_deviceManager->init();
|
||||
m_thingManager->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::onDeviceManagerFetchingChanged()
|
||||
{
|
||||
if (!m_deviceManager->fetchingData()) {
|
||||
if (!m_thingManager->fetchingData()) {
|
||||
m_ruleManager->init();
|
||||
m_scriptManager->init();
|
||||
m_nymeaConfiguration->init();
|
||||
|
||||
@ -50,6 +50,7 @@ class Engine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(DeviceManager* deviceManager READ deviceManager CONSTANT)
|
||||
Q_PROPERTY(DeviceManager* thingManager READ thingManager CONSTANT)
|
||||
Q_PROPERTY(RuleManager* ruleManager READ ruleManager CONSTANT)
|
||||
Q_PROPERTY(ScriptManager* scriptManager READ scriptManager CONSTANT)
|
||||
Q_PROPERTY(TagsManager* tagsManager READ tagsManager CONSTANT)
|
||||
@ -64,6 +65,7 @@ public:
|
||||
QString connectedHost() const;
|
||||
|
||||
DeviceManager *deviceManager() const;
|
||||
DeviceManager *thingManager() const;
|
||||
RuleManager *ruleManager() const;
|
||||
ScriptManager *scriptManager() const;
|
||||
TagsManager *tagsManager() const;
|
||||
@ -76,7 +78,7 @@ public:
|
||||
|
||||
private:
|
||||
JsonRpcClient *m_jsonRpcClient;
|
||||
DeviceManager *m_deviceManager;
|
||||
DeviceManager *m_thingManager;
|
||||
RuleManager *m_ruleManager;
|
||||
ScriptManager *m_scriptManager;
|
||||
LogManager *m_logManager;
|
||||
|
||||
@ -68,6 +68,11 @@ QUuid Device::deviceClassId() const
|
||||
return m_deviceClass->id();
|
||||
}
|
||||
|
||||
QUuid Device::thingClassId() const
|
||||
{
|
||||
return m_deviceClass->id();
|
||||
}
|
||||
|
||||
QUuid Device::parentDeviceId() const
|
||||
{
|
||||
return m_parentDeviceId;
|
||||
@ -153,6 +158,11 @@ DeviceClass *Device::deviceClass() const
|
||||
return m_deviceClass;
|
||||
}
|
||||
|
||||
DeviceClass *Device::thingClass() const
|
||||
{
|
||||
return m_deviceClass;
|
||||
}
|
||||
|
||||
bool Device::hasState(const QUuid &stateTypeId)
|
||||
{
|
||||
foreach (State *state, states()->states()) {
|
||||
|
||||
@ -46,6 +46,7 @@ class Device : public QObject
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUuid id READ id CONSTANT)
|
||||
Q_PROPERTY(QUuid deviceClassId READ deviceClassId CONSTANT)
|
||||
Q_PROPERTY(QUuid thingClassId READ thingClassId CONSTANT)
|
||||
Q_PROPERTY(QUuid parentDeviceId READ parentDeviceId CONSTANT)
|
||||
Q_PROPERTY(bool isChild READ isChild CONSTANT)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
@ -55,6 +56,7 @@ class Device : public QObject
|
||||
Q_PROPERTY(Params *settings READ settings NOTIFY settingsChanged)
|
||||
Q_PROPERTY(States *states READ states NOTIFY statesChanged)
|
||||
Q_PROPERTY(DeviceClass *deviceClass READ deviceClass CONSTANT)
|
||||
Q_PROPERTY(DeviceClass *thingClass READ thingClass CONSTANT)
|
||||
|
||||
public:
|
||||
enum DeviceSetupStatus {
|
||||
@ -74,6 +76,7 @@ public:
|
||||
void setName(const QString &name);
|
||||
|
||||
QUuid deviceClassId() const;
|
||||
QUuid thingClassId() const;
|
||||
QUuid parentDeviceId() const;
|
||||
bool isChild() const;
|
||||
|
||||
@ -91,6 +94,7 @@ public:
|
||||
void setStates(States *states);
|
||||
|
||||
DeviceClass *deviceClass() const;
|
||||
DeviceClass *thingClass() const;
|
||||
|
||||
Q_INVOKABLE bool hasState(const QUuid &stateTypeId);
|
||||
|
||||
|
||||
@ -129,8 +129,8 @@ QString DeviceClass::baseInterface() const
|
||||
if (interface == "blind") {
|
||||
return "blind";
|
||||
}
|
||||
if (interface == "garagegate") {
|
||||
return "garagegate";
|
||||
if (interface == "garagedoor") {
|
||||
return "garagedoor";
|
||||
}
|
||||
if (interface == "inputtrigger") {
|
||||
return "inputtrigger";
|
||||
|
||||
@ -199,7 +199,20 @@ Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent)
|
||||
pts = createParamTypes("user", tr("User"), QVariant::String);
|
||||
addActionType("useraccesscontrol", "removeUser", tr("Remove user"), pts);
|
||||
|
||||
addInterface("garagegate", tr("Garage doors"), {"closable"});
|
||||
addInterface("garagedoor", tr("Garage doors"));
|
||||
|
||||
addInterface("impulsegaragedoor", tr("Garage doors"), {"garagedoor"});
|
||||
addActionType("impulsegaragedoor", "triggerImpulse", tr("Operate"), new ParamTypes());
|
||||
|
||||
addInterface("simplegaragedoor", tr("Garage doors"), {"garagedoor", "closable"});
|
||||
|
||||
addInterface("statefulgaragedoor", tr("Garage doors"), {"garagedoor", "closable"});
|
||||
addStateType("statefulgaragedoor", "state", QVariant::String, false, tr("State"), tr("State changed"));
|
||||
|
||||
addInterface("extendedstatfulgaragedoor", tr("Garage doors"), {"statefulgaragedoor", "extendedclosable"});
|
||||
|
||||
// Deprecated garagegate
|
||||
addInterface("garagegate", tr("Garage doors"), {"garagedoor", "closable"});
|
||||
addStateType("garagegate", "state", QVariant::String, false, tr("State"), tr("State changed"));
|
||||
addStateType("garagegate", "intermediatePosition", QVariant::Bool, false, tr("Intermediate position"), tr("Intermediate position changed"));
|
||||
|
||||
|
||||
@ -131,7 +131,7 @@
|
||||
<file>ui/images/settings.svg</file>
|
||||
<file>ui/images/share.svg</file>
|
||||
<file>ui/images/slideshow.svg</file>
|
||||
<file>ui/images/sort-listitem.svg</file>
|
||||
<file>ui/images/closable-move.svg</file>
|
||||
<file>ui/images/starred.svg</file>
|
||||
<file>ui/images/state-interface.svg</file>
|
||||
<file>ui/images/state.svg</file>
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
<file>ui/devicepages/InputTriggerDevicePage.qml</file>
|
||||
<file>ui/devicepages/StateLogPage.qml</file>
|
||||
<file>ui/devicepages/ShutterDevicePage.qml</file>
|
||||
<file>ui/devicepages/GarageGateDevicePage.qml</file>
|
||||
<file>ui/devicepages/GarageThingPage.qml</file>
|
||||
<file>ui/devicepages/AwningDevicePage.qml</file>
|
||||
<file>ui/devicepages/NotificationsDevicePage.qml</file>
|
||||
<file>ui/devicepages/LightDevicePage.qml</file>
|
||||
@ -75,7 +75,7 @@
|
||||
<file>ui/devicepages/DeviceLogPage.qml</file>
|
||||
<file>ui/devicelistpages/GenericDeviceListPage.qml</file>
|
||||
<file>ui/devicelistpages/ClosablesDeviceListPage.qml</file>
|
||||
<file>ui/devicelistpages/GarageDeviceListPage.qml</file>
|
||||
<file>ui/devicelistpages/GarageThingListPage.qml</file>
|
||||
<file>ui/devicelistpages/AwningDeviceListPage.qml</file>
|
||||
<file>ui/devicelistpages/ShutterDeviceListPage.qml</file>
|
||||
<file>ui/devicelistpages/BlindDeviceListPage.qml</file>
|
||||
|
||||
@ -110,7 +110,7 @@ ApplicationWindow {
|
||||
"light",
|
||||
"weather",
|
||||
"media",
|
||||
"garagegate",
|
||||
"garagedoor",
|
||||
"awning",
|
||||
"shutter",
|
||||
"blind",
|
||||
@ -172,7 +172,7 @@ ApplicationWindow {
|
||||
case "awning":
|
||||
case "extendedawning":
|
||||
return qsTr("Awnings");
|
||||
case "garagegate":
|
||||
case "garagedoor":
|
||||
return qsTr("Garage doors");
|
||||
case "accesscontrol":
|
||||
return qsTr("Access control");
|
||||
@ -209,6 +209,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function interfacesToIcon(interfaces) {
|
||||
print("finding icon for interfaces:", interfaces)
|
||||
for (var i = 0; i < interfaces.length; i++) {
|
||||
var icon = interfaceToIcon(interfaces[i]);
|
||||
if (icon !== "") {
|
||||
@ -219,6 +220,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function interfaceToIcon(name) {
|
||||
print("finding icon for interface:", name)
|
||||
switch (name) {
|
||||
case "light":
|
||||
case "colorlight":
|
||||
@ -279,7 +281,7 @@ ApplicationWindow {
|
||||
case "blind":
|
||||
case "extendedblind":
|
||||
return Qt.resolvedUrl("images/shutter/shutter-060.svg")
|
||||
case "garagegate":
|
||||
case "garagedoor":
|
||||
return Qt.resolvedUrl("images/garage/garage-100.svg")
|
||||
case "awning":
|
||||
case "extendedawning":
|
||||
@ -289,7 +291,7 @@ ApplicationWindow {
|
||||
case "uncategorized":
|
||||
return Qt.resolvedUrl("images/select-none.svg")
|
||||
case "simpleclosable":
|
||||
return Qt.resolvedUrl("images/sort-listitem.svg")
|
||||
return Qt.resolvedUrl("images/closable-move.svg")
|
||||
case "fingerprintreader":
|
||||
return Qt.resolvedUrl("images/fingerprint.svg")
|
||||
case "accesscontrol":
|
||||
@ -451,8 +453,8 @@ ApplicationWindow {
|
||||
page = "SensorDevicePage.qml";
|
||||
} else if (interfaceList.indexOf("inputtrigger") >= 0) {
|
||||
page = "InputTriggerDevicePage.qml";
|
||||
} else if (interfaceList.indexOf("garagegate") >= 0 ) {
|
||||
page = "GarageGateDevicePage.qml";
|
||||
} else if (interfaceList.indexOf("garagedoor") >= 0 ) {
|
||||
page = "GarageThingPage.qml";
|
||||
} else if (interfaceList.indexOf("light") >= 0) {
|
||||
page = "LightDevicePage.qml";
|
||||
} else if (interfaceList.indexOf("shutter") >= 0 || interfaceList.indexOf("blind") >= 0) {
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
|
||||
ClosablesDeviceListPage {
|
||||
title: qsTr("Garage gates")
|
||||
iconBasename: "../images/shutter/shutter"
|
||||
}
|
||||
287
nymea-app/ui/devicelistpages/GarageThingListPage.qml
Normal file
287
nymea-app/ui/devicelistpages/GarageThingListPage.qml
Normal file
@ -0,0 +1,287 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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.5
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Controls.Material 2.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtGraphicalEffects 1.0
|
||||
import Nymea 1.0
|
||||
import "../components"
|
||||
|
||||
DeviceListPageBase {
|
||||
id: root
|
||||
|
||||
property string iconBasename: "../images/garage/garage"
|
||||
|
||||
header: NymeaHeader {
|
||||
id: header
|
||||
onBackPressed: pageStack.pop()
|
||||
text: root.title
|
||||
}
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
model: devicesProxy
|
||||
spacing: app.margins
|
||||
|
||||
delegate: Pane {
|
||||
id: itemDelegate
|
||||
width: parent.width
|
||||
|
||||
|
||||
property bool inline: width > 500
|
||||
|
||||
property Device device: devicesProxy.getDevice(model.id)
|
||||
property Device thing: device
|
||||
property DeviceClass deviceClass: device.deviceClass
|
||||
|
||||
readonly property bool isImpulseBased: device.deviceClass.interfaces.indexOf("impulsegaragedoor") >= 0
|
||||
readonly property bool isStateful: device.deviceClass.interfaces.indexOf("statefulgaragedoor") >= 0
|
||||
|| device.deviceClass.interfaces.indexOf("garagegate") >= 0 // garagegate did not inherit garagedoor before 0.23
|
||||
readonly property bool isExtended: device.deviceClass.interfaces.indexOf("extendedstatefulgaragedoor") >= 0
|
||||
|
||||
property var connectedStateType: deviceClass.stateTypes.findByName("connected");
|
||||
property var connectedState: connectedStateType ? device.states.getState(connectedStateType.id) : null
|
||||
|
||||
|
||||
property StateType movingStateType: deviceClass.stateTypes.findByName("moving");
|
||||
property ActionType movingActionType: deviceClass.actionTypes.findByName("moving");
|
||||
property State movingState: movingStateType ? device.states.getState(movingStateType.id) : null
|
||||
|
||||
Material.elevation: 1
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
contentItem: ItemDelegate {
|
||||
id: contentItem
|
||||
implicitHeight: contentLoader.item.implicitHeight
|
||||
|
||||
topPadding: 0
|
||||
|
||||
contentItem: Loader {
|
||||
id: contentLoader
|
||||
enabled: itemDelegate.connectedState === null || itemDelegate.connectedState.value === true
|
||||
sourceComponent: isImpulseBased ? impulseGaragedoor
|
||||
: isExtended ? extendedStatefulGaragedoor
|
||||
: isStateful ? garagedoor
|
||||
: simpleGaragedoor
|
||||
Binding { target: contentLoader.item; property: "device"; value: itemDelegate.device }
|
||||
}
|
||||
onClicked: {
|
||||
enterPage(index, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: impulseGaragedoor
|
||||
|
||||
RowLayout {
|
||||
id: contentItem
|
||||
property Device device: null
|
||||
|
||||
spacing: app.margins
|
||||
Item {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
ColorIcon {
|
||||
id: icon
|
||||
anchors.fill: parent
|
||||
name: root.iconBasename + "-100.svg"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: contentItem.device.name
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
ItemDelegate {
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
Layout.preferredWidth: height
|
||||
ColorIcon {
|
||||
anchors.centerIn: parent
|
||||
height: app.iconSize
|
||||
width: height
|
||||
name: "../images/closable-move.svg"
|
||||
}
|
||||
onClicked: {
|
||||
var actionTypeId = device.thingClass.actionTypes.findByName("triggerImpulse").id
|
||||
print("Triggering impulse", actionTypeId)
|
||||
engine.thingManager.executeAction(device.id, actionTypeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: simpleGaragedoor
|
||||
|
||||
RowLayout {
|
||||
id: contentItem
|
||||
spacing: app.margins
|
||||
property Device device: null
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
ColorIcon {
|
||||
id: icon
|
||||
anchors.fill: parent
|
||||
color: keyColor
|
||||
name: root.iconBasename + "-100.svg"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: contentItem.device.name
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: shutterControls.implicitWidth
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
ShutterControls {
|
||||
id: shutterControls
|
||||
height: parent.height
|
||||
device: contentItem.device
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: garagedoor
|
||||
|
||||
RowLayout {
|
||||
id: contentItem
|
||||
spacing: app.margins
|
||||
property Device device: null
|
||||
|
||||
property StateType stateStateType: device.deviceClass.stateTypes.findByName("state")
|
||||
property State stateState: stateStateType ? device.states.getState(stateStateType.id) : null
|
||||
Item {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
ColorIcon {
|
||||
id: icon
|
||||
anchors.fill: parent
|
||||
color: ["opening", "closing"].indexOf(contentItem.stateState.value) >= 0
|
||||
? app.accentColor
|
||||
: keyColor
|
||||
name: root.iconBasename + "-100.svg"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: contentItem.device.name
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: shutterControls.implicitWidth
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
ShutterControls {
|
||||
id: shutterControls
|
||||
height: parent.height
|
||||
device: contentItem.device
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: extendedStatefulGaragedoor
|
||||
|
||||
RowLayout {
|
||||
id: contentItem
|
||||
spacing: app.margins
|
||||
property Device device: null
|
||||
|
||||
property StateType stateStateType: device.deviceClass.stateTypes.findByName("state")
|
||||
property State stateState: stateStateType ? device.states.getState(stateStateType.id) : null
|
||||
|
||||
property StateType percentageStateType: device.deviceClass.stateTypes.findByName("percentage");
|
||||
property ActionType percentageActionType: device.deviceClass.actionTypes.findByName("percentage");
|
||||
property State percentageState: percentageStateType ? device.states.getState(percentageStateType.id) : null
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
ColorIcon {
|
||||
id: icon
|
||||
anchors.fill: parent
|
||||
color: ["opening", "closing"].indexOf(contentItem.stateState.value) >= 0
|
||||
? app.accentColor
|
||||
: keyColor
|
||||
name: contentItem.percentageStateType
|
||||
? root.iconBasename + "-" + app.pad(Math.round(contentItem.percentageState.value / 10) * 10, 3) + ".svg"
|
||||
: root.iconBasename + "-050.svg"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: contentItem.device.name
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: shutterControls.implicitWidth
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
ShutterControls {
|
||||
id: shutterControls
|
||||
height: parent.height
|
||||
device: contentItem.device
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,6 +39,8 @@ Page {
|
||||
property Device device: null
|
||||
readonly property DeviceClass deviceClass: device.deviceClass
|
||||
|
||||
readonly property Device thing: device
|
||||
|
||||
property bool showLogsButton: true
|
||||
property bool showDetailsButton: true
|
||||
property bool showBrowserButton: true
|
||||
|
||||
@ -40,10 +40,31 @@ DevicePageBase {
|
||||
id: root
|
||||
|
||||
readonly property bool landscape: width > height
|
||||
readonly property var openState: device.states.getState(deviceClass.stateTypes.findByName("state").id)
|
||||
readonly property var intermediatePositionState: device.states.getState(deviceClass.stateTypes.findByName("intermediatePosition").id)
|
||||
readonly property var lightStateType: deviceClass.stateTypes.findByName("power")
|
||||
readonly property var lightState: lightStateType ? device.states.getState(lightStateType.id) : null
|
||||
|
||||
readonly property bool isImpulseBased: thing.thingClass.interfaces.indexOf("impulsegaragedoor") >= 0
|
||||
readonly property bool isStateful: thing.thingClass.interfaces.indexOf("statefulgaragedoor") >= 0
|
||||
readonly property bool isExtended: thing.thingClass.interfaces.indexOf("extendedstatefulgaragedoor") >= 0
|
||||
|
||||
// Stateful garagedoor
|
||||
readonly property StateType stateStateType: thing.thingClass.stateTypes.findByName("state")
|
||||
readonly property State stateState: stateStateType ? thing.states.getState(stateStateType.id) : null
|
||||
|
||||
// Extended stateful garagedoor
|
||||
readonly property StateType percentageStateType: thing.thingClass.stateTypes.findByName("percentage")
|
||||
readonly property State percentageState: percentageStateType ? thing.states.getState(percentageStateType.id) : null
|
||||
|
||||
|
||||
// Backward compatiblity with old garagegate interface
|
||||
readonly property StateType intermediatePositionStateType: thing.thingClass.stateTypes.findByName("intermediatePosition")
|
||||
readonly property var intermediatePositionState: intermediatePositionStateType ? device.states.getState(intermediatePositionStateType.id) : null
|
||||
|
||||
// Some garages may also implement the light interface
|
||||
readonly property var lightStateType: thing.thingClass.stateTypes.findByName("power")
|
||||
readonly property var lightState: lightStateType ? thing.states.getState(lightStateType.id) : null
|
||||
|
||||
Component.onCompleted: {
|
||||
print("Creating garage page. Impulse based:", isImpulseBased, "stateful:", isStateful, "extended:", isExtended, "legacy:", intermediatePositionState !== null)
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
@ -56,8 +77,16 @@ DevicePageBase {
|
||||
: Math.min(Math.min(parent.width, 500), parent.height - shutterControlsContainer.minimumHeight)
|
||||
Layout.preferredHeight: width
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
property string currentImage: root.openState.value === "closed" ? "100" :
|
||||
root.openState.value === "open" && root.intermediatePositionState.value === false ? "000" : "050"
|
||||
property string currentImage: {
|
||||
if (root.isExtended) {
|
||||
return app.pad(Math.round(root.percentageState.value / 10), 2) + "0"
|
||||
}
|
||||
if (root.intermediatePositionStateType) {
|
||||
return root.stateState.value === "closed" ? "100"
|
||||
: root.intermediatePositionState.value === false ? "000" : "050"
|
||||
}
|
||||
return "100"
|
||||
}
|
||||
name: "../images/garage/garage-" + currentImage + ".svg"
|
||||
|
||||
Item {
|
||||
@ -66,8 +95,8 @@ DevicePageBase {
|
||||
width: app.iconSize * 2
|
||||
height: parent.height * .6
|
||||
clip: true
|
||||
visible: root.openState.value === "opening" || root.openState.value === "closing"
|
||||
property bool up: root.openState.value === "opening"
|
||||
visible: root.stateStateType && (root.stateState.value === "opening" || root.stateState.value === "closing")
|
||||
property bool up: root.stateState && root.stateState.value === "opening"
|
||||
|
||||
// NumberAnimation doesn't reload to/from while it's running. If we switch from closing to opening or vice versa
|
||||
// we need to somehow stop and start the animation
|
||||
@ -76,7 +105,7 @@ DevicePageBase {
|
||||
if (!animationHack) hackTimer.start();
|
||||
}
|
||||
Timer { id: hackTimer; interval: 1; onTriggered: arrows.animationHack = true }
|
||||
Connections { target: root.openState; onValueChanged: arrows.animationHack = false }
|
||||
Connections { target: root.stateState; onValueChanged: arrows.animationHack = false }
|
||||
|
||||
NumberAnimation {
|
||||
target: arrowColumn
|
||||
@ -86,7 +115,7 @@ DevicePageBase {
|
||||
from: arrows.up ? app.iconSize : -app.iconSize
|
||||
to: arrows.up ? -app.iconSize : app.iconSize
|
||||
loops: Animation.Infinite
|
||||
running: arrows.animationHack && (root.openState.value === "opening" || root.openState.value === "closing")
|
||||
running: arrows.animationHack && root.stateState && (root.stateState.value === "opening" || root.stateState.value === "closing")
|
||||
}
|
||||
|
||||
Column {
|
||||
@ -114,11 +143,29 @@ DevicePageBase {
|
||||
property int minimumWidth: app.iconSize * 2.5 * (root.lightState ? 4 : 3)
|
||||
property int minimumHeight: app.iconSize * 2.5
|
||||
|
||||
ItemDelegate {
|
||||
height: app.iconSize * 2
|
||||
width: height
|
||||
anchors.centerIn: parent
|
||||
visible: root.isImpulseBased
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
name: "../images/closable-move.svg"
|
||||
anchors.margins: app.margins
|
||||
}
|
||||
onClicked: {
|
||||
var actionTypeId = root.thing.thingClass.actionTypes.findByName("triggerImpulse").id
|
||||
print("Triggering impulse", actionTypeId)
|
||||
engine.thingManager.executeAction(root.thing.id, actionTypeId)
|
||||
}
|
||||
}
|
||||
|
||||
ShutterControls {
|
||||
id: shutterControls
|
||||
device: root.device
|
||||
anchors.centerIn: parent
|
||||
spacing: (parent.width - app.iconSize*2*children.length) / (children.length - 1)
|
||||
visible: !root.isImpulseBased
|
||||
|
||||
ItemDelegate {
|
||||
width: app.iconSize * 2
|
||||
@ -36,19 +36,19 @@ import Nymea 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property string title: qsTr("Garage gates")
|
||||
readonly property string title: qsTr("Garage doors")
|
||||
readonly property string icon: Qt.resolvedUrl("qrc:/ui/images/shutter/shutter-050.svg")
|
||||
|
||||
DevicesProxy {
|
||||
id: garagesFilterModel
|
||||
engine: _engine
|
||||
shownInterfaces: ["garagegate"]
|
||||
shownInterfaces: ["garagedoors"]
|
||||
}
|
||||
|
||||
EmptyViewPlaceholder {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - app.margins * 2
|
||||
text: qsTr("There are no garage gates set up yet.")
|
||||
text: qsTr("There are no garage doors set up yet.")
|
||||
imageSource: "qrc:/ui/images/shutter/shutter-050.svg"
|
||||
buttonText: qsTr("Set up now")
|
||||
visible: garagesFilterModel.count === 0
|
||||
|
||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
@ -70,8 +70,9 @@ MainPageTile {
|
||||
case "smartmeter":
|
||||
page ="SmartMeterDeviceListPage.qml";
|
||||
break;
|
||||
case "garagegate":
|
||||
page = "GarageDeviceListPage.qml";
|
||||
case "garagegate": // Deprecated, might not inherit garagedoor in old versions
|
||||
case "garagedoor":
|
||||
page = "GarageThingListPage.qml";
|
||||
break;
|
||||
case "awning":
|
||||
case "extendedAwning":
|
||||
|
||||
@ -77,7 +77,7 @@ SettingsPageBase {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Qt version:")
|
||||
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
|
||||
subText: engine.jsonRpcClient.serverQtVersion + (engine.jsonRpcClient.serverQtVersion !== engine.jsonRpcClient.serverQtBuildVersion ? + " (" + qsTr("Built with %1").arg(engine.jsonRpcClient.serverQtBuildVersion) + ")" : "")
|
||||
subText: engine.jsonRpcClient.serverQtVersion + (engine.jsonRpcClient.serverQtVersion !== engine.jsonRpcClient.serverQtBuildVersion ? " (" + qsTr("Built with %1").arg(engine.jsonRpcClient.serverQtBuildVersion) + ")" : "")
|
||||
progressive: false
|
||||
prominentSubText: false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user