more work on the cloud login
This commit is contained in:
parent
245eb9d85d
commit
d5839a5229
@ -5,32 +5,34 @@
|
|||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "connection/srp.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
static QByteArray clientId = "8rjhfdlf9jf1suok2jcrltd6v";
|
static QByteArray clientId = "8rjhfdlf9jf1suok2jcrltd6v";
|
||||||
|
|
||||||
AWSClient::AWSClient(QObject *parent) : QObject(parent)
|
AWSClient::AWSClient(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
m_nam = new QNetworkAccessManager(this);
|
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)
|
void AWSClient::login(const QString &username, const QString &password)
|
||||||
{
|
{
|
||||||
if (m_srpUser != nullptr) {
|
m_username = username;
|
||||||
qWarning() << "Already logged in. Cannot log in again";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_srpUser = srp_user_new(SRP_SHA256, SRP_NG_2048, username.toLocal8Bit(), (const unsigned char*)password.toLocal8Bit().data(), password.length(), nullptr ,nullptr);
|
QSettings settings;
|
||||||
|
settings.remove("cloud");
|
||||||
char *user;
|
settings.beginGroup("cloud");
|
||||||
unsigned char *bytes_A;
|
settings.setValue("username", username);
|
||||||
int len_A;
|
|
||||||
srp_user_start_authentication(m_srpUser, (const char**)&user, (const unsigned char**)&bytes_A, &len_A);
|
|
||||||
|
|
||||||
QUrl url("https://cognito-idp.eu-west-1.amazonaws.com/");
|
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);
|
QJsonDocument jsonDoc = QJsonDocument::fromVariant(params);
|
||||||
|
|
||||||
QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact);
|
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);
|
QNetworkReply *reply = m_nam->post(request, payload);
|
||||||
connect(reply, &QNetworkReply::finished, this, &AWSClient::initiateAuthReply);
|
connect(reply, &QNetworkReply::finished, this, &AWSClient::initiateAuthReply);
|
||||||
|
qDebug() << "Logging in to AWS as user:" << username;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AWSClient::initiateAuthReply()
|
void AWSClient::initiateAuthReply()
|
||||||
@ -73,7 +68,11 @@ void AWSClient::initiateAuthReply()
|
|||||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
QByteArray data = reply->readAll();
|
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;
|
QJsonParseError error;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
@ -83,11 +82,18 @@ void AWSClient::initiateAuthReply()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap authenticationResult = jsonDoc.toVariant().toMap().value("AuthenticationResult").toMap();
|
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;
|
m_accessToken = authenticationResult.value("AccessToken").toByteArray();
|
||||||
qDebug() << "have idToken:" << idToken;
|
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/");
|
QUrl url("https://cognito-identity.eu-west-1.amazonaws.com/");
|
||||||
|
|
||||||
@ -102,7 +108,7 @@ void AWSClient::initiateAuthReply()
|
|||||||
request.setRawHeader("X-Amz-Target", "AWSCognitoIdentityService.GetId");
|
request.setRawHeader("X-Amz-Target", "AWSCognitoIdentityService.GetId");
|
||||||
|
|
||||||
QVariantMap logins;
|
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;
|
QVariantMap params;
|
||||||
params.insert("IdentityPoolId", "eu-west-1:108a174c-5786-40f9-966a-1a0cd33d6801");
|
params.insert("IdentityPoolId", "eu-west-1:108a174c-5786-40f9-966a-1a0cd33d6801");
|
||||||
@ -111,14 +117,6 @@ void AWSClient::initiateAuthReply()
|
|||||||
jsonDoc = QJsonDocument::fromVariant(params);
|
jsonDoc = QJsonDocument::fromVariant(params);
|
||||||
QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact);
|
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);
|
reply = m_nam->post(request, payload);
|
||||||
connect(reply, &QNetworkReply::finished, this, &AWSClient::getIdReply);
|
connect(reply, &QNetworkReply::finished, this, &AWSClient::getIdReply);
|
||||||
}
|
}
|
||||||
@ -128,8 +126,39 @@ void AWSClient::getIdReply()
|
|||||||
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
QNetworkReply* reply = static_cast<QNetworkReply*>(sender());
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
QByteArray data = reply->readAll();
|
QByteArray data = reply->readAll();
|
||||||
qDebug() << "RespondToAuthChallenge reply" << reply->error() << reply->errorString() << qUtf8Printable(data);
|
qDebug() << "GetID reply" << reply->error() << reply->errorString() << qUtf8Printable(data);
|
||||||
|
}
|
||||||
|
|
||||||
// QM
|
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;
|
class QNetworkAccessManager;
|
||||||
struct SRPUser;
|
struct SRPUser;
|
||||||
|
|
||||||
|
class AWSDevice {
|
||||||
|
public:
|
||||||
|
QString id;
|
||||||
|
QString name;
|
||||||
|
bool online;
|
||||||
|
};
|
||||||
|
|
||||||
class AWSClient : public QObject
|
class AWSClient : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool isLoggedIn READ isLoggedIn NOTIFY isLoggedInChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AWSClient(QObject *parent = nullptr);
|
explicit AWSClient(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
bool isLoggedIn() const;
|
||||||
|
|
||||||
Q_INVOKABLE void login(const QString &username, const QString &password);
|
Q_INVOKABLE void login(const QString &username, const QString &password);
|
||||||
|
|
||||||
|
Q_INVOKABLE void fetchDevices();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void isLoggedInChanged();
|
||||||
|
|
||||||
|
void devicesFetched(QList<AWSDevice> devices);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void initiateAuthReply();
|
void initiateAuthReply();
|
||||||
void getIdReply();
|
void getIdReply();
|
||||||
|
|
||||||
private:
|
|
||||||
QByteArray createClaim(const QByteArray &secretBlock, const QByteArray &srpB, const QByteArray &salt);
|
|
||||||
QByteArray getPasswordAuthenticationKey(const QByteArray &username, const QByteArray &password);
|
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager *m_nam = nullptr;
|
QNetworkAccessManager *m_nam = nullptr;
|
||||||
SRPUser *m_srpUser = nullptr;
|
|
||||||
|
|
||||||
void sign(QNetworkRequest &request);
|
QString m_username;
|
||||||
|
QByteArray m_accessToken;
|
||||||
|
QByteArray m_idToken;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AWSCLIENT_H
|
#endif // AWSCLIENT_H
|
||||||
|
|||||||
@ -3,10 +3,15 @@
|
|||||||
#include "jsonrpc/jsonrpcclient.h"
|
#include "jsonrpc/jsonrpcclient.h"
|
||||||
|
|
||||||
BasicConfiguration::BasicConfiguration(JsonRpcClient* client, QObject *parent) :
|
BasicConfiguration::BasicConfiguration(JsonRpcClient* client, QObject *parent) :
|
||||||
QObject(parent),
|
JsonHandler(parent),
|
||||||
m_client(client)
|
m_client(client)
|
||||||
{
|
{
|
||||||
|
client->registerNotificationHandler(this, "notificationReceived");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BasicConfiguration::nameSpace() const
|
||||||
|
{
|
||||||
|
return "Configuration";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BasicConfiguration::debugServerEnabled() const
|
bool BasicConfiguration::debugServerEnabled() const
|
||||||
@ -33,6 +38,18 @@ void BasicConfiguration::setServerName(const QString &serverName)
|
|||||||
m_client->sendCommand("Configuration.SetServerName", params, this, "setServerNameResponse");
|
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()
|
void BasicConfiguration::init()
|
||||||
{
|
{
|
||||||
m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse");
|
m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse");
|
||||||
@ -43,7 +60,17 @@ void BasicConfiguration::getConfigurationsResponse(const QVariantMap ¶ms)
|
|||||||
// qDebug() << "have config reply" << params;
|
// qDebug() << "have config reply" << params;
|
||||||
QVariantMap basicConfig = params.value("params").toMap().value("basicConfiguration").toMap();
|
QVariantMap basicConfig = params.value("params").toMap().value("basicConfiguration").toMap();
|
||||||
m_debugServerEnabled = basicConfig.value("debugServerEnabled").toBool();
|
m_debugServerEnabled = basicConfig.value("debugServerEnabled").toBool();
|
||||||
|
emit debugServerEnabledChanged();
|
||||||
m_serverName = basicConfig.value("serverName").toString();
|
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)
|
void BasicConfiguration::setDebugServerEnabledResponse(const QVariantMap ¶ms)
|
||||||
@ -55,3 +82,30 @@ void BasicConfiguration::setServerNameResponse(const QVariantMap ¶ms)
|
|||||||
{
|
{
|
||||||
qDebug() << "Server name set:" << params;
|
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
|
#define BASICCONFIGURATION_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include "jsonrpc/jsonhandler.h"
|
||||||
|
|
||||||
class JsonRpcClient;
|
class JsonRpcClient;
|
||||||
|
|
||||||
class BasicConfiguration : public QObject
|
class BasicConfiguration : public JsonHandler
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool debugServerEnabled READ debugServerEnabled WRITE setDebugServerEnabled NOTIFY debugServerEnabledChanged)
|
Q_PROPERTY(bool debugServerEnabled READ debugServerEnabled WRITE setDebugServerEnabled NOTIFY debugServerEnabledChanged)
|
||||||
Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged)
|
Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(bool cloudEnabled READ cloudEnabled WRITE setCloudEnabled NOTIFY cloudEnabledChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BasicConfiguration(JsonRpcClient* client, QObject *parent = nullptr);
|
explicit BasicConfiguration(JsonRpcClient* client, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QString nameSpace() const override;
|
||||||
|
|
||||||
bool debugServerEnabled() const;
|
bool debugServerEnabled() const;
|
||||||
void setDebugServerEnabled(bool debugServerEnabled);
|
void setDebugServerEnabled(bool debugServerEnabled);
|
||||||
|
|
||||||
QString serverName() const;
|
QString serverName() const;
|
||||||
void setServerName(const QString &serverName);
|
void setServerName(const QString &serverName);
|
||||||
|
|
||||||
|
bool cloudEnabled() const;
|
||||||
|
void setCloudEnabled(bool cloudEnabled);
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_INVOKABLE void getConfigurationsResponse(const QVariantMap ¶ms);
|
Q_INVOKABLE void getConfigurationsResponse(const QVariantMap ¶ms);
|
||||||
|
Q_INVOKABLE void getCloudConfigurationResponse(const QVariantMap ¶ms);
|
||||||
Q_INVOKABLE void setDebugServerEnabledResponse(const QVariantMap ¶ms);
|
Q_INVOKABLE void setDebugServerEnabledResponse(const QVariantMap ¶ms);
|
||||||
Q_INVOKABLE void setServerNameResponse(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:
|
signals:
|
||||||
void debugServerEnabledChanged();
|
void debugServerEnabledChanged();
|
||||||
void serverNameChanged();
|
void serverNameChanged();
|
||||||
|
void cloudEnabledChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JsonRpcClient* m_client = nullptr;
|
JsonRpcClient* m_client = nullptr;
|
||||||
bool m_debugServerEnabled = false;
|
bool m_debugServerEnabled = false;
|
||||||
QString m_serverName;
|
QString m_serverName;
|
||||||
|
bool m_cloudEnabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BASICCONFIGURATION_H
|
#endif // BASICCONFIGURATION_H
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
#include "nymeadiscovery.h"
|
#include "nymeadiscovery.h"
|
||||||
|
#include "engine.h"
|
||||||
#include "upnpdiscovery.h"
|
#include "upnpdiscovery.h"
|
||||||
#include "zeroconfdiscovery.h"
|
#include "zeroconfdiscovery.h"
|
||||||
#include "bluetoothservicediscovery.h"
|
#include "bluetoothservicediscovery.h"
|
||||||
|
#include "awsclient.h"
|
||||||
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QBluetoothUuid>
|
#include <QBluetoothUuid>
|
||||||
@ -17,6 +18,8 @@ NymeaDiscovery::NymeaDiscovery(QObject *parent) : QObject(parent)
|
|||||||
#ifndef Q_OS_IOS
|
#ifndef Q_OS_IOS
|
||||||
m_bluetooth = new BluetoothServiceDiscovery(m_discoveryModel, this);
|
m_bluetooth = new BluetoothServiceDiscovery(m_discoveryModel, this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
connect(Engine::instance()->awsClient(), &AWSClient::devicesFetched, this, &NymeaDiscovery::cloudDevicesFetched);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NymeaDiscovery::discovering() const
|
bool NymeaDiscovery::discovering() const
|
||||||
@ -36,6 +39,9 @@ void NymeaDiscovery::setDiscovering(bool discovering)
|
|||||||
if (m_bluetooth) {
|
if (m_bluetooth) {
|
||||||
m_bluetooth->discover();
|
m_bluetooth->discover();
|
||||||
}
|
}
|
||||||
|
if (Engine::instance()->awsClient()->isLoggedIn()) {
|
||||||
|
Engine::instance()->awsClient()->fetchDevices();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
m_upnp->stopDiscovery();
|
m_upnp->stopDiscovery();
|
||||||
if (m_bluetooth) {
|
if (m_bluetooth) {
|
||||||
@ -50,3 +56,13 @@ DiscoveryModel *NymeaDiscovery::discoveryModel() const
|
|||||||
{
|
{
|
||||||
return m_discoveryModel;
|
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 <QObject>
|
||||||
|
|
||||||
|
#include "awsclient.h"
|
||||||
|
|
||||||
class DiscoveryModel;
|
class DiscoveryModel;
|
||||||
class UpnpDiscovery;
|
class UpnpDiscovery;
|
||||||
class ZeroconfDiscovery;
|
class ZeroconfDiscovery;
|
||||||
@ -25,6 +27,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void discoveringChanged();
|
void discoveringChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void cloudDevicesFetched(const QList<AWSDevice> &devices);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_discovering = false;
|
bool m_discovering = false;
|
||||||
DiscoveryModel *m_discoveryModel = nullptr;
|
DiscoveryModel *m_discoveryModel = nullptr;
|
||||||
|
|||||||
@ -77,6 +77,13 @@ void JsonRpcClient::setNotificationsEnabled(bool enabled)
|
|||||||
sendRequest(reply->requestMap());
|
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)
|
void JsonRpcClient::setNotificationsEnabledResponse(const QVariantMap ¶ms)
|
||||||
{
|
{
|
||||||
qDebug() << "Notifications enabled:" << params;
|
qDebug() << "Notifications enabled:" << params;
|
||||||
@ -88,8 +95,6 @@ void JsonRpcClient::setNotificationsEnabledResponse(const QVariantMap ¶ms)
|
|||||||
|
|
||||||
void JsonRpcClient::notificationReceived(const QVariantMap &data)
|
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))))))
|
//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") {
|
if (data.value("notification").toString() == "JSONRPC.PushButtonAuthFinished") {
|
||||||
qDebug() << "Push button auth finished.";
|
qDebug() << "Push button auth finished.";
|
||||||
@ -111,7 +116,23 @@ void JsonRpcClient::notificationReceived(const QVariantMap &data)
|
|||||||
} else {
|
} else {
|
||||||
emit pushButtonAuthFailed();
|
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
|
bool JsonRpcClient::connected() const
|
||||||
@ -134,6 +155,11 @@ bool JsonRpcClient::pushButtonAuthAvailable() const
|
|||||||
return m_pushButtonAuthAvailable;
|
return m_pushButtonAuthAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JsonRpcClient::cloudConnected() const
|
||||||
|
{
|
||||||
|
return m_cloudConnected;
|
||||||
|
}
|
||||||
|
|
||||||
QString JsonRpcClient::serverVersion() const
|
QString JsonRpcClient::serverVersion() const
|
||||||
{
|
{
|
||||||
return m_serverVersion;
|
return m_serverVersion;
|
||||||
@ -267,7 +293,7 @@ void JsonRpcClient::onInterfaceConnectedChanged(bool connected)
|
|||||||
|
|
||||||
void JsonRpcClient::dataReceived(const QByteArray &data)
|
void JsonRpcClient::dataReceived(const QByteArray &data)
|
||||||
{
|
{
|
||||||
qDebug() << "JsonRpcClient: received data:" << qUtf8Printable(data);
|
// qDebug() << "JsonRpcClient: received data:" << qUtf8Printable(data);
|
||||||
m_receiveBuffer.append(data);
|
m_receiveBuffer.append(data);
|
||||||
|
|
||||||
int splitIndex = m_receiveBuffer.indexOf("}\n{") + 1;
|
int splitIndex = m_receiveBuffer.indexOf("}\n{") + 1;
|
||||||
@ -334,6 +360,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
setNotificationsEnabled(true);
|
setNotificationsEnabled(true);
|
||||||
|
getCloudConnectionStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this is a reply to a request
|
// 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 initialSetupRequired READ initialSetupRequired NOTIFY initialSetupRequiredChanged)
|
||||||
Q_PROPERTY(bool authenticationRequired READ authenticationRequired NOTIFY authenticationRequiredChanged)
|
Q_PROPERTY(bool authenticationRequired READ authenticationRequired NOTIFY authenticationRequiredChanged)
|
||||||
Q_PROPERTY(bool pushButtonAuthAvailable READ pushButtonAuthAvailable NOTIFY pushButtonAuthAvailableChanged)
|
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 serverVersion READ serverVersion NOTIFY handshakeReceived)
|
||||||
Q_PROPERTY(QString jsonRpcVersion READ jsonRpcVersion NOTIFY handshakeReceived)
|
Q_PROPERTY(QString jsonRpcVersion READ jsonRpcVersion NOTIFY handshakeReceived)
|
||||||
Q_PROPERTY(QString serverUuid READ serverUuid NOTIFY handshakeReceived)
|
Q_PROPERTY(QString serverUuid READ serverUuid NOTIFY handshakeReceived)
|
||||||
@ -59,6 +60,7 @@ public:
|
|||||||
bool initialSetupRequired() const;
|
bool initialSetupRequired() const;
|
||||||
bool authenticationRequired() const;
|
bool authenticationRequired() const;
|
||||||
bool pushButtonAuthAvailable() const;
|
bool pushButtonAuthAvailable() const;
|
||||||
|
bool cloudConnected() const;
|
||||||
|
|
||||||
QString serverVersion() const;
|
QString serverVersion() const;
|
||||||
QString jsonRpcVersion() const;
|
QString jsonRpcVersion() const;
|
||||||
@ -82,6 +84,7 @@ signals:
|
|||||||
void authenticationFailed();
|
void authenticationFailed();
|
||||||
void pushButtonAuthFailed();
|
void pushButtonAuthFailed();
|
||||||
void createUserFailed(const QString &error);
|
void createUserFailed(const QString &error);
|
||||||
|
void cloudConnectedChanged();
|
||||||
|
|
||||||
void responseReceived(const int &commandId, const QVariantMap &response);
|
void responseReceived(const int &commandId, const QVariantMap &response);
|
||||||
|
|
||||||
@ -102,6 +105,7 @@ private:
|
|||||||
bool m_initialSetupRequired = false;
|
bool m_initialSetupRequired = false;
|
||||||
bool m_authenticationRequired = false;
|
bool m_authenticationRequired = false;
|
||||||
bool m_pushButtonAuthAvailable = false;
|
bool m_pushButtonAuthAvailable = false;
|
||||||
|
bool m_cloudConnected = false;
|
||||||
int m_pendingPushButtonTransaction = -1;
|
int m_pendingPushButtonTransaction = -1;
|
||||||
QString m_serverUuid;
|
QString m_serverUuid;
|
||||||
QVersionNumber m_jsonRpcVersion;
|
QVersionNumber m_jsonRpcVersion;
|
||||||
@ -110,6 +114,7 @@ private:
|
|||||||
QByteArray m_receiveBuffer;
|
QByteArray m_receiveBuffer;
|
||||||
|
|
||||||
void setNotificationsEnabled(bool enabled);
|
void setNotificationsEnabled(bool enabled);
|
||||||
|
void getCloudConnectionStatus();
|
||||||
|
|
||||||
// json handler
|
// json handler
|
||||||
Q_INVOKABLE void processAuthenticate(const QVariantMap &data);
|
Q_INVOKABLE void processAuthenticate(const QVariantMap &data);
|
||||||
@ -118,6 +123,7 @@ private:
|
|||||||
|
|
||||||
Q_INVOKABLE void setNotificationsEnabledResponse(const QVariantMap ¶ms);
|
Q_INVOKABLE void setNotificationsEnabledResponse(const QVariantMap ¶ms);
|
||||||
Q_INVOKABLE void notificationReceived(const QVariantMap &data);
|
Q_INVOKABLE void notificationReceived(const QVariantMap &data);
|
||||||
|
Q_INVOKABLE void isCloudConnectedReply(const QVariantMap &data);
|
||||||
|
|
||||||
void sendRequest(const QVariantMap &request);
|
void sendRequest(const QVariantMap &request);
|
||||||
|
|
||||||
|
|||||||
@ -240,5 +240,8 @@
|
|||||||
<file>ui/images/configure.svg</file>
|
<file>ui/images/configure.svg</file>
|
||||||
<file>ui/images/network-wifi-symbolic.svg</file>
|
<file>ui/images/network-wifi-symbolic.svg</file>
|
||||||
<file>ui/KeyboardLoader.qml</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>
|
</qresource>
|
||||||
</RCC>
|
</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 {
|
MeaListItemDelegate {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
iconName: "../images/plugin.svg"
|
iconName: "../images/plugin.svg"
|
||||||
@ -110,30 +117,4 @@ Page {
|
|||||||
onClicked: pageStack.push(Qt.resolvedUrl("system/AboutNymeaPage.qml"))
|
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 {
|
header: FancyHeader {
|
||||||
title: qsTr("Connect %1").arg(app.systemName)
|
title: qsTr("Connect %1").arg(app.systemName)
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement { iconSource: "../images/network-vpn.svg"; text: qsTr("Manual connection"); page: "ManualConnectPage.qml" }
|
ListElement { iconSource: "../images/network-vpn.svg"; text: qsTr("Manual connection"); page: "connection/ManualConnectPage.qml" }
|
||||||
ListElement { iconSource: "../images/bluetooth.svg"; text: qsTr("Wireless setup"); page: "BluetoothDiscoveryPage.qml"; }
|
ListElement { iconSource: "../images/bluetooth.svg"; text: qsTr("Wireless setup"); page: "connection/BluetoothDiscoveryPage.qml"; }
|
||||||
ListElement { iconSource: "../images/private-browsing.svg"; text: qsTr("Demo mode"); page: "" }
|
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("App settings"); page: "AppSettingsPage.qml" }
|
||||||
ListElement { iconSource: "../images/stock_application.svg"; text: qsTr("Cloud login"); page: "AppSettingsPage.qml" }
|
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
switch (index) {
|
pageStack.push(model.get(index).page);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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