From a1d910f7590f990394d7300d2f69fddcf6181273 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 29 Apr 2020 12:11:04 +0200 Subject: [PATCH] Add support for AP mode in settings and display IP address configs --- libnymea-app/configuration/networkmanager.cpp | 92 ++++++++-- libnymea-app/configuration/networkmanager.h | 41 +++-- libnymea-app/types/interfaces.cpp | 2 +- libnymea-app/types/networkdevice.cpp | 39 +++++ libnymea-app/types/networkdevice.h | 28 +++- libnymea-app/types/networkdevices.cpp | 28 +++- libnymea-app/types/networkdevices.h | 12 +- nymea-app/ui/components/PasswordTextField.qml | 2 +- nymea-app/ui/system/NetworkSettingsPage.qml | 157 +++++++++++++++--- 9 files changed, 341 insertions(+), 60 deletions(-) diff --git a/libnymea-app/configuration/networkmanager.cpp b/libnymea-app/configuration/networkmanager.cpp index 2a1eb9d8..242eba4e 100644 --- a/libnymea-app/configuration/networkmanager.cpp +++ b/libnymea-app/configuration/networkmanager.cpp @@ -98,8 +98,8 @@ void NetworkManager::init() m_loading = true; emit loadingChanged(); - m_engine->jsonRpcClient()->sendCommand("NetworkManager.GetNetworkStatus", QVariantMap(), this, "getStatusReply"); - m_engine->jsonRpcClient()->sendCommand("NetworkManager.GetNetworkDevices", QVariantMap(), this, "getDevicesReply"); + m_engine->jsonRpcClient()->sendCommand("NetworkManager.GetNetworkStatus", QVariantMap(), this, "getStatusResponse"); + m_engine->jsonRpcClient()->sendCommand("NetworkManager.GetNetworkDevices", QVariantMap(), this, "getDevicesResponse"); } bool NetworkManager::available() const @@ -132,45 +132,54 @@ WirelessNetworkDevices *NetworkManager::wirelessNetworkDevices() const return m_wirelessNetworkDevices; } -void NetworkManager::enableNetworking(bool enable) +int NetworkManager::enableNetworking(bool enable) { QVariantMap params; params.insert("enable", enable); - m_engine->jsonRpcClient()->sendCommand("NetworkManager.EnableNetworking", params, this, "enableNetworkingReply"); + return m_engine->jsonRpcClient()->sendCommand("NetworkManager.EnableNetworking", params, this, "enableNetworkingResponse"); } -void NetworkManager::enableWirelessNetworking(bool enable) +int NetworkManager::enableWirelessNetworking(bool enable) { QVariantMap params; params.insert("enable", enable); - m_engine->jsonRpcClient()->sendCommand("NetworkManager.EnableWirelessNetworking", params, this, "enableNetworkingReply"); + return m_engine->jsonRpcClient()->sendCommand("NetworkManager.EnableWirelessNetworking", params, this, "enableWirelessNetworkingResponse"); } void NetworkManager::refreshWifis(const QString &interface) { QVariantMap params; params.insert("interface", interface); - int requestId = m_engine->jsonRpcClient()->sendCommand("NetworkManager.GetWirelessAccessPoints", params, this, "getAccessPointsReply"); + int requestId = m_engine->jsonRpcClient()->sendCommand("NetworkManager.GetWirelessAccessPoints", params, this, "getAccessPointsResponse"); m_apRequests.insert(requestId, interface); } -void NetworkManager::connectToWiFi(const QString &interface, const QString &ssid, const QString &passphrase) +int NetworkManager::connectToWiFi(const QString &interface, const QString &ssid, const QString &passphrase) { QVariantMap params; params.insert("interface", interface); params.insert("ssid", ssid); params.insert("password", passphrase); - m_engine->jsonRpcClient()->sendCommand("NetworkManager.ConnectWifiNetwork", params, this, "connectToWiFiReply"); + return m_engine->jsonRpcClient()->sendCommand("NetworkManager.ConnectWifiNetwork", params, this, "connectToWiFiResponse"); } -void NetworkManager::disconnectInterface(const QString &interface) +int NetworkManager::startAccessPoint(const QString &interface, const QString &ssid, const QString &passphrase) { QVariantMap params; params.insert("interface", interface); - m_engine->jsonRpcClient()->sendCommand("NetworkManager.DisconnectInterface", params, this, "disconnectReply"); + params.insert("ssid", ssid); + params.insert("password", passphrase); + return m_engine->jsonRpcClient()->sendCommand("NetworkManager.StartAccessPoint", params, this, "startAccessPointResponse"); } -void NetworkManager::getStatusReply(const QVariantMap ¶ms) +int NetworkManager::disconnectInterface(const QString &interface) +{ + QVariantMap params; + params.insert("interface", interface); + return m_engine->jsonRpcClient()->sendCommand("NetworkManager.DisconnectInterface", params, this, "disconnectResponse"); +} + +void NetworkManager::getStatusResponse(const QVariantMap ¶ms) { m_loading = false; emit loadingChanged(); @@ -206,13 +215,15 @@ void NetworkManager::getStatusReply(const QVariantMap ¶ms) } } -void NetworkManager::getDevicesReply(const QVariantMap ¶ms) +void NetworkManager::getDevicesResponse(const QVariantMap ¶ms) { -// qDebug() << "Devices reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + qDebug() << "Devices reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); foreach (const QVariant &deviceVariant, params.value("params").toMap().value("wiredNetworkDevices").toList()) { QVariantMap deviceMap = deviceVariant.toMap(); WiredNetworkDevice *device = new WiredNetworkDevice(deviceMap.value("macAddress").toString(), deviceMap.value("interface").toString(), this); + device->setIpv4Addresses(deviceMap.value("ipv4Addresses").toStringList()); + device->setIpv6Addresses(deviceMap.value("ipv6Addresses").toStringList()); device->setBitRate(deviceMap.value("bitRate").toString()); QMetaEnum stateEnum = QMetaEnum::fromType(); device->setState(static_cast(stateEnum.keyToValue(deviceMap.value("state").toString().toUtf8()))); @@ -222,9 +233,13 @@ void NetworkManager::getDevicesReply(const QVariantMap ¶ms) foreach (const QVariant &deviceVariant, params.value("params").toMap().value("wirelessNetworkDevices").toList()) { QVariantMap deviceMap = deviceVariant.toMap(); WirelessNetworkDevice *device = new WirelessNetworkDevice(deviceMap.value("macAddress").toString(), deviceMap.value("interface").toString(), this); + device->setIpv4Addresses(deviceMap.value("ipv4Addresses").toStringList()); + device->setIpv6Addresses(deviceMap.value("ipv6Addresses").toStringList()); device->setBitRate(deviceMap.value("bitRate").toString()); QMetaEnum stateEnum = QMetaEnum::fromType(); device->setState(static_cast(stateEnum.keyToValue(deviceMap.value("state").toString().toUtf8()))); + QMetaEnum modeEnum = QMetaEnum::fromType(); + device->setWirelessMode(static_cast(modeEnum.keyToValue(deviceMap.value("mode").toString().toUtf8()))); QVariantMap currentApMap = deviceMap.value("currentAccessPoint").toMap(); device->currentAccessPoint()->setSsid(currentApMap.value("ssid").toString()); @@ -236,7 +251,7 @@ void NetworkManager::getDevicesReply(const QVariantMap ¶ms) } } -void NetworkManager::getAccessPointsReply(const QVariantMap ¶ms) +void NetworkManager::getAccessPointsResponse(const QVariantMap ¶ms) { qDebug() << "Access points reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); @@ -268,19 +283,44 @@ void NetworkManager::getAccessPointsReply(const QVariantMap ¶ms) } -void NetworkManager::connectToWiFiReply(const QVariantMap ¶ms) +void NetworkManager::connectToWiFiResponse(const QVariantMap ¶ms) { qDebug() << "connect to wifi reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + int id = params.value("id").toInt(); + QString status = params.value("params").toMap().value("networkManagerError").toString(); + emit connectToWiFiReply(id, status); } -void NetworkManager::disconnectReply(const QVariantMap ¶ms) +void NetworkManager::disconnectResponse(const QVariantMap ¶ms) { qDebug() << "disconnect reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + int id = params.value("id").toInt(); + QString status = params.value("params").toMap().value("networkManagerError").toString(); + emit disconnectReply(id, status); } -void NetworkManager::enableNetworkingReply(const QVariantMap ¶ms) +void NetworkManager::enableNetworkingResponse(const QVariantMap ¶ms) { qDebug() << "enable networking reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + int id = params.value("id").toInt(); + QString status = params.value("params").toMap().value("networkManagerError").toString(); + emit enableNetworkingReply(id, status); +} + +void NetworkManager::enableWirelessNetworkingResponse(const QVariantMap ¶ms) +{ + qDebug() << "enable wireless networking reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + int id = params.value("id").toInt(); + QString status = params.value("params").toMap().value("networkManagerError").toString(); + emit enableWirelessNetworkingReply(id, status); +} + +void NetworkManager::startAccessPointResponse(const QVariantMap ¶ms) +{ + qDebug() << "Start access point reply" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson(QJsonDocument::Indented)); + int id = params.value("id").toInt(); + QString status = params.value("params").toMap().value("networkManagerError").toString(); + emit startAccessPointReply(id, status); } void NetworkManager::notificationReceived(const QVariantMap ¶ms) @@ -294,14 +334,30 @@ void NetworkManager::notificationReceived(const QVariantMap ¶ms) return; } device->setBitRate(deviceMap.value("bitRate").toString()); + device->setIpv4Addresses(deviceMap.value("ipv4Addresses").toStringList()); + device->setIpv6Addresses(deviceMap.value("ipv6Addresses").toStringList()); QMetaEnum stateEnum = QMetaEnum::fromType(); device->setState(static_cast(stateEnum.keyToValue(deviceMap.value("state").toString().toUtf8()))); + QMetaEnum modeEnum = QMetaEnum::fromType(); + device->setWirelessMode(static_cast(modeEnum.keyToValue(deviceMap.value("mode").toString().toUtf8()))); QVariantMap currentApMap = deviceMap.value("currentAccessPoint").toMap(); device->currentAccessPoint()->setSsid(currentApMap.value("ssid").toString()); device->currentAccessPoint()->setMacAddress(currentApMap.value("macAddress").toString()); device->currentAccessPoint()->setProtected(currentApMap.value("protected").toBool()); device->currentAccessPoint()->setSignalStrength(currentApMap.value("signalStrength").toInt()); + } else if (notification == "NetworkManager.WiredNetworkDeviceChanged") { + QVariantMap deviceMap = params.value("params").toMap().value("wiredNetworkDevice").toMap(); + WiredNetworkDevice* device = m_wiredNetworkDevices->getWiredNetworkDevice(deviceMap.value("interface").toString()); + if (!device) { + qWarning() << "Received a notification for a network device we don't know" << deviceMap; + return; + } + device->setBitRate(deviceMap.value("bitRate").toString()); + device->setIpv4Addresses(deviceMap.value("ipv4Addresses").toStringList()); + device->setIpv6Addresses(deviceMap.value("ipv6Addresses").toStringList()); + QMetaEnum stateEnum = QMetaEnum::fromType(); + device->setState(static_cast(stateEnum.keyToValue(deviceMap.value("state").toString().toUtf8()))); } else if (notification == "NetworkManager.NetworkStatusChanged") { QMetaEnum stateEnum = QMetaEnum::fromType(); NetworkManagerState state = static_cast(stateEnum.keyToValue(params.value("params").toMap().value("status").toMap().value("state").toString().toUtf8())); diff --git a/libnymea-app/configuration/networkmanager.h b/libnymea-app/configuration/networkmanager.h index 3b06bad3..72d02919 100644 --- a/libnymea-app/configuration/networkmanager.h +++ b/libnymea-app/configuration/networkmanager.h @@ -87,25 +87,14 @@ public: WiredNetworkDevices* wiredNetworkDevices() const; WirelessNetworkDevices* wirelessNetworkDevices() const; - Q_INVOKABLE void enableNetworking(bool enable); - Q_INVOKABLE void enableWirelessNetworking(bool enable); + Q_INVOKABLE int enableNetworking(bool enable); + Q_INVOKABLE int enableWirelessNetworking(bool enable); Q_INVOKABLE void refreshWifis(const QString &interface); - Q_INVOKABLE void connectToWiFi(const QString &interface, const QString &ssid, const QString &passphrase); - Q_INVOKABLE void disconnectInterface(const QString &interface); - -private slots: - void init(); - - void getStatusReply(const QVariantMap ¶ms); - void getDevicesReply(const QVariantMap ¶ms); - void getAccessPointsReply(const QVariantMap ¶ms); - void connectToWiFiReply(const QVariantMap ¶ms); - void disconnectReply(const QVariantMap ¶ms); - void enableNetworkingReply(const QVariantMap ¶ms); - - void notificationReceived(const QVariantMap ¶ms); + Q_INVOKABLE int connectToWiFi(const QString &interface, const QString &ssid, const QString &passphrase); + Q_INVOKABLE int startAccessPoint(const QString &interface, const QString &ssid, const QString &passphrase); + Q_INVOKABLE int disconnectInterface(const QString &interface); signals: void engineChanged(); @@ -115,6 +104,26 @@ signals: void networkingEnabledChanged(); void wirelessNetworkingEnabledChanged(); + void enableNetworkingReply(int id, const QString &status); + void enableWirelessNetworkingReply(int id, const QString &status); + void connectToWiFiReply(int id, const QString &status); + void disconnectReply(int id, const QString &status); + void startAccessPointReply(int id, const QString &status); + +private slots: + void init(); + + void getStatusResponse(const QVariantMap ¶ms); + void getDevicesResponse(const QVariantMap ¶ms); + void getAccessPointsResponse(const QVariantMap ¶ms); + void connectToWiFiResponse(const QVariantMap ¶ms); + void disconnectResponse(const QVariantMap ¶ms); + void enableNetworkingResponse(const QVariantMap ¶ms); + void enableWirelessNetworkingResponse(const QVariantMap ¶ms); + void startAccessPointResponse(const QVariantMap ¶ms); + + void notificationReceived(const QVariantMap ¶ms); + private: Engine *m_engine = nullptr; bool m_loading = false; diff --git a/libnymea-app/types/interfaces.cpp b/libnymea-app/types/interfaces.cpp index 3e131ec7..4ecdb540 100644 --- a/libnymea-app/types/interfaces.cpp +++ b/libnymea-app/types/interfaces.cpp @@ -85,7 +85,7 @@ Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent) addInterface("button", tr("Switches")); addEventType("button", "pressed", tr("Button pressed"), new ParamTypes()); - addInterface("sensor", tr("Sensor")); + addInterface("sensor", tr("Sensors")); addInterface("closablesensor", tr("Closable sensors"), {"sensor"}); addStateType("closablesensor", "closed", QVariant::Bool, false, tr("Closed"), tr("Opened or closed")); diff --git a/libnymea-app/types/networkdevice.cpp b/libnymea-app/types/networkdevice.cpp index 7bc93be1..d4f79341 100644 --- a/libnymea-app/types/networkdevice.cpp +++ b/libnymea-app/types/networkdevice.cpp @@ -46,11 +46,37 @@ QString NetworkDevice::macAddress() const return m_macAddress; } +QStringList NetworkDevice::ipv4Addresses() const +{ + return m_ipv4Addresses; +} + +QStringList NetworkDevice::ipv6Addresses() const +{ + return m_ipv6Addresses; +} + QString NetworkDevice::interface() const { return m_interface; } +void NetworkDevice::setIpv4Addresses(const QStringList &ipAddresses) +{ + if (m_ipv4Addresses != ipAddresses) { + m_ipv4Addresses = ipAddresses; + emit ipv4AddressesChanged(); + } +} + +void NetworkDevice::setIpv6Addresses(const QStringList &ipAddresses) +{ + if (m_ipv6Addresses != ipAddresses) { + m_ipv6Addresses = ipAddresses; + emit ipv6AddressesChanged(); + } +} + QString NetworkDevice::bitRate() const { return m_bitRate; @@ -103,6 +129,11 @@ WirelessNetworkDevice::WirelessNetworkDevice(const QString &macAddress, const QS m_currentAccessPoint = new WirelessAccessPoint(this); } +WirelessNetworkDevice::WirelessMode WirelessNetworkDevice::wirelessMode() const +{ + return m_wirelessMode; +} + WirelessAccessPoints *WirelessNetworkDevice::accessPoints() const { return m_accessPoints; @@ -112,3 +143,11 @@ WirelessAccessPoint *WirelessNetworkDevice::currentAccessPoint() const { return m_currentAccessPoint; } + +void WirelessNetworkDevice::setWirelessMode(WirelessNetworkDevice::WirelessMode wirelessMode) +{ + if (m_wirelessMode != wirelessMode) { + m_wirelessMode = wirelessMode; + emit wirelessModeChanged(); + } +} diff --git a/libnymea-app/types/networkdevice.h b/libnymea-app/types/networkdevice.h index b81f7630..01ced778 100644 --- a/libnymea-app/types/networkdevice.h +++ b/libnymea-app/types/networkdevice.h @@ -40,6 +40,8 @@ class NetworkDevice : public QObject { Q_OBJECT Q_PROPERTY(QString macAddress READ macAddress CONSTANT) + Q_PROPERTY(QStringList ipv4Addresses READ ipv4Addresses NOTIFY ipv4AddressesChanged) + Q_PROPERTY(QStringList ipv6Addresses READ ipv6Addresses NOTIFY ipv6AddressesChanged) Q_PROPERTY(QString interface READ interface CONSTANT) Q_PROPERTY(QString bitRate READ bitRate NOTIFY bitRateChanged) Q_PROPERTY(NetworkDeviceState state READ state NOTIFY stateChanged) @@ -65,8 +67,13 @@ public: explicit NetworkDevice(const QString &macAddress, const QString &interface, QObject *parent = nullptr); virtual ~NetworkDevice() = default; - QString macAddress() const; QString interface() const; + QString macAddress() const; + QStringList ipv4Addresses() const; + QStringList ipv6Addresses() const; + + void setIpv4Addresses(const QStringList &ipv4Addresses); + void setIpv6Addresses(const QStringList &ipv6Addresses); QString bitRate() const; void setBitRate(const QString &bitRate); @@ -77,9 +84,13 @@ public: signals: void bitRateChanged(); void stateChanged(); + void ipv4AddressesChanged(); + void ipv6AddressesChanged(); private: QString m_macAddress; + QStringList m_ipv4Addresses; + QStringList m_ipv6Addresses; QString m_interface; QString m_bitRate; NetworkDeviceState m_state; @@ -105,16 +116,31 @@ private: class WirelessNetworkDevice: public NetworkDevice { Q_OBJECT + Q_PROPERTY(WirelessMode wirelessMode READ wirelessMode NOTIFY wirelessModeChanged) Q_PROPERTY(WirelessAccessPoints* accessPoints READ accessPoints CONSTANT) Q_PROPERTY(WirelessAccessPoint* currentAccessPoint READ currentAccessPoint CONSTANT) public: + enum WirelessMode { + WirelessModeUnknown = 0, + WirelessModeAdhoc = 1, + WirelessModeInfrastructure = 2, + WirelessModeAccessPoint = 3 + }; + Q_ENUM(WirelessMode) explicit WirelessNetworkDevice(const QString &macAddress, const QString &interface, QObject *parent = nullptr); + WirelessMode wirelessMode() const; WirelessAccessPoints* accessPoints() const; WirelessAccessPoint* currentAccessPoint() const; + void setWirelessMode(WirelessMode wirelessMode); + +signals: + void wirelessModeChanged(); + private: + WirelessMode m_wirelessMode = WirelessModeUnknown; WirelessAccessPoints *m_accessPoints = nullptr; WirelessAccessPoint *m_currentAccessPoint = nullptr; }; diff --git a/libnymea-app/types/networkdevices.cpp b/libnymea-app/types/networkdevices.cpp index eac8198e..9ab562a2 100644 --- a/libnymea-app/types/networkdevices.cpp +++ b/libnymea-app/types/networkdevices.cpp @@ -53,6 +53,10 @@ QVariant NetworkDevices::data(const QModelIndex &index, int role) const return m_list.at(index.row())->bitRate(); case RoleState: return m_list.at(index.row())->state(); + case RoleIpv4Addresses: + return m_list.at(index.row())->ipv4Addresses(); + case RoleIpv6Addresses: + return m_list.at(index.row())->ipv6Addresses(); } return QVariant(); } @@ -64,6 +68,8 @@ QHash NetworkDevices::roleNames() const roles.insert(RoleInterface, "interface"); roles.insert(RoleBitRate, "bitRate"); roles.insert(RoleState, "state"); + roles.insert(RoleIpv4Addresses, "ipv4Addresses"); + roles.insert(RoleIpv6Addresses, "ipv6Addresses"); return roles; } @@ -164,13 +170,33 @@ QHash WiredNetworkDevices::roleNames() const return roles; } +WiredNetworkDevice *WiredNetworkDevices::getWiredNetworkDevice(const QString &interface) +{ + return dynamic_cast(NetworkDevices::getNetworkDevice(interface)); +} + WirelessNetworkDevices::WirelessNetworkDevices(QObject *parent): NetworkDevices (parent) { } -#include +QVariant WirelessNetworkDevices::data(const QModelIndex &index, int role) const +{ + if (role == RoleWirelessMode) { + WirelessNetworkDevice *dev = qobject_cast(m_list.at(index.row())); + return dev->wirelessMode(); + } + return NetworkDevices::data(index, role); +} + + +QHash WirelessNetworkDevices::roleNames() const +{ + QHash roles = NetworkDevices::roleNames(); + roles.insert(RoleWirelessMode, "wirelessMode"); + return roles; +} WirelessNetworkDevice *WirelessNetworkDevices::getWirelessNetworkDevice(const QString &interface) { diff --git a/libnymea-app/types/networkdevices.h b/libnymea-app/types/networkdevices.h index ff05e13c..d86fcb80 100644 --- a/libnymea-app/types/networkdevices.h +++ b/libnymea-app/types/networkdevices.h @@ -47,6 +47,8 @@ public: RoleInterface, RoleBitRate, RoleState, + RoleIpv4Addresses, + RoleIpv6Addresses }; Q_ENUM(Roles) @@ -82,18 +84,26 @@ public: explicit WiredNetworkDevices(QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; void addNetworkDevice(NetworkDevice *device) override; - QHash roleNames() const override; + Q_INVOKABLE WiredNetworkDevice* getWiredNetworkDevice(const QString &interface); + }; class WirelessNetworkDevices: public NetworkDevices { Q_OBJECT public: + enum Roles { + RoleWirelessMode = 1000 + }; explicit WirelessNetworkDevices(QObject *parent = nullptr); + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + Q_INVOKABLE WirelessNetworkDevice* getWirelessNetworkDevice(const QString &interface); }; diff --git a/nymea-app/ui/components/PasswordTextField.qml b/nymea-app/ui/components/PasswordTextField.qml index eef878c7..6a62f7ab 100644 --- a/nymea-app/ui/components/PasswordTextField.qml +++ b/nymea-app/ui/components/PasswordTextField.qml @@ -71,7 +71,7 @@ ColumnLayout { id: passwordTextField Layout.fillWidth: true echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal - placeholderText: root.signup ? qsTr("Pick a password") : "" + placeholderText: root.signup ? qsTr("Pick a password") : qsTr("Password") ToolTip.visible: root.signup && focus && !root.isValidPassword ToolTip.delay: 1000 diff --git a/nymea-app/ui/system/NetworkSettingsPage.qml b/nymea-app/ui/system/NetworkSettingsPage.qml index fff94ebd..0586b677 100644 --- a/nymea-app/ui/system/NetworkSettingsPage.qml +++ b/nymea-app/ui/system/NetworkSettingsPage.qml @@ -38,14 +38,64 @@ import "../components" SettingsPageBase { id: root title: qsTr("Network settings") - busy: networkManager.loading + busy: networkManager.loading || d.pendingCallId !== -1 NetworkManager { id: networkManager engine: _engine + onEnableNetworkingReply: handleReply(id, status) + onEnableWirelessNetworkingReply: handleReply(id, status) + onConnectToWiFiReply: handleReply(id, status) + onStartAccessPointReply: handleReply(id, status) + onDisconnectReply: handleReply(id, status) + + function handleReply(id, status) { + if (id === d.pendingCallId) { + d.pendingCallId = -1 + } + var errorMessage; + switch (status) { + case "NetworkManagerErrorNoError": + return; + case "NetworkManagerErrorWirelessNotAvailable": + errorMessage = qsTr("No wireless hardware available.") + break; + case "NetworkManagerErrorAccessPointNotFound": + errorMessage = qsTr("The access point cannot be found.") + break; + case "NetworkManagerErrorNetworkInterfaceNotFound": + errorMessage = qsTr("The network interface cannot be found.") + break; + case "NetworkManagerErrorInvalidNetworkDeviceType": + errorMessage = qsTr("Invalid network device type.") + break; + case "NetworkManagerErrorWirelessNetworkingDisabled": + errorMessage = qsTr("Wireless networking is disabled.") + break; + case "NetworkManagerErrorWirelessConnectionFailed": + errorMessage = qsTr("The wireless connection failed.") + break; + case "NetworkManagerErrorNetworkingDisabled": + errorMessage = qsTr("Networking is disabled.") + break; + case "NetworkManagerErrorNetworkManagerNotAvailable": + errorMessage = qsTr("The network manager is not available.") + break; + case "NetworkManagerErrorUnknownError": + break; + + } + var component = Qt.createComponent(Qt.resolvedUrl("../components/ErrorDialog.qml")) + var popup = component.createObject(root, {text: errorMessage, errorCode: stats}) + } } - function networkStateToString(networkState) { + QtObject { + id: d + property int pendingCallId: -1 + } + + function networkStateToString(networkState, mode) { switch (networkState) { case NetworkDevice.NetworkDeviceStateUnknown: return qsTr("Unknown") @@ -72,13 +122,17 @@ SettingsPageBase { case NetworkDevice.NetworkDeviceStateSecondaries: return qsTr("Secondaries") case NetworkDevice.NetworkDeviceStateActivated: - return qsTr("Connected"); + if (mode === WirelessNetworkDevice.WirelessModeAccessPoint) { + return qsTr("Hosting access point"); + } else { + return qsTr("Connected"); + } } } RowLayout { Layout.topMargin: app.margins * 6 - visible: !networkManager.available + visible: !networkManager.available && !networkManager.loading spacing: app.margins ColorIcon { Layout.preferredHeight: app.iconSize @@ -172,13 +226,13 @@ SettingsPageBase { }); popup.open(); popup.accepted.connect(function() { - networkManager.enableNetworking(false); + d.pendingCallId = networkManager.enableNetworking(false); }) popup.rejected.connect(function() { checked = true; }) } else { - networkManager.enableNetworking(true); + d.pendingCallId = networkManager.enableNetworking(true); } } } @@ -186,7 +240,7 @@ SettingsPageBase { SettingsPageSectionHeader { text: qsTr("Wired network") - visible: networkManager.available + visible: networkManager.available && networkManager.networkingEnabled } Label { @@ -195,7 +249,7 @@ SettingsPageBase { Layout.rightMargin: app.margins text: qsTr("No wired network interfaces available") wrapMode: Text.WordWrap - visible: networkManager.available && networkManager.wiredNetworkDevices.count == 0 + visible: networkManager.available && networkManager.networkingEnabled && networkManager.wiredNetworkDevices.count == 0 } Repeater { @@ -205,7 +259,7 @@ SettingsPageBase { Layout.fillWidth: true iconName: model.pluggedIn ? "../images/network-wired.svg" : "../images/network-wired-offline.svg" text: model.interface + " (" + model.macAddress + ")" - visible: networkManager.available + visible: networkManager.available && networkManager.networkingEnabled subText: { var ret = model.pluggedIn ? qsTr("Plugged in") : qsTr("Unplugged") ret += " - " @@ -218,7 +272,7 @@ SettingsPageBase { SettingsPageSectionHeader { text: qsTr("Wireless network") - visible: networkManager.available + visible: networkManager.available && networkManager.networkingEnabled } NymeaListItemDelegate { @@ -227,10 +281,11 @@ SettingsPageBase { subText: qsTr("Enable or disable WiFi") progressive: false prominentSubText: false + visible: networkManager.available && networkManager.networkingEnabled additionalItem: Switch { anchors.verticalCenter: parent.verticalCenter checked: networkManager.wirelessNetworkingEnabled - visible: networkManager.available + visible: networkManager.available && networkManager.networkingEnabled onClicked: { if (!checked) { var dialog = Qt.createComponent(Qt.resolvedUrl("../components/MeaDialog.qml")); @@ -246,13 +301,13 @@ SettingsPageBase { }); popup.open(); popup.accepted.connect(function() { - networkManager.enableWirelessNetworking(false); + d.pendingCallId = networkManager.enableWirelessNetworking(false); }) popup.rejected.connect(function() { checked = true; }) } else { - networkManager.enableWirelessNetworking(true); + d.pendingCallId = networkManager.enableWirelessNetworking(true); } } } @@ -264,14 +319,14 @@ SettingsPageBase { Layout.rightMargin: app.margins text: qsTr("No wired network interfaces available") wrapMode: Text.WordWrap - visible: networkManager.available &&networkManager.wirelessNetworkDevices.count == 0 + visible: networkManager.available && networkManager.wirelessNetworkDevices.count == 0 } Repeater { model: networkManager.wirelessNetworkDevices - visible: networkManager.available NymeaListItemDelegate { Layout.fillWidth: true + visible: networkManager.available && networkManager.networkingEnabled iconName: { switch (model.state) { case NetworkDevice.NetworkDeviceStateUnknown: @@ -300,8 +355,9 @@ SettingsPageBase { console.warn("Unhandled enum", model.state) } text: model.interface + " (" + model.macAddress + ")" - subText: networkStateToString(model.state) + subText: networkStateToString(model.state, model.wirelessMode) onClicked: { + print("*** --", model.wirelessMode) var wirelessNetworkDevice = networkManager.wirelessNetworkDevices.getWirelessNetworkDevice(model.interface); if (wirelessNetworkDevice.state === NetworkDevice.NetworkDeviceStateDisconnected) { networkManager.refreshWifis(model.interface) @@ -319,13 +375,56 @@ SettingsPageBase { id: wirelessAccessPointsPage title: qsTr("WiFi networks") - property var wirelessNetworkDevice: null + property WirelessNetworkDevice wirelessNetworkDevice: null WirelessAccessPointsProxy { id: apProxy accessPoints: wirelessAccessPointsPage.wirelessNetworkDevice.accessPoints } + SettingsPageSectionHeader { + text: qsTr("Access Point") + } + + TextField { + id: ssidTextField + Layout.fillWidth: true + maximumLength: 32 + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + placeholderText: qsTr("SSID") + } + + PasswordTextField { + id: passwordTextField + Layout.fillWidth: true + minPasswordLength: 8 + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + requireLowerCaseLetter: false + requireUpperCaseLetter: false + requireNumber: false + requireSpecialChar: false + signup: false + } + + Button { + Layout.fillWidth: true + Layout.margins: app.margins + Layout.leftMargin: app.margins + Layout.rightMargin: app.margins + text: qsTr("Create Access Point") + enabled: ssidTextField.displayText.length > 0 && passwordTextField.isValidPassword + onClicked: { + d.pendingCallId = networkManager.startAccessPoint(wirelessAccessPointsPage.wirelessNetworkDevice.interface, ssidTextField.text, passwordTextField.password) + pageStack.pop(root); + } + } + + SettingsPageSectionHeader { + text: qsTr("Connect to wireless network") + } + Repeater { id: listView model: apProxy @@ -333,6 +432,7 @@ SettingsPageBase { Layout.fillWidth: true text: model.ssid !== "" ? model.ssid : qsTr("Hidden Network") subText: "%1 (%2)".arg(model.macAddress).arg(model.frequency < 3 ? "2.4GHz" : "5GHz") + prominentSubText: false iconName: { var ret = "../images/nm-signal-"; if (model.signalStrength > 90) { @@ -353,8 +453,6 @@ SettingsPageBase { return ret; } - progressive: false - prominentSubText: false onClicked: { print("pushing", wirelessAccessPointsPage.wirelessNetworkDevice.state) pageStack.push(authPageComponent, {wirelessNetworkDevice: wirelessAccessPointsPage.wirelessNetworkDevice, wirelessAccessPoint: apProxy.get(index)}) @@ -407,7 +505,7 @@ SettingsPageBase { text: qsTr("OK") enabled: passwordTextField.displayText.length >= 8 onClicked: { - networkManager.connectToWiFi(authPage.wirelessNetworkDevice.interface, authPage.wirelessAccessPoint.ssid, passwordTextField.text) + d.pendingCallId = networkManager.connectToWiFi(authPage.wirelessNetworkDevice.interface, authPage.wirelessAccessPoint.ssid, passwordTextField.text) pageStack.pop(root); } } @@ -423,6 +521,9 @@ SettingsPageBase { property WirelessNetworkDevice wirelessNetworkDevice: null + SettingsPageSectionHeader { + text: wirelessNetworkDevice.wirelessMode === WirelessNetworkDevice.WirelessModeAccessPoint ? qsTr("Hosting access point") : qsTr("Connected to") + } NymeaListItemDelegate { Layout.fillWidth: true @@ -430,6 +531,20 @@ SettingsPageBase { subText: currentApPage.wirelessNetworkDevice.currentAccessPoint.ssid progressive: false } + + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("IPv4 Address") + subText: currentApPage.wirelessNetworkDevice.ipv4Addresses.join(", ") + progressive: false + } + NymeaListItemDelegate { + Layout.fillWidth: true + text: qsTr("IPv6 Address") + subText: currentApPage.wirelessNetworkDevice.ipv6Addresses.join(", ") + visible: subText.length > 0 + progressive: false + } NymeaListItemDelegate { Layout.fillWidth: true text: qsTr("MAC Address") @@ -454,7 +569,7 @@ SettingsPageBase { Layout.margins: app.margins text: qsTr("Disconnect") onClicked: { - networkManager.disconnectInterface(currentApPage.wirelessNetworkDevice.interface) + d.pendingCallId = networkManager.disconnectInterface(currentApPage.wirelessNetworkDevice.interface) pageStack.pop(root); } }