more work on the cloud login
This commit is contained in:
parent
245eb9d85d
commit
d5839a5229
@ -5,32 +5,34 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrlQuery>
|
||||
#include <QJsonDocument>
|
||||
|
||||
|
||||
extern "C" {
|
||||
#include "connection/srp.h"
|
||||
}
|
||||
#include <QSettings>
|
||||
|
||||
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<QNetworkReply*>(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<QNetworkReply*>(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<AWSDevice> 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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -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<AWSDevice> 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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -2,38 +2,53 @@
|
||||
#define BASICCONFIGURATION_H
|
||||
|
||||
#include <QObject>
|
||||
#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
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
#include "nymeadiscovery.h"
|
||||
|
||||
#include "engine.h"
|
||||
#include "upnpdiscovery.h"
|
||||
#include "zeroconfdiscovery.h"
|
||||
#include "bluetoothservicediscovery.h"
|
||||
#include "awsclient.h"
|
||||
|
||||
#include <QUuid>
|
||||
#include <QBluetoothUuid>
|
||||
@ -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<AWSDevice> &devices)
|
||||
{
|
||||
foreach (const AWSDevice &d, devices) {
|
||||
DiscoveryDevice *device = m_discoveryModel->find(d.id);
|
||||
if (!device) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "awsclient.h"
|
||||
|
||||
class DiscoveryModel;
|
||||
class UpnpDiscovery;
|
||||
class ZeroconfDiscovery;
|
||||
@ -25,6 +27,9 @@ public:
|
||||
signals:
|
||||
void discoveringChanged();
|
||||
|
||||
private slots:
|
||||
void cloudDevicesFetched(const QList<AWSDevice> &devices);
|
||||
|
||||
private:
|
||||
bool m_discovering = false;
|
||||
DiscoveryModel *m_discoveryModel = nullptr;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -240,5 +240,8 @@
|
||||
<file>ui/images/configure.svg</file>
|
||||
<file>ui/images/network-wifi-symbolic.svg</file>
|
||||
<file>ui/KeyboardLoader.qml</file>
|
||||
<file>ui/images/cloud.svg</file>
|
||||
<file>ui/system/CloudSettingsPage.qml</file>
|
||||
<file>ui/connection/CloudLoginPage.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
nymea-app/ui/connection/CloudLoginPage.qml
Normal file
43
nymea-app/ui/connection/CloudLoginPage.qml
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
160
nymea-app/ui/images/cloud.svg
Normal file
160
nymea-app/ui/images/cloud.svg
Normal file
@ -0,0 +1,160 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="96"
|
||||
height="96"
|
||||
id="svg4874"
|
||||
version="1.1"
|
||||
inkscape:version="0.91+devel r"
|
||||
viewBox="0 0 96 96.000001"
|
||||
sodipodi:docname="weather-clouds-symbolic.svg">
|
||||
<defs
|
||||
id="defs4876" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4.4959994"
|
||||
inkscape:cx="11.154354"
|
||||
inkscape:cy="34.719727"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g4780"
|
||||
showgrid="false"
|
||||
showborder="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5451"
|
||||
empspacing="8" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="8,-8.0000001"
|
||||
id="guide4063" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="4,-8.0000001"
|
||||
id="guide4065" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,88.000001"
|
||||
id="guide4067" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,92.000001"
|
||||
id="guide4069" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="104,4"
|
||||
id="guide4071" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,8.0000001"
|
||||
id="guide4073" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="88,-8.0000001"
|
||||
id="guide4077" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,84.000001"
|
||||
id="guide4074" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="12,-8.0000001"
|
||||
id="guide4076" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="84,-8.0000001"
|
||||
id="guide4080" />
|
||||
<sodipodi:guide
|
||||
position="48,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4170" />
|
||||
<sodipodi:guide
|
||||
position="-8,48"
|
||||
orientation="0,1"
|
||||
id="guide4172" />
|
||||
<sodipodi:guide
|
||||
position="92,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4760" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4879">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(67.857146,-78.50504)">
|
||||
<g
|
||||
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||
id="g4845"
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="next01.png"
|
||||
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||
id="g4778"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||
id="g4780"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||
id="rect4782"
|
||||
width="96.037987"
|
||||
height="96"
|
||||
x="-438.00244"
|
||||
y="345.36221"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#808080;fill-opacity:1;stroke:none;stroke-width:4.00000048;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="M 51.539062 16.888672 C 39.655652 16.888672 29.559451 24.212821 24.738281 34.675781 L 24.416016 35.376953 L 23.646484 35.433594 C 12.678934 36.232468 3.9980469 45.714566 3.9980469 57.255859 C 3.9980469 69.316737 13.439055 79.21875 25.109375 79.21875 L 51.539062 79.21875 L 76.175781 79.21875 C 84.926381 79.21875 92 71.787763 92 62.779297 C 92 55.94799 87.899411 50.217256 82.082031 47.746094 L 81.324219 47.423828 L 81.287109 46.603516 C 80.540729 30.134022 67.596276 16.888672 51.541016 16.888672 L 51.539062 16.888672 z M 51.539062 20.888672 C 65.393253 20.888672 76.634896 32.305371 77.291016 46.783203 L 77.289062 46.779297 L 77.4375 50.117188 L 80.515625 51.427734 C 84.906955 53.293126 87.998047 57.547827 87.998047 62.779297 C 87.998047 69.694971 82.658528 75.21875 76.173828 75.21875 L 51.539062 75.21875 L 25.109375 75.21875 C 15.702915 75.21875 7.9980469 67.230513 7.9980469 57.255859 C 7.9980469 47.719033 15.103887 40.06517 23.935547 39.421875 L 23.9375 39.421875 L 27.064453 39.191406 L 28.371094 36.349609 C 32.601004 27.169791 41.300243 20.888672 51.539062 20.888672 z "
|
||||
transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
|
||||
id="path4181" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
31
nymea-app/ui/system/CloudSettingsPage.qml
Normal file
31
nymea-app/ui/system/CloudSettingsPage.qml
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user