From 601171daf8c81b700c66bf23edbf51acd46f1e35 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 22 Jan 2019 23:39:23 +0100 Subject: [PATCH] also allow reconfiguring of devices that require pairing --- libnymea-app-core/devicediscovery.cpp | 101 +++++++++++++++++- libnymea-app-core/devicediscovery.h | 49 ++++++++- libnymea-app-core/libnymea-app-core.h | 1 + libnymea-app-core/vendorsproxy.cpp | 8 +- libnymea-app-core/vendorsproxy.h | 4 + nymea-app/ui/MainPage.qml | 6 +- .../ui/thingconfiguration/NewThingPage.qml | 9 +- .../ui/thingconfiguration/SetupWizard.qml | 31 ++++-- 8 files changed, 194 insertions(+), 15 deletions(-) diff --git a/libnymea-app-core/devicediscovery.cpp b/libnymea-app-core/devicediscovery.cpp index ec3a2e6e..e937f4b1 100644 --- a/libnymea-app-core/devicediscovery.cpp +++ b/libnymea-app-core/devicediscovery.cpp @@ -22,6 +22,8 @@ QVariant DeviceDiscovery::data(const QModelIndex &index, int role) const return m_foundDevices.at(index.row())->name(); case RoleDescription: return m_foundDevices.at(index.row())->description(); + case RoleDeviceId: + return m_foundDevices.at(index.row())->deviceId(); } return QVariant(); @@ -31,6 +33,7 @@ QHash DeviceDiscovery::roleNames() const { QHash roles; roles.insert(RoleId, "id"); + roles.insert(RoleDeviceId, "deviceId"); roles.insert(RoleName, "name"); roles.insert(RoleDescription, "description"); return roles; @@ -104,6 +107,7 @@ void DeviceDiscovery::discoverDevicesResponse(const QVariantMap ¶ms) if (!contains(descriptorVariant.toMap().value("id").toUuid())) { beginInsertRows(QModelIndex(), m_foundDevices.count(), m_foundDevices.count()); DeviceDescriptor *descriptor = new DeviceDescriptor(descriptorVariant.toMap().value("id").toUuid(), + descriptorVariant.toMap().value("deviceId").toString(), descriptorVariant.toMap().value("title").toString(), descriptorVariant.toMap().value("description").toString()); foreach (const QVariant ¶mVariant, descriptorVariant.toMap().value("deviceParams").toList()) { @@ -128,9 +132,10 @@ bool DeviceDiscovery::contains(const QUuid &deviceDescriptorId) const return false; } -DeviceDescriptor::DeviceDescriptor(const QUuid &id, const QString &name, const QString &description, QObject *parent): +DeviceDescriptor::DeviceDescriptor(const QUuid &id, const QUuid &deviceId, const QString &name, const QString &description, QObject *parent): QObject(parent), m_id(id), + m_deviceId(deviceId), m_name(name), m_description(description), m_params(new Params(this)) @@ -143,6 +148,11 @@ QUuid DeviceDescriptor::id() const return m_id; } +QUuid DeviceDescriptor::deviceId() const +{ + return m_deviceId; +} + QString DeviceDescriptor::name() const { return m_name; @@ -157,3 +167,92 @@ Params* DeviceDescriptor::params() const { return m_params; } + +DeviceDiscoveryProxy::DeviceDiscoveryProxy(QObject *parent): + QSortFilterProxyModel (parent) +{ + +} + +DeviceDiscovery *DeviceDiscoveryProxy::deviceDiscovery() const +{ + return m_deviceDiscovery; +} + +void DeviceDiscoveryProxy::setDeviceDiscovery(DeviceDiscovery *deviceDiscovery) +{ + if (m_deviceDiscovery != deviceDiscovery) { + m_deviceDiscovery = deviceDiscovery; + setSourceModel(deviceDiscovery); + emit deviceDiscoveryChanged(); + emit countChanged(); + connect(m_deviceDiscovery, &DeviceDiscovery::countChanged, this, &DeviceDiscoveryProxy::countChanged); + invalidateFilter(); + } +} + +bool DeviceDiscoveryProxy::showAlreadyAdded() const +{ + return m_showAlreadyAdded; +} + +void DeviceDiscoveryProxy::setShowAlreadyAdded(bool showAlreadyAdded) +{ + if (m_showAlreadyAdded != showAlreadyAdded) { + m_showAlreadyAdded = showAlreadyAdded; + emit showAlreadyAddedChanged(); + invalidateFilter(); + emit countChanged(); + } +} + +bool DeviceDiscoveryProxy::showNew() const +{ + return m_showNew; +} + +void DeviceDiscoveryProxy::setShowNew(bool showNew) +{ + if (m_showNew != showNew) { + m_showNew = showNew; + emit showNewChanged(); + invalidateFilter(); + emit countChanged(); + } +} + +QUuid DeviceDiscoveryProxy::filterDeviceId() const +{ + return m_filterDeviceId; +} + +void DeviceDiscoveryProxy::setFilterDeviceId(const QUuid &filterDeviceId) +{ + if (m_filterDeviceId != filterDeviceId) { + m_filterDeviceId = filterDeviceId; + emit filterDeviceIdChanged(); + invalidateFilter(); + emit countChanged(); + } +} + +DeviceDescriptor *DeviceDiscoveryProxy::get(int index) const +{ + return m_deviceDiscovery->get(mapToSource(this->index(index, 0)).row()); +} + +bool DeviceDiscoveryProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + Q_UNUSED(sourceParent) + DeviceDescriptor* dev = m_deviceDiscovery->get(sourceRow); + if (!m_showAlreadyAdded && !dev->deviceId().isNull()) { + return false; + } + if (!m_showNew && dev->deviceId().isNull()) { + return false; + } + if (!m_filterDeviceId.isNull() && dev->deviceId() != m_filterDeviceId) { + return false; + } + return true; +} diff --git a/libnymea-app-core/devicediscovery.h b/libnymea-app-core/devicediscovery.h index 1e486b65..cd99d228 100644 --- a/libnymea-app-core/devicediscovery.h +++ b/libnymea-app-core/devicediscovery.h @@ -9,19 +9,22 @@ class DeviceDescriptor: public QObject { Q_OBJECT Q_PROPERTY(QUuid id READ id CONSTANT) + Q_PROPERTY(QUuid deviceId READ deviceId CONSTANT) Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString description READ description CONSTANT) Q_PROPERTY(Params* params READ params CONSTANT) public: - DeviceDescriptor(const QUuid &id, const QString &name, const QString &description, QObject *parent = nullptr); + DeviceDescriptor(const QUuid &id, const QUuid &deviceId, const QString &name, const QString &description, QObject *parent = nullptr); QUuid id() const; + QUuid deviceId() const; QString name() const; QString description() const; Params* params() const; private: QUuid m_id; + QUuid m_deviceId; QString m_name; QString m_description; Params *m_params = nullptr; @@ -36,6 +39,7 @@ class DeviceDiscovery : public QAbstractListModel public: enum Roles { RoleId, + RoleDeviceId, RoleName, RoleDescription }; @@ -72,4 +76,47 @@ private: QList m_foundDevices; }; +class DeviceDiscoveryProxy: public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + Q_PROPERTY(DeviceDiscovery* deviceDiscovery READ deviceDiscovery WRITE setDeviceDiscovery NOTIFY deviceDiscoveryChanged) + Q_PROPERTY(bool showAlreadyAdded READ showAlreadyAdded WRITE setShowAlreadyAdded NOTIFY showAlreadyAddedChanged) + Q_PROPERTY(bool showNew READ showNew WRITE setShowNew NOTIFY showNewChanged) + Q_PROPERTY(QUuid filterDeviceId READ filterDeviceId WRITE setFilterDeviceId NOTIFY filterDeviceIdChanged) + +public: + DeviceDiscoveryProxy(QObject *parent = nullptr); + + DeviceDiscovery* deviceDiscovery() const; + void setDeviceDiscovery(DeviceDiscovery* deviceDiscovery); + + bool showAlreadyAdded() const; + void setShowAlreadyAdded(bool showAlreadyAdded); + + bool showNew() const; + void setShowNew(bool showNew); + + QUuid filterDeviceId() const; + void setFilterDeviceId(const QUuid &filterDeviceId); + + Q_INVOKABLE DeviceDescriptor* get(int index) const; + +signals: + void countChanged(); + void deviceDiscoveryChanged(); + void showAlreadyAddedChanged(); + void showNewChanged(); + void filterDeviceIdChanged(); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + +private: + DeviceDiscovery* m_deviceDiscovery = nullptr; + bool m_showAlreadyAdded = false; + bool m_showNew = true; + QUuid m_filterDeviceId; +}; + #endif // DEVICEDISCOVERY_H diff --git a/libnymea-app-core/libnymea-app-core.h b/libnymea-app-core/libnymea-app-core.h index c710add8..d4402af8 100644 --- a/libnymea-app-core/libnymea-app-core.h +++ b/libnymea-app-core/libnymea-app-core.h @@ -114,6 +114,7 @@ void registerQmlTypes() { qmlRegisterUncreatableType(uri, 1, 0, "DeviceClasses", "Can't create this in QML. Get it from the DeviceManager."); qmlRegisterType(uri, 1, 0, "DeviceClassesProxy"); qmlRegisterType(uri, 1, 0, "DeviceDiscovery"); + qmlRegisterType(uri, 1, 0, "DeviceDiscoveryProxy"); qmlRegisterUncreatableType(uri, 1, 0, "DeviceDescriptor", "Get it from DeviceDiscovery"); qmlRegisterType(uri, 1, 0, "DeviceModel"); diff --git a/libnymea-app-core/vendorsproxy.cpp b/libnymea-app-core/vendorsproxy.cpp index a4ce4568..377de4d2 100644 --- a/libnymea-app-core/vendorsproxy.cpp +++ b/libnymea-app-core/vendorsproxy.cpp @@ -26,7 +26,7 @@ VendorsProxy::VendorsProxy(QObject *parent) : QSortFilterProxyModel(parent) { - + setSortRole(Vendors::RoleDisplayName); } Vendors *VendorsProxy::vendors() @@ -40,10 +40,16 @@ void VendorsProxy::setVendors(Vendors *vendors) m_vendors = vendors; setSourceModel(vendors); emit vendorsChanged(); + connect(m_vendors, &Vendors::countChanged, this, &VendorsProxy::countChanged); sort(0); } } +Vendor *VendorsProxy::get(int index) const +{ + return m_vendors->get(mapToSource(this->index(index, 0)).row()); +} + bool VendorsProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { QVariant leftName = sourceModel()->data(left); diff --git a/libnymea-app-core/vendorsproxy.h b/libnymea-app-core/vendorsproxy.h index 2ddd2bdd..021713c1 100644 --- a/libnymea-app-core/vendorsproxy.h +++ b/libnymea-app-core/vendorsproxy.h @@ -32,6 +32,7 @@ class VendorsProxy : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(Vendors *vendors READ vendors WRITE setVendors NOTIFY vendorsChanged) + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) public: explicit VendorsProxy(QObject *parent = nullptr); @@ -39,8 +40,11 @@ public: Vendors *vendors(); void setVendors(Vendors *vendors); + Q_INVOKABLE Vendor* get(int index) const; + signals: void vendorsChanged(); + void countChanged(); private: Vendors *m_vendors; diff --git a/nymea-app/ui/MainPage.qml b/nymea-app/ui/MainPage.qml index 153b71b5..5a9b20b6 100644 --- a/nymea-app/ui/MainPage.qml +++ b/nymea-app/ui/MainPage.qml @@ -97,7 +97,7 @@ Page { imageSource: "images/starred.svg" buttonVisible: engine.deviceManager.devices.count === 0 buttonText: qsTr("Add a thing") - onButtonClicked: pageStack.push(Qt.resolvedUrl("NewDeviceWizard.qml")) + onButtonClicked: pageStack.push(Qt.resolvedUrl("thingconfiguration/NewThingPage.qml")) } } @@ -124,7 +124,7 @@ Page { text: qsTr("There are no things set up yet.") + "\n" + qsTr("In order for your %1 box to be useful, go ahead and add some things.").arg(app.systemName) imageSource: "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle) buttonText: qsTr("Add a thing") - onButtonClicked: pageStack.push(Qt.resolvedUrl("NewDeviceWizard.qml")) + onButtonClicked: pageStack.push(Qt.resolvedUrl("thingconfiguration/NewThingPage.qml")) } } @@ -146,7 +146,7 @@ Page { buttonText: engine.deviceManager.devices.count === 0 ? qsTr("Add a thing") : qsTr("Add a scene") onButtonClicked: { if (engine.deviceManager.devices.count === 0) { - pageStack.push(Qt.resolvedUrl("NewDeviceWizard.qml")) + pageStack.push(Qt.resolvedUrl("thingconfiguration/NewThingPage.qml")) } else { var page = pageStack.push(Qt.resolvedUrl("MagicPage.qml")) page.addRule() diff --git a/nymea-app/ui/thingconfiguration/NewThingPage.qml b/nymea-app/ui/thingconfiguration/NewThingPage.qml index 462f9162..dddeef8b 100644 --- a/nymea-app/ui/thingconfiguration/NewThingPage.qml +++ b/nymea-app/ui/thingconfiguration/NewThingPage.qml @@ -42,13 +42,18 @@ Page { id: vendorFilterComboBox Layout.fillWidth: true textRole: "displayName" + VendorsProxy { + id: vendorsProxy + vendors: engine.deviceManager.vendors + } model: ListModel { id: vendorsFilterModel ListElement { displayName: qsTr("All"); vendorId: "" } + Component.onCompleted: { - for (var i = 0; i < engine.deviceManager.vendors.count; i++) { - var vendor = engine.deviceManager.vendors.get(i); + for (var i = 0; i < vendorsProxy.count; i++) { + var vendor = vendorsProxy.get(i); append({displayName: vendor.displayName, vendorId: vendor.id}) } } diff --git a/nymea-app/ui/thingconfiguration/SetupWizard.qml b/nymea-app/ui/thingconfiguration/SetupWizard.qml index bbc9932a..0ec7a0ec 100644 --- a/nymea-app/ui/thingconfiguration/SetupWizard.qml +++ b/nymea-app/ui/thingconfiguration/SetupWizard.qml @@ -28,7 +28,7 @@ Page { HeaderButton { imageSource: "../images/close.svg" - onClicked: pageStack.pop(); + onClicked: root.done(); } } @@ -72,7 +72,6 @@ Page { break; default: print("Setup method", params["setupMethod"], "not handled"); - } } onConfirmPairingReply: { @@ -176,7 +175,13 @@ Page { ListView { Layout.fillWidth: true Layout.fillHeight: true - model: discovery + model: DeviceDiscoveryProxy { + id: discoveryProxy + deviceDiscovery: discovery + showAlreadyAdded: root.device !== null + showNew: root.device === null + filterDeviceId: root.device !== null ? root.device.id : null + } delegate: MeaListItemDelegate { width: parent.width height: app.delegateHeight @@ -184,14 +189,26 @@ Page { subText: model.description iconName: app.interfacesToIcon(discoveryView.deviceClass.interfaces) onClicked: { - d.deviceDescriptor = discovery.get(index); + d.deviceDescriptor = discoveryProxy.get(index); d.deviceName = model.name; // Overriding params for reconfiguring discovered devices not supported by core yet // So if we are reconfiguring and discovering, go straight to end + if (root.device && d.deviceDescriptor) { busyOverlay.shown = true; - engine.deviceManager.reconfigureDiscoveredDevice(root.device.id, d.deviceDescriptor.id); + + switch (root.deviceClass.setupMethod) { + case 0: + engine.deviceManager.reconfigureDiscoveredDevice(root.device.id, d.deviceDescriptor.id); + break; + case 1: + case 2: + case 3: + engine.deviceManager.pairDevice(root.deviceClass.id, d.deviceDescriptor.id, root.device.name); + break; + } + return; } @@ -205,7 +222,7 @@ Page { Layout.leftMargin: app.margins; Layout.rightMargin: app.margins text: qsTr("Search again") onClicked: discovery.discoverDevices(root.deviceClass.id, d.discoveryParams) - visible: !discovery.busy && discovery.count > 0 + visible: !discovery.busy && discoveryProxy.count > 0 } Button { @@ -239,7 +256,7 @@ Page { ColumnLayout { anchors.centerIn: parent width: parent.width - app.margins * 2 - visible: !discovery.busy && discovery.count == 0 + visible: !discovery.busy && discoveryProxy.count === 0 spacing: app.margins * 2 Label { text: qsTr("Too bad...")