Make plugin issues more visible to the user

This commit is contained in:
Michael Zanetti 2020-09-05 00:04:52 +02:00
parent ca682fc61f
commit 5b0397ba2b
12 changed files with 103 additions and 34 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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 &params){
connect(m_thingManager, &DeviceManager::executeActionReply, this, [this](const QVariantMap &params){
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);

View File

@ -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;

View File

@ -34,9 +34,9 @@
#include <QDebug>
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 &params)
}
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)

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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