diff --git a/libnymea-app-core/awsclient.cpp b/libnymea-app-core/awsclient.cpp index 48c50241..2e6e5a39 100644 --- a/libnymea-app-core/awsclient.cpp +++ b/libnymea-app-core/awsclient.cpp @@ -5,32 +5,34 @@ #include #include #include - - -extern "C" { -#include "connection/srp.h" -} +#include static QByteArray clientId = "8rjhfdlf9jf1suok2jcrltd6v"; AWSClient::AWSClient(QObject *parent) : QObject(parent) { m_nam = new QNetworkAccessManager(this); + + QSettings settings; + settings.beginGroup("cloud"); + m_username = settings.value("username").toString(); + m_accessToken = settings.value("accessToken").toByteArray(); + m_idToken = settings.value("idToken").toByteArray(); +} + +bool AWSClient::isLoggedIn() const +{ + return !m_username.isEmpty() && !m_accessToken.isEmpty() && !m_idToken.isEmpty(); } void AWSClient::login(const QString &username, const QString &password) { - if (m_srpUser != nullptr) { - qWarning() << "Already logged in. Cannot log in again"; - return; - } + m_username = username; - m_srpUser = srp_user_new(SRP_SHA256, SRP_NG_2048, username.toLocal8Bit(), (const unsigned char*)password.toLocal8Bit().data(), password.length(), nullptr ,nullptr); - - char *user; - unsigned char *bytes_A; - int len_A; - srp_user_start_authentication(m_srpUser, (const char**)&user, (const unsigned char**)&bytes_A, &len_A); + QSettings settings; + settings.remove("cloud"); + settings.beginGroup("cloud"); + settings.setValue("username", username); QUrl url("https://cognito-idp.eu-west-1.amazonaws.com/"); @@ -56,16 +58,9 @@ void AWSClient::login(const QString &username, const QString &password) QJsonDocument jsonDoc = QJsonDocument::fromVariant(params); QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); - - qDebug() << "Posting:\nURL:" << request.url().toString(); - qDebug() << "HEADERS:"; - foreach (const QByteArray &headerName, request.rawHeaderList()) { - qDebug() << headerName << ":" << request.rawHeader(headerName); - } - qDebug().noquote() << "Payload:" << payload; - QNetworkReply *reply = m_nam->post(request, payload); connect(reply, &QNetworkReply::finished, this, &AWSClient::initiateAuthReply); + qDebug() << "Logging in to AWS as user:" << username; } void AWSClient::initiateAuthReply() @@ -73,7 +68,11 @@ void AWSClient::initiateAuthReply() QNetworkReply* reply = static_cast(sender()); reply->deleteLater(); QByteArray data = reply->readAll(); - qDebug() << "InitiateAuth reply" << reply->error() << reply->errorString() << qUtf8Printable(data); + + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Error logging in to aws:" << reply->error() << reply->errorString() << qUtf8Printable(data); + return; + } QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); @@ -83,11 +82,18 @@ void AWSClient::initiateAuthReply() } QVariantMap authenticationResult = jsonDoc.toVariant().toMap().value("AuthenticationResult").toMap(); - QByteArray accessToken = authenticationResult.value("AccessToken").toByteArray(); - QByteArray idToken = authenticationResult.value("IdToken").toByteArray(); - qDebug() << "Have acess token:" << accessToken; - qDebug() << "have idToken:" << idToken; + m_accessToken = authenticationResult.value("AccessToken").toByteArray(); + m_idToken = authenticationResult.value("IdToken").toByteArray(); + QSettings settings; + settings.beginGroup("cloud"); + settings.setValue("accessToken", m_accessToken); + settings.setValue("idToken", m_idToken); + + qDebug() << "AWS login successful"; + emit isLoggedInChanged(); + + return; // Why should we call GetId? Ask Luca QUrl url("https://cognito-identity.eu-west-1.amazonaws.com/"); @@ -102,7 +108,7 @@ void AWSClient::initiateAuthReply() request.setRawHeader("X-Amz-Target", "AWSCognitoIdentityService.GetId"); QVariantMap logins; - logins.insert("cognito-idp.eu-west-1.amazonaws.com/eu-west-1_6eX6YjmXr", idToken); + logins.insert("cognito-idp.eu-west-1.amazonaws.com/eu-west-1_6eX6YjmXr", m_idToken); QVariantMap params; params.insert("IdentityPoolId", "eu-west-1:108a174c-5786-40f9-966a-1a0cd33d6801"); @@ -111,14 +117,6 @@ void AWSClient::initiateAuthReply() jsonDoc = QJsonDocument::fromVariant(params); QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); - - qDebug() << "Posting:\nURL:" << request.url().toString(); - qDebug() << "HEADERS:"; - foreach (const QByteArray &headerName, request.rawHeaderList()) { - qDebug() << headerName << ":" << request.rawHeader(headerName); - } - qDebug().noquote() << "Payload:" << payload; - reply = m_nam->post(request, payload); connect(reply, &QNetworkReply::finished, this, &AWSClient::getIdReply); } @@ -128,8 +126,39 @@ void AWSClient::getIdReply() QNetworkReply* reply = static_cast(sender()); reply->deleteLater(); QByteArray data = reply->readAll(); - qDebug() << "RespondToAuthChallenge reply" << reply->error() << reply->errorString() << qUtf8Printable(data); - - -// QM + qDebug() << "GetID reply" << reply->error() << reply->errorString() << qUtf8Printable(data); +} + +void AWSClient::fetchDevices() +{ + QUrl url("https://z6368zhf2m.execute-api.eu-west-1.amazonaws.com/dev/devices"); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setRawHeader("x-api-idToken", m_idToken); + + QNetworkReply *reply = m_nam->get(request); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + reply->deleteLater(); + QByteArray data = reply->readAll(); + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Error fetching cloud devices:" << reply->error() << reply->errorString() << qUtf8Printable(data); + return; + } + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse JSON from server" << error.errorString() << qUtf8Printable(data); + return; + } + QList ret; + foreach (const QVariant &entry, jsonDoc.toVariant().toMap().value("devices").toList()) { + AWSDevice d; + d.id = entry.toMap().value("deviceId").toString(); + d.name = entry.toMap().value("name").toString(); + d.online = entry.toMap().value("online").toBool(); + ret.append(d); + } + emit devicesFetched(ret); + }); + } diff --git a/libnymea-app-core/awsclient.h b/libnymea-app-core/awsclient.h index cf3f3d3e..7a5f634a 100644 --- a/libnymea-app-core/awsclient.h +++ b/libnymea-app-core/awsclient.h @@ -7,26 +7,42 @@ class QNetworkAccessManager; struct SRPUser; +class AWSDevice { +public: + QString id; + QString name; + bool online; +}; + class AWSClient : public QObject { Q_OBJECT + Q_PROPERTY(bool isLoggedIn READ isLoggedIn NOTIFY isLoggedInChanged) + public: explicit AWSClient(QObject *parent = nullptr); + bool isLoggedIn() const; + Q_INVOKABLE void login(const QString &username, const QString &password); + Q_INVOKABLE void fetchDevices(); + +signals: + void isLoggedInChanged(); + + void devicesFetched(QList devices); + private slots: void initiateAuthReply(); void getIdReply(); -private: - QByteArray createClaim(const QByteArray &secretBlock, const QByteArray &srpB, const QByteArray &salt); - QByteArray getPasswordAuthenticationKey(const QByteArray &username, const QByteArray &password); private: QNetworkAccessManager *m_nam = nullptr; - SRPUser *m_srpUser = nullptr; - void sign(QNetworkRequest &request); + QString m_username; + QByteArray m_accessToken; + QByteArray m_idToken; }; #endif // AWSCLIENT_H diff --git a/libnymea-app-core/basicconfiguration.cpp b/libnymea-app-core/basicconfiguration.cpp index ccc4da0c..b158a82e 100644 --- a/libnymea-app-core/basicconfiguration.cpp +++ b/libnymea-app-core/basicconfiguration.cpp @@ -3,10 +3,15 @@ #include "jsonrpc/jsonrpcclient.h" BasicConfiguration::BasicConfiguration(JsonRpcClient* client, QObject *parent) : - QObject(parent), + JsonHandler(parent), m_client(client) { + client->registerNotificationHandler(this, "notificationReceived"); +} +QString BasicConfiguration::nameSpace() const +{ + return "Configuration"; } bool BasicConfiguration::debugServerEnabled() const @@ -33,6 +38,18 @@ void BasicConfiguration::setServerName(const QString &serverName) m_client->sendCommand("Configuration.SetServerName", params, this, "setServerNameResponse"); } +bool BasicConfiguration::cloudEnabled() const +{ + return m_cloudEnabled; +} + +void BasicConfiguration::setCloudEnabled(bool cloudEnabled) +{ + QVariantMap params; + params.insert("enabled", cloudEnabled); + m_client->sendCommand("Configuration.SetCloudEnabled", params, this, "setCloudEnabledResponse"); +} + void BasicConfiguration::init() { m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse"); @@ -43,7 +60,17 @@ void BasicConfiguration::getConfigurationsResponse(const QVariantMap ¶ms) // qDebug() << "have config reply" << params; QVariantMap basicConfig = params.value("params").toMap().value("basicConfiguration").toMap(); m_debugServerEnabled = basicConfig.value("debugServerEnabled").toBool(); + emit debugServerEnabledChanged(); m_serverName = basicConfig.value("serverName").toString(); + emit serverNameChanged(); + QVariantMap cloudConfig = params.value("params").toMap().value("cloud").toMap(); + m_cloudEnabled = cloudConfig.value("enabled").toBool(); + emit cloudEnabledChanged(); +} + +void BasicConfiguration::getCloudConfigurationResponse(const QVariantMap ¶ms) +{ + qDebug() << "Cloud config reply" << params; } void BasicConfiguration::setDebugServerEnabledResponse(const QVariantMap ¶ms) @@ -55,3 +82,30 @@ void BasicConfiguration::setServerNameResponse(const QVariantMap ¶ms) { qDebug() << "Server name set:" << params; } + +void BasicConfiguration::setCloudEnabledResponse(const QVariantMap ¶ms) +{ + qDebug() << "Set cloud enabled:" << params; +} + +void BasicConfiguration::notificationReceived(const QVariantMap ¬ification) +{ + QString notif = notification.value("notification").toString(); + if (notif == "Configuration.BasicConfigurationChanged") { + QVariantMap params = notification.value("params").toMap().value("basicConfiguration").toMap(); + qDebug() << "notif" << params; + m_debugServerEnabled = params.value("debugServerEnabled").toBool(); + emit debugServerEnabled(); + m_serverName = params.value("serverName").toString(); + emit serverNameChanged(); + return; + } + if (notif == "Configuration.CloudConfigurationChanged") { + QVariantMap params = notification.value("params").toMap().value("cloudConfiguration").toMap(); + qDebug() << "notif" << params; + m_cloudEnabled = params.value("enabled").toBool(); + emit cloudEnabledChanged(); + return; + } + qDebug() << "Unhandled Configuration notification" << notif; +} diff --git a/libnymea-app-core/basicconfiguration.h b/libnymea-app-core/basicconfiguration.h index c0451539..64ddcc7e 100644 --- a/libnymea-app-core/basicconfiguration.h +++ b/libnymea-app-core/basicconfiguration.h @@ -2,38 +2,53 @@ #define BASICCONFIGURATION_H #include +#include "jsonrpc/jsonhandler.h" class JsonRpcClient; -class BasicConfiguration : public QObject +class BasicConfiguration : public JsonHandler { Q_OBJECT Q_PROPERTY(bool debugServerEnabled READ debugServerEnabled WRITE setDebugServerEnabled NOTIFY debugServerEnabledChanged) Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged) + + Q_PROPERTY(bool cloudEnabled READ cloudEnabled WRITE setCloudEnabled NOTIFY cloudEnabledChanged) + public: explicit BasicConfiguration(JsonRpcClient* client, QObject *parent = nullptr); + QString nameSpace() const override; + bool debugServerEnabled() const; void setDebugServerEnabled(bool debugServerEnabled); QString serverName() const; void setServerName(const QString &serverName); + bool cloudEnabled() const; + void setCloudEnabled(bool cloudEnabled); + void init(); private: Q_INVOKABLE void getConfigurationsResponse(const QVariantMap ¶ms); + Q_INVOKABLE void getCloudConfigurationResponse(const QVariantMap ¶ms); Q_INVOKABLE void setDebugServerEnabledResponse(const QVariantMap ¶ms); Q_INVOKABLE void setServerNameResponse(const QVariantMap ¶ms); + Q_INVOKABLE void setCloudEnabledResponse(const QVariantMap ¶ms); + + Q_INVOKABLE void notificationReceived(const QVariantMap ¬ification); signals: void debugServerEnabledChanged(); void serverNameChanged(); + void cloudEnabledChanged(); private: JsonRpcClient* m_client = nullptr; bool m_debugServerEnabled = false; QString m_serverName; + bool m_cloudEnabled = false; }; #endif // BASICCONFIGURATION_H diff --git a/libnymea-app-core/discovery/nymeadiscovery.cpp b/libnymea-app-core/discovery/nymeadiscovery.cpp index 3fc553c8..32a66893 100644 --- a/libnymea-app-core/discovery/nymeadiscovery.cpp +++ b/libnymea-app-core/discovery/nymeadiscovery.cpp @@ -1,8 +1,9 @@ #include "nymeadiscovery.h" - +#include "engine.h" #include "upnpdiscovery.h" #include "zeroconfdiscovery.h" #include "bluetoothservicediscovery.h" +#include "awsclient.h" #include #include @@ -17,6 +18,8 @@ NymeaDiscovery::NymeaDiscovery(QObject *parent) : QObject(parent) #ifndef Q_OS_IOS m_bluetooth = new BluetoothServiceDiscovery(m_discoveryModel, this); #endif + + connect(Engine::instance()->awsClient(), &AWSClient::devicesFetched, this, &NymeaDiscovery::cloudDevicesFetched); } bool NymeaDiscovery::discovering() const @@ -36,6 +39,9 @@ void NymeaDiscovery::setDiscovering(bool discovering) if (m_bluetooth) { m_bluetooth->discover(); } + if (Engine::instance()->awsClient()->isLoggedIn()) { + Engine::instance()->awsClient()->fetchDevices(); + } } else { m_upnp->stopDiscovery(); if (m_bluetooth) { @@ -50,3 +56,13 @@ DiscoveryModel *NymeaDiscovery::discoveryModel() const { return m_discoveryModel; } + +void NymeaDiscovery::cloudDevicesFetched(const QList &devices) +{ + foreach (const AWSDevice &d, devices) { + DiscoveryDevice *device = m_discoveryModel->find(d.id); + if (!device) { + + } + } +} diff --git a/libnymea-app-core/discovery/nymeadiscovery.h b/libnymea-app-core/discovery/nymeadiscovery.h index 1a4850e3..b138cff6 100644 --- a/libnymea-app-core/discovery/nymeadiscovery.h +++ b/libnymea-app-core/discovery/nymeadiscovery.h @@ -3,6 +3,8 @@ #include +#include "awsclient.h" + class DiscoveryModel; class UpnpDiscovery; class ZeroconfDiscovery; @@ -25,6 +27,9 @@ public: signals: void discoveringChanged(); +private slots: + void cloudDevicesFetched(const QList &devices); + private: bool m_discovering = false; DiscoveryModel *m_discoveryModel = nullptr; diff --git a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp index 7107446b..0d45b0a5 100644 --- a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp @@ -77,6 +77,13 @@ void JsonRpcClient::setNotificationsEnabled(bool enabled) sendRequest(reply->requestMap()); } +void JsonRpcClient::getCloudConnectionStatus() +{ + JsonRpcReply *reply = createReply("JSONRPC.IsCloudConnected", QVariantMap(), this, "isCloudConnectedReply"); + m_replies.insert(reply->commandId(), reply); + sendRequest(reply->requestMap()); +} + void JsonRpcClient::setNotificationsEnabledResponse(const QVariantMap ¶ms) { qDebug() << "Notifications enabled:" << params; @@ -88,8 +95,6 @@ void JsonRpcClient::setNotificationsEnabledResponse(const QVariantMap ¶ms) void JsonRpcClient::notificationReceived(const QVariantMap &data) { - qDebug() << "JsonRpcClient: Notification received" << data; - //JsonRpcClient: Notification received QMap(("id", QVariant(double, 2))("notification", QVariant(QString, "JSONRPC.PushButtonAuthFinished"))("params", QVariant(QVariantMap, QMap(("success", QVariant(bool, true))("token", QVariant(QString, "FJPaAJ8FEtrqcC+/s0s/lAcDubz0OyEtwbRsyFIWM9c="))("transactionId", QVariant(double, 2)))))) if (data.value("notification").toString() == "JSONRPC.PushButtonAuthFinished") { qDebug() << "Push button auth finished."; @@ -111,7 +116,23 @@ void JsonRpcClient::notificationReceived(const QVariantMap &data) } else { emit pushButtonAuthFailed(); } + return; } + + if (data.value("notification").toString() == "JSONRPC.CloudConnectedChanged") { + m_cloudConnected = data.value("params").toMap().value("connected").toBool(); + emit cloudConnectedChanged(); + return; + } + + qDebug() << "JsonRpcClient: Unhandled notification received" << data; +} + +void JsonRpcClient::isCloudConnectedReply(const QVariantMap &data) +{ + qDebug() << "Cloud is connected" << data; + m_cloudConnected = data.value("params").toMap().value("connected").toBool(); + emit cloudConnectedChanged(); } bool JsonRpcClient::connected() const @@ -134,6 +155,11 @@ bool JsonRpcClient::pushButtonAuthAvailable() const return m_pushButtonAuthAvailable; } +bool JsonRpcClient::cloudConnected() const +{ + return m_cloudConnected; +} + QString JsonRpcClient::serverVersion() const { return m_serverVersion; @@ -267,7 +293,7 @@ void JsonRpcClient::onInterfaceConnectedChanged(bool connected) void JsonRpcClient::dataReceived(const QByteArray &data) { - qDebug() << "JsonRpcClient: received data:" << qUtf8Printable(data); +// qDebug() << "JsonRpcClient: received data:" << qUtf8Printable(data); m_receiveBuffer.append(data); int splitIndex = m_receiveBuffer.indexOf("}\n{") + 1; @@ -334,6 +360,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data) } setNotificationsEnabled(true); + getCloudConnectionStatus(); } // check if this is a reply to a request diff --git a/libnymea-app-core/jsonrpc/jsonrpcclient.h b/libnymea-app-core/jsonrpc/jsonrpcclient.h index fab1389a..df7f8570 100644 --- a/libnymea-app-core/jsonrpc/jsonrpcclient.h +++ b/libnymea-app-core/jsonrpc/jsonrpcclient.h @@ -40,6 +40,7 @@ class JsonRpcClient : public JsonHandler Q_PROPERTY(bool initialSetupRequired READ initialSetupRequired NOTIFY initialSetupRequiredChanged) Q_PROPERTY(bool authenticationRequired READ authenticationRequired NOTIFY authenticationRequiredChanged) Q_PROPERTY(bool pushButtonAuthAvailable READ pushButtonAuthAvailable NOTIFY pushButtonAuthAvailableChanged) + Q_PROPERTY(bool cloudConnected READ cloudConnected NOTIFY cloudConnectedChanged) Q_PROPERTY(QString serverVersion READ serverVersion NOTIFY handshakeReceived) Q_PROPERTY(QString jsonRpcVersion READ jsonRpcVersion NOTIFY handshakeReceived) Q_PROPERTY(QString serverUuid READ serverUuid NOTIFY handshakeReceived) @@ -59,6 +60,7 @@ public: bool initialSetupRequired() const; bool authenticationRequired() const; bool pushButtonAuthAvailable() const; + bool cloudConnected() const; QString serverVersion() const; QString jsonRpcVersion() const; @@ -82,6 +84,7 @@ signals: void authenticationFailed(); void pushButtonAuthFailed(); void createUserFailed(const QString &error); + void cloudConnectedChanged(); void responseReceived(const int &commandId, const QVariantMap &response); @@ -102,6 +105,7 @@ private: bool m_initialSetupRequired = false; bool m_authenticationRequired = false; bool m_pushButtonAuthAvailable = false; + bool m_cloudConnected = false; int m_pendingPushButtonTransaction = -1; QString m_serverUuid; QVersionNumber m_jsonRpcVersion; @@ -110,6 +114,7 @@ private: QByteArray m_receiveBuffer; void setNotificationsEnabled(bool enabled); + void getCloudConnectionStatus(); // json handler Q_INVOKABLE void processAuthenticate(const QVariantMap &data); @@ -118,6 +123,7 @@ private: Q_INVOKABLE void setNotificationsEnabledResponse(const QVariantMap ¶ms); Q_INVOKABLE void notificationReceived(const QVariantMap &data); + Q_INVOKABLE void isCloudConnectedReply(const QVariantMap &data); void sendRequest(const QVariantMap &request); diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index 895c817f..30036a24 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -240,5 +240,8 @@ ui/images/configure.svg ui/images/network-wifi-symbolic.svg ui/KeyboardLoader.qml + ui/images/cloud.svg + ui/system/CloudSettingsPage.qml + ui/connection/CloudLoginPage.qml diff --git a/nymea-app/ui/SettingsPage.qml b/nymea-app/ui/SettingsPage.qml index 5dec62e5..5577479d 100644 --- a/nymea-app/ui/SettingsPage.qml +++ b/nymea-app/ui/SettingsPage.qml @@ -90,6 +90,13 @@ Page { } + MeaListItemDelegate { + Layout.fillWidth: true + iconName: "../images/cloud.svg" + text: qsTr("Cloud") + onClicked: pageStack.push(Qt.resolvedUrl("system/CloudSettingsPage.qml")) + } + MeaListItemDelegate { Layout.fillWidth: true iconName: "../images/plugin.svg" @@ -110,30 +117,4 @@ Page { onClicked: pageStack.push(Qt.resolvedUrl("system/AboutNymeaPage.qml")) } } - - Component { - id: styleChangedDialog - Dialog { - width: Math.min(parent.width * .8, contentLabel.implicitWidth) - x: (parent.width - width) / 2 - y: (parent.height - height) / 2 - modal: true - - title: qsTr("Style changed") - - standardButtons: Dialog.Ok - - ColumnLayout { - id: content - anchors { left: parent.left; top: parent.top; right: parent.right } - - Label { - id: contentLabel - Layout.fillWidth: true - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - text: qsTr("The application needs to be restarted for style changes to take effect.") - } - } - } - } } diff --git a/nymea-app/ui/connection/CloudLoginPage.qml b/nymea-app/ui/connection/CloudLoginPage.qml new file mode 100644 index 00000000..50a9f718 --- /dev/null +++ b/nymea-app/ui/connection/CloudLoginPage.qml @@ -0,0 +1,43 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import Nymea 1.0 +import "../components" + +Page { + id: root + header: GuhHeader { + text: qsTr("Cloud login") + onBackPressed: pageStack.pop() + } + + ColumnLayout { + anchors.fill: parent + Label { + Layout.fillWidth: true + text: "Username (e-mail)" + } + TextField { + id: usernameTextField + Layout.fillWidth: true + placeholderText: "john@dummy.com" + } + Label { + Layout.fillWidth: true + text: qsTr("Password") + } + TextField { + id: passwordTextField + Layout.fillWidth: true + } + + Button { + Layout.fillWidth: true + text: qsTr("OK") + enabled: usernameTextField.displayText.length > 0 && passwordTextField.displayText.length > 0 + onClicked: { + Engine.awsClient.login(usernameTextField.text, passwordTextField.text); + } + } + } +} diff --git a/nymea-app/ui/connection/ConnectPage.qml b/nymea-app/ui/connection/ConnectPage.qml index dc401262..106ccb5b 100644 --- a/nymea-app/ui/connection/ConnectPage.qml +++ b/nymea-app/ui/connection/ConnectPage.qml @@ -85,29 +85,13 @@ Page { header: FancyHeader { title: qsTr("Connect %1").arg(app.systemName) model: ListModel { - ListElement { iconSource: "../images/network-vpn.svg"; text: qsTr("Manual connection"); page: "ManualConnectPage.qml" } - ListElement { iconSource: "../images/bluetooth.svg"; text: qsTr("Wireless setup"); page: "BluetoothDiscoveryPage.qml"; } - ListElement { iconSource: "../images/private-browsing.svg"; text: qsTr("Demo mode"); page: "" } + ListElement { iconSource: "../images/network-vpn.svg"; text: qsTr("Manual connection"); page: "connection/ManualConnectPage.qml" } + ListElement { iconSource: "../images/bluetooth.svg"; text: qsTr("Wireless setup"); page: "connection/BluetoothDiscoveryPage.qml"; } + ListElement { iconSource: "../images/cloud.svg"; text: qsTr("Cloud login"); page: "connection/CloudLoginPage.qml" } ListElement { iconSource: "../images/stock_application.svg"; text: qsTr("App settings"); page: "AppSettingsPage.qml" } - ListElement { iconSource: "../images/stock_application.svg"; text: qsTr("Cloud login"); page: "AppSettingsPage.qml" } } onClicked: { - switch (index) { - case 0: - case 1: - case 3: - pageStack.push(model.get(index).page); - break; - case 2: - var page = pageStack.push(Qt.resolvedUrl("ConnectingPage.qml")) - page.cancel.connect(function() { - Engine.connection.disconnect() - }) - Engine.connection.connect("nymea://nymea.nymea.io:2222") - break; - case 4: - Engine.awsClient.login("michael.zanetti@guh.io", "H22*xgemmmmm"); - } + pageStack.push(model.get(index).page); } } diff --git a/nymea-app/ui/images/cloud.svg b/nymea-app/ui/images/cloud.svg new file mode 100644 index 00000000..b8342eeb --- /dev/null +++ b/nymea-app/ui/images/cloud.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/system/CloudSettingsPage.qml b/nymea-app/ui/system/CloudSettingsPage.qml new file mode 100644 index 00000000..aaf74b8b --- /dev/null +++ b/nymea-app/ui/system/CloudSettingsPage.qml @@ -0,0 +1,31 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import Nymea 1.0 +import "../components" + +Page { + id: root + header: GuhHeader { + text: qsTr("Cloud settings") + onBackPressed: pageStack.pop(); + } + + ColumnLayout { + anchors { left: parent.left; top: parent.top; right: parent.right } + + Label { + Layout.fillWidth: true + text: Engine.jsonRpcClient.cloudConnected + } + + SwitchDelegate { + Layout.fillWidth: true + text: qsTr("Cloud connection enabled") + checked: Engine.basicConfiguration.cloudEnabled + onToggled: { + Engine.basicConfiguration.cloudEnabled = checked; + } + } + } +}