From 5b0397ba2b199087fe9e060db6928c97722f27f2 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 5 Sep 2020 00:04:52 +0200 Subject: [PATCH] Make plugin issues more visible to the user --- libnymea-app/devicemanager.cpp | 2 +- libnymea-app/devicesproxy.cpp | 21 +++++++++++++++++ libnymea-app/devicesproxy.h | 7 ++++++ libnymea-app/jsonrpc/jsontypes.cpp | 10 ++++---- libnymea-app/thinggroup.cpp | 6 ++--- libnymea-app/thinggroup.h | 2 +- libnymea-app/types/device.cpp | 10 ++++---- libnymea-app/types/device.h | 20 +++++++++++----- nymea-app/ui/components/MainPageTile.qml | 18 ++++++++++++--- nymea-app/ui/delegates/InterfaceTile.qml | 8 +++++++ nymea-app/ui/delegates/ThingDelegate.qml | 29 ++++++++++++++++-------- nymea-app/ui/delegates/ThingTile.qml | 4 ++++ 12 files changed, 103 insertions(+), 34 deletions(-) diff --git a/libnymea-app/devicemanager.cpp b/libnymea-app/devicemanager.cpp index 7b46a240..7021b7ca 100644 --- a/libnymea-app/devicemanager.cpp +++ b/libnymea-app/devicemanager.cpp @@ -457,7 +457,7 @@ void DeviceManager::savePluginConfig(const QUuid &pluginId) ThingGroup *DeviceManager::createGroup(Interface *interface, DevicesProxy *things) { ThingGroup* group = new ThingGroup(this, interface->createDeviceClass(), things, this); - group->setSetupStatus(Device::DeviceSetupStatusComplete, QString()); + group->setSetupStatus(Device::ThingSetupStatusComplete, QString()); return group; } diff --git a/libnymea-app/devicesproxy.cpp b/libnymea-app/devicesproxy.cpp index bc77975a..e73d192a 100644 --- a/libnymea-app/devicesproxy.cpp +++ b/libnymea-app/devicesproxy.cpp @@ -293,6 +293,21 @@ void DevicesProxy::setFilterDisconnected(bool filterDisconnected) } } +bool DevicesProxy::filterSetupFailed() const +{ + return m_filterSetupFailed; +} + +void DevicesProxy::setFilterSetupFailed(bool filterSetupFailed) +{ + if (m_filterSetupFailed != filterSetupFailed) { + m_filterSetupFailed = filterSetupFailed; + emit filterSetupFailedChanged(); + invalidateFilter(); + emit countChanged(); + } +} + bool DevicesProxy::groupByInterface() const { return m_groupByInterface; @@ -426,6 +441,12 @@ bool DevicesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_pa } } + if (m_filterSetupFailed) { + if (device->setupStatus() != Device::DeviceSetupStatusFailed) { + return false; + } + } + if (!m_nameFilter.isEmpty()) { if (!device->name().toLower().contains(m_nameFilter.toLower().trimmed())) { return false; diff --git a/libnymea-app/devicesproxy.h b/libnymea-app/devicesproxy.h index c5f11c65..a3ed9ef2 100644 --- a/libnymea-app/devicesproxy.h +++ b/libnymea-app/devicesproxy.h @@ -65,6 +65,8 @@ class DevicesProxy : public QSortFilterProxyModel // Setting this to true will imply filtering for "connectable" interface Q_PROPERTY(bool filterDisconnected READ filterDisconnected WRITE setFilterDisconnected NOTIFY filterDisconnectedChanged) + Q_PROPERTY(bool filterSetupFailed READ filterSetupFailed WRITE setFilterSetupFailed NOTIFY filterSetupFailedChanged) + Q_PROPERTY(bool groupByInterface READ groupByInterface WRITE setGroupByInterface NOTIFY groupByInterfaceChanged) public: @@ -115,6 +117,9 @@ public: bool filterDisconnected() const; void setFilterDisconnected(bool filterDisconnected); + bool filterSetupFailed() const; + void setFilterSetupFailed(bool filterSetupFailed); + bool groupByInterface() const; void setGroupByInterface(bool groupByInterface); @@ -137,6 +142,7 @@ signals: void showAnalogOutputsChanged(); void filterBatteryCriticalChanged(); void filterDisconnectedChanged(); + void filterSetupFailedChanged(); void groupByInterfaceChanged(); void countChanged(); @@ -160,6 +166,7 @@ private: bool m_filterBatteryCritical = false; bool m_filterDisconnected = false; + bool m_filterSetupFailed = false; bool m_groupByInterface = false; diff --git a/libnymea-app/jsonrpc/jsontypes.cpp b/libnymea-app/jsonrpc/jsontypes.cpp index a890a807..c825b2cc 100644 --- a/libnymea-app/jsonrpc/jsontypes.cpp +++ b/libnymea-app/jsonrpc/jsontypes.cpp @@ -250,16 +250,16 @@ Device* JsonTypes::unpackDevice(DeviceManager *deviceManager, const QVariantMap QString setupStatus = deviceMap.value("setupStatus").toString(); QString setupDisplayMessage = deviceMap.value("setupDisplayMessage").toString(); if (setupStatus == "DeviceSetupStatusNone" || setupStatus == "ThingSetupStatusNone") { - device->setSetupStatus(Device::DeviceSetupStatusNone, setupDisplayMessage); + device->setSetupStatus(Device::ThingSetupStatusNone, setupDisplayMessage); } else if (setupStatus == "DeviceSetupStatusInProgress" || setupStatus == "ThingSetupStatusInProgress") { - device->setSetupStatus(Device::DeviceSetupStatusInProgress, setupDisplayMessage); + device->setSetupStatus(Device::ThingSetupStatusInProgress, setupDisplayMessage); } else if (setupStatus == "DeviceSetupStatusComplete" || setupStatus == "ThingSetupStatusComplete") { - device->setSetupStatus(Device::DeviceSetupStatusComplete, setupDisplayMessage); + device->setSetupStatus(Device::ThingSetupStatusComplete, setupDisplayMessage); } else if (setupStatus == "DeviceSetupStatusFailed" || setupStatus == "ThingSetupStatusFailed") { - device->setSetupStatus(Device::DeviceSetupStatusFailed, setupDisplayMessage); + device->setSetupStatus(Device::ThingSetupStatusFailed, setupDisplayMessage); } } else { - device->setSetupStatus(deviceMap.value("setupComplete").toBool() ? Device::DeviceSetupStatusComplete : Device::DeviceSetupStatusNone, QString()); + device->setSetupStatus(deviceMap.value("setupComplete").toBool() ? Device::ThingSetupStatusComplete : Device::ThingSetupStatusNone, QString()); } Params *params = device->params(); diff --git a/libnymea-app/thinggroup.cpp b/libnymea-app/thinggroup.cpp index 492a4837..b3d78801 100644 --- a/libnymea-app/thinggroup.cpp +++ b/libnymea-app/thinggroup.cpp @@ -36,7 +36,7 @@ ThingGroup::ThingGroup(DeviceManager *deviceManager, DeviceClass *deviceClass, DevicesProxy *devices, QObject *parent): Device(deviceManager, deviceClass, QUuid::createUuid(), parent), - m_deviceManager(deviceManager), + m_thingManager(deviceManager), m_devices(devices) { deviceClass->setParent(this); @@ -56,7 +56,7 @@ ThingGroup::ThingGroup(DeviceManager *deviceManager, DeviceClass *deviceClass, D syncStates(); }); - connect(m_deviceManager, &DeviceManager::executeActionReply, this, [this](const QVariantMap ¶ms){ + connect(m_thingManager, &DeviceManager::executeActionReply, this, [this](const QVariantMap ¶ms){ int returningId = params.value("id").toInt(); foreach (int id, m_pendingActions.keys()) { if (m_pendingActions.value(id).contains(returningId)) { @@ -101,7 +101,7 @@ int ThingGroup::executeAction(const QString &actionName, const QVariantList &par qDebug() << "Initial params" << params; qDebug() << "Executing" << device->id() << actionType->name() << finalParams; - int id = m_deviceManager->executeAction(device->id(), actionType->id(), finalParams); + int id = m_thingManager->executeAction(device->id(), actionType->id(), finalParams); pendingIds.append(id); } m_pendingActions.insert(++m_idCounter, pendingIds); diff --git a/libnymea-app/thinggroup.h b/libnymea-app/thinggroup.h index f076d513..59473b59 100644 --- a/libnymea-app/thinggroup.h +++ b/libnymea-app/thinggroup.h @@ -53,7 +53,7 @@ signals: void actionExecutionFinished(int id, const QString &status); private: - DeviceManager* m_deviceManager = nullptr; + DeviceManager* m_thingManager = nullptr; DevicesProxy* m_devices = nullptr; int m_idCounter = 0; diff --git a/libnymea-app/types/device.cpp b/libnymea-app/types/device.cpp index 989f547f..f33b4ca5 100644 --- a/libnymea-app/types/device.cpp +++ b/libnymea-app/types/device.cpp @@ -34,9 +34,9 @@ #include -Device::Device(DeviceManager *deviceManager, DeviceClass *thingClass, const QUuid &parentId, QObject *parent) : +Device::Device(DeviceManager *thingManager, DeviceClass *thingClass, const QUuid &parentId, QObject *parent) : QObject(parent), - m_deviceManager(deviceManager), + m_thingManager(thingManager), m_parentId(parentId), m_thingClass(thingClass) { @@ -83,7 +83,7 @@ bool Device::isChild() const return !m_parentId.isNull(); } -Device::DeviceSetupStatus Device::setupStatus() const +Device::ThingSetupStatus Device::setupStatus() const { return m_setupStatus; } @@ -93,7 +93,7 @@ QString Device::setupDisplayMessage() const return m_setupDisplayMessage; } -void Device::setSetupStatus(Device::DeviceSetupStatus setupStatus, const QString &displayMessage) +void Device::setSetupStatus(Device::ThingSetupStatus setupStatus, const QString &displayMessage) { if (m_setupStatus != setupStatus || m_setupDisplayMessage != displayMessage) { m_setupStatus = setupStatus; @@ -215,7 +215,7 @@ int Device::executeAction(const QString &actionName, const QVariantList ¶ms) } finalParams.append(param); } - return m_deviceManager->executeAction(m_id, actionType->id(), finalParams); + return m_thingManager->executeAction(m_id, actionType->id(), finalParams); } QDebug operator<<(QDebug &dbg, Device *thing) diff --git a/libnymea-app/types/device.h b/libnymea-app/types/device.h index 1f60b3fb..d0189832 100644 --- a/libnymea-app/types/device.h +++ b/libnymea-app/types/device.h @@ -50,7 +50,7 @@ class Device : public QObject Q_PROPERTY(QUuid parentDeviceId READ parentDeviceId CONSTANT) Q_PROPERTY(bool isChild READ isChild CONSTANT) Q_PROPERTY(QString name READ name NOTIFY nameChanged) - Q_PROPERTY(DeviceSetupStatus setupStatus READ setupStatus NOTIFY setupStatusChanged) + Q_PROPERTY(ThingSetupStatus setupStatus READ setupStatus NOTIFY setupStatusChanged) Q_PROPERTY(QString setupDisplayMessage READ setupDisplayMessage NOTIFY setupStatusChanged) Q_PROPERTY(Params *params READ params NOTIFY paramsChanged) Q_PROPERTY(Params *settings READ settings NOTIFY settingsChanged) @@ -67,7 +67,15 @@ public: }; Q_ENUM(DeviceSetupStatus) - explicit Device(DeviceManager *deviceManager, DeviceClass *thingClass, const QUuid &parentId = QUuid(), QObject *parent = nullptr); + enum ThingSetupStatus { + ThingSetupStatusNone, + ThingSetupStatusInProgress, + ThingSetupStatusComplete, + ThingSetupStatusFailed + }; + Q_ENUM(ThingSetupStatus) + + explicit Device(DeviceManager *thingManager, DeviceClass *thingClass, const QUuid &parentId = QUuid(), QObject *parent = nullptr); QUuid id() const; void setId(const QUuid &id); @@ -80,9 +88,9 @@ public: QUuid parentDeviceId() const; bool isChild() const; - DeviceSetupStatus setupStatus() const; + Device::ThingSetupStatus setupStatus() const; QString setupDisplayMessage() const; - void setSetupStatus(DeviceSetupStatus setupStatus, const QString &displayMessage); + void setSetupStatus(Device::ThingSetupStatus setupStatus, const QString &displayMessage); Params *params() const; void setParams(Params *params); @@ -115,11 +123,11 @@ signals: private: protected: - DeviceManager *m_deviceManager = nullptr; + DeviceManager *m_thingManager = nullptr; QString m_name; QUuid m_id; QUuid m_parentId; - DeviceSetupStatus m_setupStatus = DeviceSetupStatusNone; + ThingSetupStatus m_setupStatus = ThingSetupStatusNone; QString m_setupDisplayMessage; Params *m_params = nullptr; Params *m_settings = nullptr; diff --git a/nymea-app/ui/components/MainPageTile.qml b/nymea-app/ui/components/MainPageTile.qml index 5a93f687..0f1f708f 100644 --- a/nymea-app/ui/components/MainPageTile.qml +++ b/nymea-app/ui/components/MainPageTile.qml @@ -32,6 +32,7 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.2 import QtQuick.Layouts 1.3 +import Nymea 1.0 Item { id: root @@ -42,6 +43,9 @@ Item { property alias backgroundImage: background.source property string text property bool disconnected: false + property bool isWireless: false + property int signalStrength: -1 + property int setupStatus: Device.DeviceSetupStatusNone property bool batteryCritical: false property alias contentItem: innerContent.children @@ -143,12 +147,20 @@ Item { Row { id: quickAlertPane anchors { top: parent.top; right: parent.right; margins: app.margins } + spacing: app.margins / 2 ColorIcon { height: app.iconSize / 2 width: height - name: "../images/dialog-warning-symbolic.svg" - color: "red" - visible: root.disconnected + name: root.isWireless ? "../images/network-wifi-offline.svg" : "../images/network-wired-offline.svg" + color: root.disconnected ? "red" : "orange" + visible: root.setupStatus == Device.DeviceSetupStatusComplete && (root.disconnected || (root.signalStrength >= 0 && root.signalStrength < 10)) + } + ColorIcon { + height: app.iconSize / 2 + width: height + name: root.setupStatus === Device.DeviceSetupStatusFailed ? "../images/dialog-warning-symbolic.svg" : "../images/settings.svg" + color: root.setupStatus === Device.DeviceSetupStatusFailed ? "red" : keyColor + visible: root.setupStatus === Device.DeviceSetupStatusFailed || root.setupStatus === Device.DeviceSetupStatusInProgress } ColorIcon { height: app.iconSize / 2 diff --git a/nymea-app/ui/delegates/InterfaceTile.qml b/nymea-app/ui/delegates/InterfaceTile.qml index 9d936ca5..888c8b94 100644 --- a/nymea-app/ui/delegates/InterfaceTile.qml +++ b/nymea-app/ui/delegates/InterfaceTile.qml @@ -41,7 +41,9 @@ MainPageTile { iconName: iface ? interfaceToIcon(iface.name) : interfaceToIcon("uncategorized") iconColor: app.accentColor disconnected: devicesSubProxyConnectables.count > 0 + isWireless: devicesSubProxyConnectables.count > 0 && devicesSubProxyConnectables.get(0).thingClass.interfaces.indexOf("wirelessconnectable") >= 0 batteryCritical: devicesSubProxyBattery.count > 0 + setupStatus: thingsSubProxySetupFailure.count > 0 ? Device.DeviceSetupStatusFailed : Device.DeviceSetupStatusComplete property Interface iface: null property alias filterTagId: devicesProxy.filterTagId @@ -118,6 +120,12 @@ MainPageTile { parentProxy: devicesProxy filterBatteryCritical: true } + DevicesProxy { + id: thingsSubProxySetupFailure + engine: _engine + parentProxy: devicesProxy + filterSetupFailed: true + } property int currentDeviceIndex: 0 readonly property Device currentDevice: devicesProxy.get(currentDeviceIndex) diff --git a/nymea-app/ui/delegates/ThingDelegate.qml b/nymea-app/ui/delegates/ThingDelegate.qml index 60c67374..812b40bd 100644 --- a/nymea-app/ui/delegates/ThingDelegate.qml +++ b/nymea-app/ui/delegates/ThingDelegate.qml @@ -37,22 +37,31 @@ import Nymea 1.0 NymeaListItemDelegate { id: root width: parent.width - iconName: device && device.deviceClass ? app.interfacesToIcon(device.deviceClass.interfaces) : "" - text: device ? device.name : "" + iconName: thing && thing.thingClass ? app.interfacesToIcon(thing.thingClass.interfaces) : "" + text: thing ? thing.name : "" progressive: true secondaryIconName: batteryCritical ? "../images/battery/battery-010.svg" : "" - tertiaryIconName: disconnected ? "../images/dialog-warning-symbolic.svg" : "" - tertiaryIconColor: "red" + tertiaryIconName: thing.setupStatus == Thing.ThingSetupStatusFailed + ? "../images/dialog-warning-symbolic.svg" + : thing.setupStatus == Thing.ThingSetupStatusInProgress + ? "../images/settings.svg" + : disconnected + ? "../images/dialog-warning-symbolic.svg" + : "" + tertiaryIconColor: thing.setupStatus == Thing.ThingSetupStatusInProgress ? iconKeyColor : "red" property Device device: null + property Thing thing: device - readonly property bool hasBatteryInterface: device && device.deviceClass.interfaces.indexOf("battery") > 0 - readonly property StateType batteryCriticalStateType: hasBatteryInterface ? device.deviceClass.stateTypes.findByName("batteryCritical") : null - readonly property State batteryCriticalState: batteryCriticalStateType ? device.states.getState(batteryCriticalStateType.id) : null + readonly property bool hasBatteryInterface: thing && thing.thingClass.interfaces.indexOf("battery") > 0 + readonly property StateType batteryCriticalStateType: hasBatteryInterface ? thing.thingClass.stateTypes.findByName("batteryCritical") : null + readonly property State batteryCriticalState: batteryCriticalStateType ? thing.states.getState(batteryCriticalStateType.id) : null readonly property bool batteryCritical: batteryCriticalState && batteryCriticalState.value === true - readonly property bool hasConnectableInterface: device && device.deviceClass.interfaces.indexOf("connectable") > 0 - readonly property StateType connectedStateType: hasConnectableInterface ? device.deviceClass.stateTypes.findByName("connected") : null - readonly property State connectedState: connectedStateType ? device.states.getState(connectedStateType.id) : null + readonly property bool hasConnectableInterface: thing && thing.thingClass.interfaces.indexOf("connectable") > 0 + readonly property StateType connectedStateType: hasConnectableInterface ? thing.thingClass.stateTypes.findByName("connected") : null + readonly property State connectedState: connectedStateType ? thing.states.getState(connectedStateType.id) : null readonly property bool disconnected: connectedState && connectedState.value === false ? true : false + + } diff --git a/nymea-app/ui/delegates/ThingTile.qml b/nymea-app/ui/delegates/ThingTile.qml index 6f61e988..bd0e7c89 100644 --- a/nymea-app/ui/delegates/ThingTile.qml +++ b/nymea-app/ui/delegates/ThingTile.qml @@ -40,14 +40,18 @@ MainPageTile { text: device.name.toUpperCase() iconName: app.interfacesToIcon(deviceClass.interfaces) iconColor: app.accentColor + isWireless: deviceClass.interfaces.indexOf("wirelessconnectable") >= 0 batteryCritical: batteryCriticalState && batteryCriticalState.value === true disconnected: connectedState && connectedState.value === false + signalStrength: signalStrengthState ? signalStrengthState.value : -1 + setupStatus: device.setupStatus backgroundImage: artworkState && artworkState.value.length > 0 ? artworkState.value : "" property Device device: null readonly property DeviceClass deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null readonly property State connectedState: deviceClass.interfaces.indexOf("connectable") >= 0 ? device.states.getState(deviceClass.stateTypes.findByName("connected").id) : null + readonly property State signalStrengthState: device.stateByName("signalStrength") readonly property State batteryCriticalState: deviceClass.interfaces.indexOf("battery") >= 0 ? device.states.getState(deviceClass.stateTypes.findByName("batteryCritical").id) : null readonly property State artworkState: deviceClass.interfaces.indexOf("mediametadataprovider") >= 0 ? device.states.getState(deviceClass.stateTypes.findByName("artwork").id) : null