diff --git a/libnymea-common/types/device.cpp b/libnymea-common/types/device.cpp index bd64b33e..00eb30ed 100644 --- a/libnymea-common/types/device.cpp +++ b/libnymea-common/types/device.cpp @@ -25,8 +25,7 @@ #include Device::Device(QObject *parent) : - QObject(parent), - m_statesProxy(new StatesProxy(this)) + QObject(parent) { } @@ -35,14 +34,9 @@ QString Device::name() const return m_name; } -QString Device::deviceName() const +void Device::setName(const QString &name) { - return m_name; -} - -void Device::setDeviceName(const QString &deviceName) -{ - m_name = deviceName; + m_name = name; emit nameChanged(); } @@ -97,12 +91,6 @@ void Device::setStates(States *states) { m_states = states; emit statesChanged(); - m_statesProxy->setStates(states); -} - -StatesProxy *Device::statesProxy() const -{ - return m_statesProxy; } bool Device::hasState(const QUuid &stateTypeId) diff --git a/libnymea-common/types/device.h b/libnymea-common/types/device.h index cac5fadd..a1e96e06 100644 --- a/libnymea-common/types/device.h +++ b/libnymea-common/types/device.h @@ -36,19 +36,15 @@ class Device : public QObject Q_PROPERTY(QUuid id READ id CONSTANT) Q_PROPERTY(QUuid deviceClassId READ deviceClassId CONSTANT) Q_PROPERTY(QString name READ name NOTIFY nameChanged) - Q_PROPERTY(QString deviceName READ deviceName NOTIFY nameChanged) Q_PROPERTY(bool setupComplete READ setupComplete NOTIFY setupCompleteChanged) Q_PROPERTY(Params *params READ params NOTIFY paramsChanged) Q_PROPERTY(States *states READ states NOTIFY statesChanged) - Q_PROPERTY(StatesProxy *statesProxy READ statesProxy CONSTANT) public: explicit Device(QObject *parent = 0); QString name() const; - - QString deviceName() const; - void setDeviceName(const QString &deviceName); + void setName(const QString &name); QUuid id() const; void setId(const QUuid &id); @@ -65,8 +61,6 @@ public: States *states() const; void setStates(States *states); - StatesProxy *statesProxy() const; - Q_INVOKABLE bool hasState(const QUuid &stateTypeId); Q_INVOKABLE QVariant stateValue(const QUuid &stateTypeId); @@ -77,9 +71,8 @@ private: QUuid m_id; QUuid m_deviceClassId; bool m_setupComplete; - Params *m_params; - States *m_states; - StatesProxy *m_statesProxy; + Params *m_params = nullptr; + States *m_states = nullptr; signals: void nameChanged(); diff --git a/libnymea-common/types/params.cpp b/libnymea-common/types/params.cpp index 318fce51..d1bb0d6b 100644 --- a/libnymea-common/types/params.cpp +++ b/libnymea-common/types/params.cpp @@ -81,6 +81,7 @@ QVariant Params::data(const QModelIndex &index, int role) const void Params::addParam(Param *param) { + param->setParent(this); beginInsertRows(QModelIndex(), m_params.count(), m_params.count()); //qDebug() << "Params: loaded param" << param->name(); m_params.append(param); diff --git a/mea/devicemanager.cpp b/mea/devicemanager.cpp index beb32b4c..443f1ca2 100644 --- a/mea/devicemanager.cpp +++ b/mea/devicemanager.cpp @@ -100,9 +100,10 @@ void DeviceManager::notificationReceived(const QVariantMap &data) } dev->setStateValue(data.value("params").toMap().value("stateTypeId").toUuid(), data.value("params").toMap().value("value")); } else if (notification == "Devices.DeviceAdded") { - Device *dev = JsonTypes::unpackDevice(data.value("params").toMap().value("device").toMap(), m_devices); - if (!dev) { + Device *dev = new Device(); + if (!JsonTypes::unpackDevice(data.value("params").toMap().value("device").toMap(), dev)) { qWarning() << "Cannot parse json device:" << data; + delete dev; return; } m_devices->addDevice(dev); @@ -112,6 +113,18 @@ void DeviceManager::notificationReceived(const QVariantMap &data) Device *device = m_devices->getDevice(deviceId); m_devices->removeDevice(device); device->deleteLater(); + } else if (notification == "Devices.DeviceChanged") { + QUuid deviceId = data.value("params").toMap().value("device").toMap().value("id").toUuid(); + qDebug() << "Device changed notification" << deviceId; + Device *oldDevice = m_devices->getDevice(deviceId); + if (!oldDevice) { + qWarning() << "Received a device changed notification for a device we don't know"; + return; + } + if (!JsonTypes::unpackDevice(data.value("params").toMap().value("device").toMap(), oldDevice)) { + qWarning() << "Error parsing device changed notification"; + return; + } } else { qWarning() << "DeviceManager unhandled device notification received" << notification; } @@ -176,7 +189,8 @@ void DeviceManager::getPluginConfigResponse(const QVariantMap ¶ms) } QVariantList pluginParams = params.value("params").toMap().value("configuration").toList(); foreach (const QVariant ¶mVariant, pluginParams) { - Param* param = JsonTypes::unpackParam(paramVariant.toMap(), p->params()); + Param* param = new Param(); + JsonTypes::unpackParam(paramVariant.toMap(), param); p->params()->addParam(param); } @@ -193,8 +207,11 @@ void DeviceManager::getConfiguredDevicesResponse(const QVariantMap ¶ms) if (params.value("params").toMap().keys().contains("devices")) { QVariantList deviceList = params.value("params").toMap().value("devices").toList(); foreach (QVariant deviceVariant, deviceList) { - Device *device = JsonTypes::unpackDevice(deviceVariant.toMap(), Engine::instance()->deviceManager()->devices()); - if (!device) continue; + Device *device = new Device(); + if (!JsonTypes::unpackDevice(deviceVariant.toMap(), device)) { + qWarning() << "Error parsing device json"; + continue; + } // qDebug() << QJsonDocument::fromVariant(deviceVariant).toJson(); DeviceClass *dc = m_deviceClasses->getDeviceClass(device->deviceClassId()); @@ -235,9 +252,13 @@ void DeviceManager::addDeviceResponse(const QVariantMap ¶ms) qWarning() << "Failed to add the device:" << params.value("params").toMap().value("deviceError").toString(); } else if (params.value("params").toMap().keys().contains("device")) { QVariantMap deviceVariant = params.value("params").toMap().value("device").toMap(); - Device *device = JsonTypes::unpackDevice(deviceVariant, m_devices); - qDebug() << "Device added" << device->id().toString(); - m_devices->addDevice(device); + Device *device = new Device(); + if (JsonTypes::unpackDevice(deviceVariant, device)) { + qDebug() << "Device added" << device->id().toString(); + m_devices->addDevice(device); + } else { + qWarning() << "Error unpacking device json"; + } } emit addDeviceReply(params.value("params").toMap()); } @@ -264,6 +285,12 @@ void DeviceManager::setPluginConfigResponse(const QVariantMap ¶ms) emit savePluginConfigReply(params); } +void DeviceManager::editDeviceResponse(const QVariantMap ¶ms) +{ + qDebug() << "Edit device response" << params; + emit editDeviceReply(params); +} + void DeviceManager::savePluginConfig(const QUuid &pluginId) { Plugin *p = m_plugins->getPlugin(pluginId); @@ -318,6 +345,14 @@ void DeviceManager::removeDevice(const QUuid &deviceId) m_jsonClient->sendCommand("Devices.RemoveConfiguredDevice", params, this, "removeDeviceResponse"); } +void DeviceManager::editDevice(const QUuid &deviceId, const QString &name) +{ + QVariantMap params; + params.insert("deviceId", deviceId.toString()); + params.insert("name", name); + m_jsonClient->sendCommand("Devices.EditDevice", params, this, "editDeviceResponse"); +} + void DeviceManager::executeAction(const QUuid &deviceId, const QUuid &actionTypeId, const QVariantList ¶ms) { qDebug() << "JsonRpc: execute action " << deviceId.toString() << actionTypeId.toString() << params; diff --git a/mea/devicemanager.h b/mea/devicemanager.h index 1e9773f4..b531105f 100644 --- a/mea/devicemanager.h +++ b/mea/devicemanager.h @@ -60,6 +60,7 @@ public: Q_INVOKABLE void pairDevice(const QUuid &deviceClassId, const QUuid &deviceDescriptorId, const QString &name); Q_INVOKABLE void confirmPairing(const QUuid &pairingTransactionId, const QString &secret = QString()); Q_INVOKABLE void removeDevice(const QUuid &deviceId); + Q_INVOKABLE void editDevice(const QUuid &deviceId, const QString &name); Q_INVOKABLE void executeAction(const QUuid &deviceId, const QUuid &actionTypeId, const QVariantList ¶ms = QVariantList()); private: @@ -74,6 +75,7 @@ private: Q_INVOKABLE void pairDeviceResponse(const QVariantMap ¶ms); Q_INVOKABLE void confirmPairingResponse(const QVariantMap ¶ms); Q_INVOKABLE void setPluginConfigResponse(const QVariantMap ¶ms); + Q_INVOKABLE void editDeviceResponse(const QVariantMap ¶ms); public slots: void savePluginConfig(const QUuid &pluginId); @@ -84,6 +86,7 @@ signals: void addDeviceReply(const QVariantMap ¶ms); void removeDeviceReply(const QVariantMap ¶ms); void savePluginConfigReply(const QVariantMap ¶ms); + void editDeviceReply(const QVariantMap ¶ms); void fetchingDataChanged(); private: diff --git a/mea/devices.cpp b/mea/devices.cpp index 876bb408..03c1d1f7 100644 --- a/mea/devices.cpp +++ b/mea/devices.cpp @@ -47,7 +47,7 @@ Device *Devices::getDevice(const QUuid &deviceId) const return device; } } - return 0; + return nullptr; } int Devices::rowCount(const QModelIndex &parent) const @@ -65,8 +65,6 @@ QVariant Devices::data(const QModelIndex &index, int role) const switch (role) { case RoleName: return device->name(); - case RoleDeviceName: - return device->deviceName(); case RoleId: return device->id().toString(); case RoleDeviceClass: @@ -86,10 +84,21 @@ QVariant Devices::data(const QModelIndex &index, int role) const void Devices::addDevice(Device *device) { + device->setParent(this); beginInsertRows(QModelIndex(), m_devices.count(), m_devices.count()); // qDebug() << "Devices: add device" << device->name(); m_devices.append(device); endInsertRows(); + connect(device, &Device::nameChanged, this, [device, this]() { + int idx = m_devices.indexOf(device); + if (idx < 0) return; + emit dataChanged(index(idx), index(idx), {RoleName}); + }); + connect(device, &Device::setupCompleteChanged, this, [device, this]() { + int idx = m_devices.indexOf(device); + if (idx < 0) return; + emit dataChanged(index(idx), index(idx), {RoleSetupComplete}); + }); emit countChanged(); } @@ -117,7 +126,6 @@ QHash Devices::roleNames() const { QHash roles; roles[RoleName] = "name"; - roles[RoleDeviceName] = "deviceName"; roles[RoleId] = "id"; roles[RoleDeviceClass] = "deviceClassId"; roles[RoleSetupComplete] = "setupComplete"; diff --git a/mea/devices.h b/mea/devices.h index 5e578ea7..0e745b2d 100644 --- a/mea/devices.h +++ b/mea/devices.h @@ -35,7 +35,6 @@ class Devices : public QAbstractListModel public: enum Roles { RoleName, - RoleDeviceName, RoleId, RoleDeviceClass, RoleSetupComplete, diff --git a/mea/discovery/zeroconfdiscovery.cpp b/mea/discovery/zeroconfdiscovery.cpp index eabd6763..b9b0eeee 100644 --- a/mea/discovery/zeroconfdiscovery.cpp +++ b/mea/discovery/zeroconfdiscovery.cpp @@ -34,10 +34,11 @@ void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry) if (!entry.name().startsWith("nymea") || entry.serviceType() != "_jsonrpc._tcp" || entry.hostAddress().protocol() == QAbstractSocket::IPv6Protocol) { return; } -// qDebug() << "avahi service entry added" << entry.name() << entry.hostAddress() << entry.port() << entry.txt() << entry.serviceType(); + qDebug() << "avahi service entry added" << entry.name() << entry.hostAddress() << entry.port() << entry.txt() << entry.serviceType(); QString uuid; bool sslEnabled = false; + QString serverName; foreach (const QString &txt, entry.txt()) { QPair txtRecord = qMakePair(txt.split("=").first(), txt.split("=").at(1)); if (!sslEnabled && txtRecord.first == "sslEnabled") { @@ -46,6 +47,9 @@ void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry) if (txtRecord.first == "uuid") { uuid = txtRecord.second; } + if (txtRecord.first == "name") { + serverName = txtRecord.second; + } } DiscoveryDevice dev = m_discoveryModel->find(entry.hostAddress()); @@ -56,7 +60,7 @@ void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry) dev.setUuid(uuid); dev.setHostAddress(entry.hostAddress()); dev.setPort(entry.port()); - dev.setFriendlyName(entry.hostName()); + dev.setFriendlyName(serverName + " on " + entry.hostName()); QHostAddress address = entry.hostAddress(); QString addressString; if (address.protocol() == QAbstractSocket::IPv6Protocol) { diff --git a/mea/jsonrpc/jsontypes.cpp b/mea/jsonrpc/jsontypes.cpp index ebf451d2..d6814cb8 100644 --- a/mea/jsonrpc/jsontypes.cpp +++ b/mea/jsonrpc/jsontypes.cpp @@ -117,9 +117,10 @@ DeviceClass *JsonTypes::unpackDeviceClass(const QVariantMap &deviceClassMap, QOb return deviceClass; } -Param *JsonTypes::unpackParam(const QVariantMap ¶mMap, QObject *parent) +void JsonTypes::unpackParam(const QVariantMap ¶mMap, Param *param) { - return new Param(paramMap.value("paramTypeId").toString(), paramMap.value("value"), parent); + param->setParamTypeId(paramMap.value("paramTypeId").toString()); + param->setValue(paramMap.value("value")); } ParamType *JsonTypes::unpackParamType(const QVariantMap ¶mTypeMap, QObject *parent) @@ -187,25 +188,32 @@ ActionType *JsonTypes::unpackActionType(const QVariantMap &actionTypeMap, QObjec return actionType; } -Device *JsonTypes::unpackDevice(const QVariantMap &deviceMap, QObject *parent) +bool JsonTypes::unpackDevice(const QVariantMap &deviceMap, Device *device) { - Device *device = new Device(parent); - device->setDeviceName(deviceMap.value("name").toString()); + device->setName(deviceMap.value("name").toString()); device->setId(deviceMap.value("id").toUuid()); device->setDeviceClassId(deviceMap.value("deviceClassId").toUuid()); device->setSetupComplete(deviceMap.value("setupComplete").toBool()); - Params *params = new Params(device); + Params *params = device->params(); + if (!params) { + params = new Params(device); + device->setParams(params); + } foreach (QVariant param, deviceMap.value("params").toList()) { - params->addParam(JsonTypes::unpackParam(param.toMap(), params)); + Param *p = params->getParam(param.toMap().value("paramTypeId").toString()); + if (!p) { + p = new Param(); + params->addParam(p); + } + JsonTypes::unpackParam(param.toMap(), p); } device->setParams(params); DeviceClass *deviceClass = Engine::instance()->deviceManager()->deviceClasses()->getDeviceClass(device->deviceClassId()); if (!deviceClass) { qWarning() << "Cannot find a device class for this device..." << device->deviceClassId() << "Skipping..."; - delete device; - return nullptr; + return false; } States *states = new States(device); foreach (StateType *stateType, deviceClass->stateTypes()->stateTypes()) { @@ -214,7 +222,7 @@ Device *JsonTypes::unpackDevice(const QVariantMap &deviceMap, QObject *parent) } device->setStates(states); - return device; + return true; } QVariantMap JsonTypes::packRule(Rule *rule) diff --git a/mea/jsonrpc/jsontypes.h b/mea/jsonrpc/jsontypes.h index f0318c5f..90bbba75 100644 --- a/mea/jsonrpc/jsontypes.h +++ b/mea/jsonrpc/jsontypes.h @@ -53,12 +53,12 @@ public: static Vendor *unpackVendor(const QVariantMap &vendorMap, QObject *parent); static Plugin *unpackPlugin(const QVariantMap &pluginMap, QObject *parent); static DeviceClass *unpackDeviceClass(const QVariantMap &deviceClassMap, QObject *parent); - static Param *unpackParam(const QVariantMap ¶mMap, QObject *parent); + static void unpackParam(const QVariantMap ¶mMap, Param *param); static ParamType *unpackParamType(const QVariantMap ¶mTypeMap, QObject *parent); static StateType *unpackStateType(const QVariantMap &stateTypeMap, QObject *parent); static EventType *unpackEventType(const QVariantMap &eventTypeMap, QObject *parent); static ActionType *unpackActionType(const QVariantMap &actionTypeMap, QObject *parent); - static Device *unpackDevice(const QVariantMap &deviceMap, QObject *parent); + static bool unpackDevice(const QVariantMap &deviceMap, Device *device); static QVariantMap packRule(Rule* rule); static QVariantList packRuleActions(RuleActions* ruleActions); diff --git a/mea/main.cpp b/mea/main.cpp index 483fb2b4..2fa7a3f2 100644 --- a/mea/main.cpp +++ b/mea/main.cpp @@ -107,7 +107,6 @@ int main(int argc, char *argv[]) qmlRegisterUncreatableType(uri, 1, 0, "State", "Can't create this in QML. Get it from the States."); qmlRegisterUncreatableType(uri, 1, 0, "States", "Can't create this in QML. Get it from the Device."); - qmlRegisterUncreatableType(uri, 1, 0, "StatesProxy", "Can't create this in QML. Get it from the Device."); qmlRegisterUncreatableType(uri, 1, 0, "Vendor", "Can't create this in QML. Get it from the Vendors."); qmlRegisterUncreatableType(uri, 1, 0, "Vendors", "Can't create this in QML. Get it from the DeviceManager."); diff --git a/mea/models/logsmodel.cpp b/mea/models/logsmodel.cpp index 0106ca18..6c7d6973 100644 --- a/mea/models/logsmodel.cpp +++ b/mea/models/logsmodel.cpp @@ -155,7 +155,7 @@ void LogsModel::update() void LogsModel::logsReply(const QVariantMap &data) { - qDebug() << "logs reply" << data; + qDebug() << "logs reply";// << data; m_busy = false; emit busyChanged(); beginResetModel(); diff --git a/mea/resources.qrc b/mea/resources.qrc index a032b7b2..f38eba94 100644 --- a/mea/resources.qrc +++ b/mea/resources.qrc @@ -141,5 +141,6 @@ ui/magic/SelectStateDescriptorParamsPage.qml ui/magic/SelectStateDescriptorPage.qml ui/images/select-none.svg + ui/images/edit.svg diff --git a/mea/ui/devicelistpages/LightsDeviceListPage.qml b/mea/ui/devicelistpages/LightsDeviceListPage.qml index 06613a48..770ec45b 100644 --- a/mea/ui/devicelistpages/LightsDeviceListPage.qml +++ b/mea/ui/devicelistpages/LightsDeviceListPage.qml @@ -65,7 +65,8 @@ Page { verticalAlignment: Text.AlignVCenter } ThrottledSlider { - visible: model.interfaces.indexOf("dimmablelight") >= 0 + id: inlineSlider + visible: model.interfaces.indexOf("dimmablelight") >= 0 && parent.width > 350 property var stateType: deviceClass.stateTypes.findByName("brightness"); property var actionType: deviceClass.actionTypes.findByName("brightness"); property var actionState: device.states.getState(stateType.id) diff --git a/mea/ui/devicepages/ConfigureThingPage.qml b/mea/ui/devicepages/ConfigureThingPage.qml index a4ad967a..124a7a69 100644 --- a/mea/ui/devicepages/ConfigureThingPage.qml +++ b/mea/ui/devicepages/ConfigureThingPage.qml @@ -15,10 +15,26 @@ Page { onBackPressed: pageStack.pop() HeaderButton { - imageSource: "../images/delete.svg" - color: "red" - onClicked: { - Engine.deviceManager.removeDevice(root.device.id) + imageSource: "../images/navigation-menu.svg" + onClicked: deviceMenu.open() + } + } + + Menu { + id: deviceMenu + width: implicitWidth + app.margins + x: parent.width - width + IconMenuItem { + iconSource: "../images/delete.svg" + text: "Delete Thing" + onTriggered: Engine.deviceManager.removeDevice(root.device.id) + } + IconMenuItem { + iconSource: "../images/edit.svg" + text: "Rename Thing" + onTriggered: { + var popup = renameDialog.createObject(root); + popup.open(); } } } @@ -35,19 +51,61 @@ Page { } } - ListView { + Flickable { anchors.fill: parent - model: root.device.params - delegate: ParamDelegate { + + ColumnLayout { width: parent.width - paramType: root.deviceClass.paramTypes.getParamType(model.id) - param: root.device.params.get(index) - writable: false + + Label { + Layout.fillWidth: true + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + Layout.topMargin: app.margins + text: "Thing parameters".toUpperCase() + color: app.guhAccent + } + + Repeater { + model: root.device.params + delegate: ParamDelegate { + Layout.fillWidth: true + paramType: root.deviceClass.paramTypes.getParamType(model.id) + param: root.device.params.get(index) + writable: false + } + } + +// ThinDivider {} } + } Component { id: errorDialog ErrorDialog { } } + + Component { + id: renameDialog + Dialog { + id: dialog + width: parent.width * .8 + x: (parent.width - width) / 2 + y: app.margins + + standardButtons: Dialog.Ok | Dialog.Cancel + + TextField { + id: textField + text: root.device.name + width: parent.width + } + + onAccepted: { + Engine.deviceManager.editDevice(root.device.id, textField.text) + dialog.destroy(); + } + } + } } diff --git a/mea/ui/images/edit.svg b/mea/ui/images/edit.svg new file mode 100644 index 00000000..e7b91bb4 --- /dev/null +++ b/mea/ui/images/edit.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/mea/ui/paramdelegates-ng/ParamDelegate.qml b/mea/ui/paramdelegates-ng/ParamDelegate.qml index 6474b478..4c6f8ca8 100644 --- a/mea/ui/paramdelegates-ng/ParamDelegate.qml +++ b/mea/ui/paramdelegates-ng/ParamDelegate.qml @@ -1,6 +1,6 @@ import QtQuick 2.8 import QtQuick.Layouts 1.2 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.1 import Mea 1.0 import "../components" @@ -102,21 +102,29 @@ ItemDelegate { text: root.paramType.minValue } Slider { + id: slider Layout.fillWidth: true from: root.paramType.minValue to: root.paramType.maxValue value: root.param.value stepSize: { - switch (root.paramType.type) { - case "Int": + switch (root.paramType.type.toLowerCase()) { + case "int": return 1; } return 0.01; - } onMoved: { - root.param.value = value; + var newValue + switch (root.paramType.type.toLowerCase()) { + case "int": + newValue = Math.round(value) + break; + default: + newValue = Math.round(value * 10) / 10 + } + root.param.value = newValue; } } Label {