Adjust main menu to fit better with new connection setup
This commit is contained in:
parent
fe0f8fee00
commit
5456384711
@ -142,7 +142,14 @@ NymeaConnection::ConnectionStatus JsonRpcClient::connectionStatus() const
|
||||
|
||||
void JsonRpcClient::connectToHost(NymeaHost *host, Connection *connection)
|
||||
{
|
||||
if (m_connection->currentHost()) {
|
||||
disconnect(m_connection->currentHost(), &NymeaHost::nameChanged, this, &JsonRpcClient::serverNameChanged);
|
||||
}
|
||||
|
||||
m_connection->connectToHost(host, connection);
|
||||
|
||||
connect(host, &NymeaHost::nameChanged, this, &JsonRpcClient::serverNameChanged);
|
||||
emit serverNameChanged();
|
||||
}
|
||||
|
||||
void JsonRpcClient::disconnectFromHost()
|
||||
@ -339,6 +346,11 @@ QString JsonRpcClient::serverUuid() const
|
||||
return m_serverUuid;
|
||||
}
|
||||
|
||||
QString JsonRpcClient::serverName() const
|
||||
{
|
||||
return m_connection->currentHost() ? m_connection->currentHost()->name() : "";
|
||||
}
|
||||
|
||||
QString JsonRpcClient::serverQtVersion()
|
||||
{
|
||||
if (!m_serverQtVersion.isEmpty()) {
|
||||
|
||||
@ -58,6 +58,7 @@ class JsonRpcClient : public QObject
|
||||
Q_PROPERTY(QString serverVersion READ serverVersion NOTIFY handshakeReceived)
|
||||
Q_PROPERTY(QString jsonRpcVersion READ jsonRpcVersion NOTIFY handshakeReceived)
|
||||
Q_PROPERTY(QString serverUuid READ serverUuid NOTIFY handshakeReceived)
|
||||
Q_PROPERTY(QString serverName READ serverName NOTIFY serverNameChanged)
|
||||
Q_PROPERTY(QString serverQtVersion READ serverQtVersion NOTIFY serverQtVersionChanged)
|
||||
Q_PROPERTY(QString serverQtBuildVersion READ serverQtBuildVersion NOTIFY serverQtVersionChanged)
|
||||
Q_PROPERTY(QVariantMap certificateIssuerInfo READ certificateIssuerInfo NOTIFY currentConnectionChanged)
|
||||
@ -97,6 +98,7 @@ public:
|
||||
QString serverVersion() const;
|
||||
QString jsonRpcVersion() const;
|
||||
QString serverUuid() const;
|
||||
QString serverName() const;
|
||||
QString serverQtVersion();
|
||||
QString serverQtBuildVersion();
|
||||
QVariantMap experiences() const;
|
||||
@ -137,6 +139,7 @@ signals:
|
||||
void createUserFailed(const QString &error);
|
||||
void cloudConnectionStateChanged();
|
||||
void serverQtVersionChanged();
|
||||
void serverNameChanged();
|
||||
|
||||
void responseReceived(const int &commandId, const QVariantMap &response);
|
||||
|
||||
|
||||
263
nymea-app/configuredhostsmodel.cpp
Normal file
263
nymea-app/configuredhostsmodel.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
#include "configuredhostsmodel.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcApplication)
|
||||
|
||||
ConfiguredHostsModel::ConfiguredHostsModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("ConfiguredHosts");
|
||||
foreach (const QString &childGroup, settings.childGroups()) {
|
||||
settings.beginGroup(childGroup);
|
||||
QUuid uuid = settings.value("uuid").toUuid();
|
||||
QString cachedName = settings.value("cachedName").toString();
|
||||
ConfiguredHost *host = new ConfiguredHost(uuid, this);
|
||||
host->setName(cachedName);
|
||||
addHost(host);
|
||||
settings.endGroup();
|
||||
m_currentIndex = settings.value("currentIndex", 0).toInt();
|
||||
}
|
||||
settings.endGroup();
|
||||
|
||||
// If there aren't any in the config, try migrating settings from old tab model
|
||||
if (m_list.isEmpty() && settings.contains("tabCount")) {
|
||||
qCInfo(dcApplication()) << "Migrating tab settings to mainmenumodel";
|
||||
int tabCount = settings.value("tabCount", 0).toInt();
|
||||
qCDebug(dcApplication()) << "Tab count:" << tabCount;
|
||||
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
settings.beginGroup(QString("tabSettings%1").arg(i));
|
||||
QUuid uuid = settings.value("lastConnectedHost").toUuid();
|
||||
ConfiguredHost *host = new ConfiguredHost(uuid, this);
|
||||
addHost(host);
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
settings.remove("tabCount");
|
||||
}
|
||||
|
||||
// There must be always 1 at least
|
||||
if (m_list.isEmpty()) {
|
||||
createHost();
|
||||
}
|
||||
}
|
||||
|
||||
int ConfiguredHostsModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_list.count();
|
||||
}
|
||||
|
||||
QVariant ConfiguredHostsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case RoleUuid:
|
||||
return m_list.at(index.row())->uuid();
|
||||
case RoleName:
|
||||
if (!m_list.at(index.row())->name().isEmpty()) {
|
||||
return m_list.at(index.row())->name();
|
||||
}
|
||||
return m_list.at(index.row())->uuid();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ConfiguredHostsModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles.insert(RoleUuid, "uuid");
|
||||
roles.insert(RoleName, "name");
|
||||
return roles;
|
||||
}
|
||||
|
||||
ConfiguredHost *ConfiguredHostsModel::get(int index) const
|
||||
{
|
||||
if (index < 0 || index >= m_list.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_list.at(index);
|
||||
}
|
||||
|
||||
int ConfiguredHostsModel::currentIndex() const
|
||||
{
|
||||
return m_currentIndex;
|
||||
}
|
||||
|
||||
void ConfiguredHostsModel::setCurrentIndex(int currentIndex)
|
||||
{
|
||||
if (m_currentIndex != currentIndex) {
|
||||
m_currentIndex = currentIndex;
|
||||
emit currentIndexChanged();
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("ConfiguredHosts");
|
||||
settings.setValue("currentIndex", currentIndex);
|
||||
settings.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
ConfiguredHost *ConfiguredHostsModel::createHost()
|
||||
{
|
||||
ConfiguredHost *host = new ConfiguredHost();
|
||||
addHost(host);
|
||||
return host;
|
||||
}
|
||||
|
||||
void ConfiguredHostsModel::removeHost(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_list.count()) {
|
||||
qCWarning(dcApplication()) << "Cannot remove connection at index" << index;
|
||||
return;
|
||||
}
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_list.takeAt(index)->deleteLater();
|
||||
saveToDisk();
|
||||
endRemoveRows();
|
||||
emit countChanged();
|
||||
|
||||
if (m_list.isEmpty()) {
|
||||
createHost();
|
||||
}
|
||||
}
|
||||
|
||||
int ConfiguredHostsModel::indexOf(ConfiguredHost *host) const
|
||||
{
|
||||
return m_list.indexOf(host);
|
||||
}
|
||||
|
||||
void ConfiguredHostsModel::addHost(ConfiguredHost *host)
|
||||
{
|
||||
host->setParent(this);
|
||||
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
|
||||
connect(host->engine()->jsonRpcClient(), &JsonRpcClient::currentHostChanged, this, [=]{
|
||||
if (host->engine()->jsonRpcClient()->currentHost()) {
|
||||
host->setUuid(host->engine()->jsonRpcClient()->currentHost()->uuid());
|
||||
} else {
|
||||
host->setUuid(QUuid());
|
||||
host->setName(QString());
|
||||
}
|
||||
saveToDisk();
|
||||
});
|
||||
connect(host->engine()->jsonRpcClient(), &JsonRpcClient::serverNameChanged, this, [=]{
|
||||
host->setName(host->engine()->jsonRpcClient()->serverName());
|
||||
saveToDisk();
|
||||
});
|
||||
connect(host, &ConfiguredHost::nameChanged, this, [=](){
|
||||
QModelIndex idx = index(m_list.indexOf(host));
|
||||
emit dataChanged(idx, idx, {RoleName});
|
||||
});
|
||||
m_list.append(host);
|
||||
endInsertRows();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void ConfiguredHostsModel::saveToDisk()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("ConfiguredHosts");
|
||||
settings.remove("");
|
||||
for (int i = 0; i < m_list.count(); i++) {
|
||||
settings.beginGroup(QString::number(i));
|
||||
settings.setValue("uuid", m_list.at(i)->uuid());
|
||||
settings.setValue("cachedName", m_list.at(i)->name());
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
ConfiguredHost::ConfiguredHost(const QUuid &uuid, QObject *parent):
|
||||
QObject(parent),
|
||||
m_uuid(uuid),
|
||||
m_engine(new Engine(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QUuid ConfiguredHost::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void ConfiguredHost::setUuid(const QUuid &uuid)
|
||||
{
|
||||
if (m_uuid != uuid) {
|
||||
m_uuid = uuid;
|
||||
emit uuidChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Engine *ConfiguredHost::engine() const
|
||||
{
|
||||
return m_engine;
|
||||
}
|
||||
|
||||
QString ConfiguredHost::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void ConfiguredHost::setName(const QString &name)
|
||||
{
|
||||
if (m_name != name) {
|
||||
m_name = name;
|
||||
emit nameChanged();
|
||||
}
|
||||
}
|
||||
|
||||
ConfiguredHostsProxyModel::ConfiguredHostsProxyModel(QObject *parent):
|
||||
QSortFilterProxyModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ConfiguredHostsModel *ConfiguredHostsProxyModel::model() const
|
||||
{
|
||||
return m_model;
|
||||
}
|
||||
|
||||
void ConfiguredHostsProxyModel::setModel(ConfiguredHostsModel *model)
|
||||
{
|
||||
if (m_model != model) {
|
||||
m_model = model;
|
||||
emit modelChanged();
|
||||
|
||||
setSourceModel(model);
|
||||
sort(0);
|
||||
}
|
||||
}
|
||||
|
||||
QUuid ConfiguredHostsProxyModel::currentHost() const
|
||||
{
|
||||
return m_currentHost;
|
||||
}
|
||||
|
||||
void ConfiguredHostsProxyModel::setCurrentHost(const QUuid ¤tHost)
|
||||
{
|
||||
if (m_currentHost != currentHost) {
|
||||
m_currentHost = currentHost;
|
||||
emit currentHostChanged();
|
||||
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
ConfiguredHost *ConfiguredHostsProxyModel::get(int index) const
|
||||
{
|
||||
return m_model->get(mapToSource(this->index(index, 0)).row());
|
||||
}
|
||||
|
||||
bool ConfiguredHostsProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
ConfiguredHost *left = m_model->get(source_left.row());
|
||||
ConfiguredHost *right = m_model->get(source_right.row());
|
||||
|
||||
if (left->uuid() == m_currentHost) {
|
||||
return true;
|
||||
}
|
||||
if (right->uuid() == m_currentHost) {
|
||||
return false;
|
||||
}
|
||||
return source_left.row() < source_right.row();
|
||||
}
|
||||
107
nymea-app/configuredhostsmodel.h
Normal file
107
nymea-app/configuredhostsmodel.h
Normal file
@ -0,0 +1,107 @@
|
||||
#ifndef CONFIGUREDHOSTSMODEL_H
|
||||
#define CONFIGUREDHOSTSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QUuid>
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
class ConfiguredHost: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUuid uuid READ uuid WRITE setUuid NOTIFY uuidChanged)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(Engine* engine READ engine CONSTANT)
|
||||
|
||||
public:
|
||||
ConfiguredHost(const QUuid &uuid = QUuid(), QObject *parent = nullptr);
|
||||
|
||||
QUuid uuid() const;
|
||||
void setUuid(const QUuid &uuid);
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
Engine* engine() const;
|
||||
|
||||
signals:
|
||||
void uuidChanged();
|
||||
void nameChanged();
|
||||
|
||||
private:
|
||||
QUuid m_uuid;
|
||||
Engine *m_engine = nullptr;
|
||||
QString m_name;
|
||||
};
|
||||
|
||||
class ConfiguredHostsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
||||
public:
|
||||
enum Roles {
|
||||
RoleUuid,
|
||||
RoleEngine,
|
||||
RoleName,
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
explicit ConfiguredHostsModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
int currentIndex() const;
|
||||
void setCurrentIndex(int currentIndex);
|
||||
|
||||
Q_INVOKABLE int indexOf(ConfiguredHost *host) const;
|
||||
Q_INVOKABLE ConfiguredHost* get(int index) const;
|
||||
Q_INVOKABLE ConfiguredHost* createHost();
|
||||
Q_INVOKABLE void removeHost(int index);
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
void currentIndexChanged();
|
||||
|
||||
private:
|
||||
void addHost(ConfiguredHost *host);
|
||||
|
||||
void saveToDisk();
|
||||
|
||||
private:
|
||||
QList<ConfiguredHost*> m_list;
|
||||
int m_currentIndex = 0;
|
||||
};
|
||||
|
||||
class ConfiguredHostsProxyModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ConfiguredHostsModel* model READ model WRITE setModel NOTIFY modelChanged)
|
||||
|
||||
Q_PROPERTY(QUuid currentHost READ currentHost WRITE setCurrentHost NOTIFY currentHostChanged)
|
||||
public:
|
||||
ConfiguredHostsProxyModel(QObject *parent = nullptr);
|
||||
|
||||
ConfiguredHostsModel* model() const;
|
||||
void setModel(ConfiguredHostsModel *model);
|
||||
|
||||
QUuid currentHost() const;
|
||||
void setCurrentHost(const QUuid ¤tHost);
|
||||
|
||||
Q_INVOKABLE ConfiguredHost* get(int index) const;
|
||||
|
||||
signals:
|
||||
void modelChanged();
|
||||
void currentHostChanged();
|
||||
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
|
||||
private:
|
||||
ConfiguredHostsModel *m_model = nullptr;
|
||||
QUuid m_currentHost;
|
||||
};
|
||||
|
||||
#endif // CONFIGUREDHOSTSMODEL_H
|
||||
@ -49,6 +49,7 @@
|
||||
#include "dashboard/dashboardmodel.h"
|
||||
#include "dashboard/dashboarditem.h"
|
||||
#include "mouseobserver.h"
|
||||
#include "configuredhostsmodel.h"
|
||||
#include "../config.h"
|
||||
|
||||
#include "logging.h"
|
||||
@ -168,6 +169,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
qmlRegisterType<MouseObserver>("Nymea", 1, 0, "MouseObserver");
|
||||
|
||||
qmlRegisterType<ConfiguredHostsModel>("Nymea", 1, 0, "ConfiguredHostsModel");
|
||||
qmlRegisterType<ConfiguredHostsProxyModel>("Nymea", 1, 0, "ConfiguredHostsProxyModel");
|
||||
qmlRegisterUncreatableType<ConfiguredHost>("Nymea", 1, 0, "ConfiguredHost", "Get them from ConfiguredHostsModel");
|
||||
|
||||
#ifdef OVERLAY_QMLTYPES
|
||||
registerOverlayTypes("Nymea", 1, 0);
|
||||
#endif
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
#include "mainmenumodel.h"
|
||||
|
||||
MainMenuModel::MainMenuModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int MainMenuModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_list.count();
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
#ifndef MAINMENUMODEL_H
|
||||
#define MAINMENUMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class MainMenuItem: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
};
|
||||
|
||||
class MainMenuModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainMenuModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
private:
|
||||
QList<MainMenuItem*> m_list;
|
||||
};
|
||||
|
||||
#endif // MAINMENUMODEL_H
|
||||
@ -19,9 +19,9 @@ PRE_TARGETDEPS += ../libnymea-app
|
||||
linux:!android:PRE_TARGETDEPS += $$top_builddir/libnymea-app/libnymea-app.a
|
||||
|
||||
HEADERS += \
|
||||
configuredhostsmodel.h \
|
||||
dashboard/dashboarditem.h \
|
||||
dashboard/dashboardmodel.h \
|
||||
mainmenumodel.h \
|
||||
mouseobserver.h \
|
||||
nfchelper.h \
|
||||
nfcthingactionwriter.h \
|
||||
@ -34,9 +34,9 @@ HEADERS += \
|
||||
ruletemplates/messages.h
|
||||
|
||||
SOURCES += main.cpp \
|
||||
configuredhostsmodel.cpp \
|
||||
dashboard/dashboarditem.cpp \
|
||||
dashboard/dashboardmodel.cpp \
|
||||
mainmenumodel.cpp \
|
||||
mouseobserver.cpp \
|
||||
nfchelper.cpp \
|
||||
nfcthingactionwriter.cpp \
|
||||
|
||||
@ -7,7 +7,8 @@ import Nymea 1.0
|
||||
Drawer {
|
||||
id: root
|
||||
|
||||
property Engine currentEngine: null
|
||||
property ConfiguredHostsModel configuredHosts: null
|
||||
readonly property Engine currentEngine: configuredHosts.get(configuredHosts.currentIndex).engine
|
||||
|
||||
signal openThingSettings();
|
||||
signal openMagicSettings();
|
||||
@ -17,12 +18,12 @@ Drawer {
|
||||
|
||||
signal startWirelessSetup();
|
||||
signal startManualConnection();
|
||||
signal startDemoMode();
|
||||
|
||||
background: Rectangle {
|
||||
color: Style.backgroundColor
|
||||
}
|
||||
|
||||
onClosed: topSectionLayout.configureConnections = false;
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
@ -30,38 +31,88 @@ Drawer {
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: topSectionLayout.implicitHeight + app.margins * 2
|
||||
Layout.preferredHeight: topSectionLayout.implicitHeight
|
||||
color: Qt.tint(Style.backgroundColor, Qt.rgba(Style.foregroundColor.r, Style.foregroundColor.g, Style.foregroundColor.b, 0.05))
|
||||
|
||||
ColumnLayout {
|
||||
id: topSectionLayout
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right; margins: app.margins }
|
||||
spacing: app.margins
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
spacing: 0
|
||||
|
||||
Image {
|
||||
Layout.preferredHeight: Style.hugeIconSize
|
||||
sourceSize.height: Style.hugeIconSize
|
||||
source: "qrc:/styles/%1/logo-wide.svg".arg(styleController.currentStyle)
|
||||
}
|
||||
property bool configureConnections: false
|
||||
|
||||
RowLayout {
|
||||
visible: root.currentEngine && root.currentEngine.jsonRpcClient.currentHost
|
||||
ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: root.currentEngine && root.currentEngine.jsonRpcClient.currentHost ? root.currentEngine.jsonRpcClient.currentHost.name : Configuration.systemName
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: root.currentEngine.jsonRpcClient.currentConnection ? root.currentEngine.jsonRpcClient.currentConnection.url : ""
|
||||
font.pixelSize: app.extraSmallFont
|
||||
enabled: false
|
||||
}
|
||||
Layout.margins: Style.margins
|
||||
Image {
|
||||
Layout.preferredHeight: Style.hugeIconSize
|
||||
sourceSize.height: Style.hugeIconSize
|
||||
Layout.fillWidth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
horizontalAlignment: Image.AlignLeft
|
||||
source: "qrc:/styles/%1/logo-wide.svg".arg(styleController.currentStyle)
|
||||
}
|
||||
ProgressButton {
|
||||
imageSource: "/ui/images/configure.svg"
|
||||
longpressEnabled: false
|
||||
imageSource: "../images/close.svg"
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
color: topSectionLayout.configureConnections ? Style.accentColor : Style.iconColor
|
||||
onClicked: {
|
||||
root.currentEngine.jsonRpcClient.disconnectFromHost();
|
||||
topSectionLayout.configureConnections = !topSectionLayout.configureConnections
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Repeater {
|
||||
model: root.configuredHosts
|
||||
delegate: NymeaItemDelegate {
|
||||
|
||||
readonly property ConfiguredHost configuredHost: root.configuredHosts.get(index)
|
||||
|
||||
Layout.fillWidth: true
|
||||
text: model.name.length > 0 ? model.name : qsTr("New connection")
|
||||
subText: configuredHost.engine.jsonRpcClient.currentConnection ? configuredHost.engine.jsonRpcClient.currentConnection.url : ""
|
||||
prominentSubText: false
|
||||
progressive: false
|
||||
additionalItem: RowLayout {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Rectangle {
|
||||
height: Style.smallIconSize
|
||||
width: height
|
||||
radius: height / 2
|
||||
color: Style.accentColor
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
visible: index === configuredHostsModel.currentIndex && !topSectionLayout.configureConnections
|
||||
}
|
||||
ProgressButton {
|
||||
imageSource: "/ui/images/close.svg"
|
||||
visible: topSectionLayout.configureConnections
|
||||
longpressEnabled: false
|
||||
onClicked: {
|
||||
configuredHostsModel.removeHost(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
configuredHostsModel.currentIndex = index
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: topSectionLayout.configureConnections ? childrenRect.height : 0
|
||||
Behavior on Layout.preferredHeight { NumberAnimation { duration: Style.animationDuration; easing.type: Easing.InOutQuad }}
|
||||
clip: true
|
||||
NymeaItemDelegate {
|
||||
width: parent.width
|
||||
text: qsTr("Set up another...")
|
||||
iconName: "add"
|
||||
progressive: false
|
||||
onClicked: {
|
||||
var host = configuredHostsModel.createHost()
|
||||
configuredHostsModel.currentIndex = configuredHosts.indexOf(host)
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
@ -83,40 +134,6 @@ Drawer {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
NymeaItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Wireless setup")
|
||||
iconName: "../images/connections/bluetooth.svg"
|
||||
progressive: false
|
||||
visible: root.currentEngine && root.currentEngine.jsonRpcClient.currentHost == null
|
||||
onClicked: {
|
||||
root.startWirelessSetup();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
NymeaItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Manual connection")
|
||||
iconName: "../images/connections/network-vpn.svg"
|
||||
progressive: false
|
||||
visible: root.currentEngine && root.currentEngine.jsonRpcClient.currentHost == null
|
||||
onClicked: {
|
||||
root.startManualConnection();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
NymeaItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Demo mode")
|
||||
iconName: "../images/private-browsing.svg"
|
||||
progressive: false
|
||||
visible: root.currentEngine && root.currentEngine.jsonRpcClient.currentHost == null
|
||||
onClicked: {
|
||||
root.startDemoMode();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
NymeaItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Configure things")
|
||||
|
||||
@ -81,7 +81,6 @@ ApplicationWindow {
|
||||
property bool showHiddenOptions: false
|
||||
property string cloudEnvironment: "Community"
|
||||
property bool showConnectionTabs: false
|
||||
property int tabCount: 1
|
||||
// FIXME: This shouldn't be needed... we should probably only use the system locale and not even provide a setting
|
||||
// However, the topic is more complex, and in the long run we'd probably want to allow the user selecting the
|
||||
// desired unit for particular interfaces/things/views. See https://github.com/nymea/nymea/issues/386
|
||||
@ -108,13 +107,17 @@ ApplicationWindow {
|
||||
value: "cloudEnvironment" in app ? app.cloudEnvironment : settings.cloudEnvironment
|
||||
}
|
||||
|
||||
ConfiguredHostsModel {
|
||||
id: configuredHostsModel
|
||||
}
|
||||
|
||||
property alias mainMenu: m
|
||||
MainMenu {
|
||||
id: m
|
||||
height: app.height
|
||||
width: Math.min(300, app.width)
|
||||
// z: 1000
|
||||
currentEngine: rootItem.currentEngine
|
||||
configuredHosts: configuredHostsModel
|
||||
onOpenThingSettings: rootItem.openThingSettings();
|
||||
onOpenMagicSettings: rootItem.openMagicSettings();
|
||||
onOpenAppSettings: rootItem.openAppSettings();
|
||||
@ -122,7 +125,6 @@ ApplicationWindow {
|
||||
onConfigureMainView: rootItem.configureMainView();
|
||||
onStartManualConnection: rootItem.startManualConnection();
|
||||
onStartWirelessSetup: rootItem.startWirelessSetup();
|
||||
onStartDemoMode: rootItem.startDemoMode();
|
||||
}
|
||||
|
||||
RootItem {
|
||||
|
||||
@ -40,8 +40,6 @@ import "connection"
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property Engine currentEngine: swipeView.currentItem ? swipeView.currentItem.engine : null
|
||||
|
||||
function handleAndroidBackButton() {
|
||||
return swipeView.currentItem.handleAndroidBackButton()
|
||||
}
|
||||
@ -77,53 +75,6 @@ Item {
|
||||
swipeView.currentItem.pageStack.currentItem.configureViews()
|
||||
}
|
||||
|
||||
function startManualConnection() {
|
||||
d.pushSettingsPage("connection/ManualConnectPage.qml")
|
||||
}
|
||||
function startWirelessSetup() {
|
||||
d.pushSettingsPage("connection/wifisetup/BluetoothDiscoveryPage.qml");
|
||||
}
|
||||
function startDemoMode() {
|
||||
var host = nymeaDiscovery.nymeaHosts.createWanHost("Demo server", "nymea://nymea.nymea.io:2222")
|
||||
root.currentEngine.jsonRpcClient.connectToHost(host)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: tabModel
|
||||
|
||||
Component.onCompleted: {
|
||||
for (var i = 0; i < settings.tabCount; i++) {
|
||||
tabModel.append({})
|
||||
}
|
||||
}
|
||||
|
||||
function addTab() {
|
||||
tabModel.append({})
|
||||
settings.tabCount++;
|
||||
swipeView.currentIndex = settings.tabCount - 1
|
||||
tabbar.currentIndex = swipeView.currentIndex
|
||||
}
|
||||
function removeTab(index) {
|
||||
if (swipeView.currentIndex === index) {
|
||||
if (swipeView.currentIndex > 0) {
|
||||
swipeView.currentIndex--;
|
||||
} else {
|
||||
swipeView.currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
remove(index);
|
||||
settings.tabCount--;
|
||||
tabbar.currentIndex = swipeView.currentIndex
|
||||
orphanedSettings.lastConnectedHost = ""
|
||||
}
|
||||
}
|
||||
Settings {
|
||||
id: orphanedSettings
|
||||
category: "tabSettings" + tabModel.count
|
||||
property string lastConnectedHost
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
@ -133,29 +84,26 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
interactive: false
|
||||
currentIndex: configuredHostsModel.currentIndex
|
||||
|
||||
Repeater {
|
||||
id: mainRepeater
|
||||
model: tabModel
|
||||
model: configuredHostsModel
|
||||
|
||||
delegate: Item {
|
||||
height: swipeView.height
|
||||
width: swipeView.width
|
||||
clip: true
|
||||
|
||||
readonly property ConfiguredHost configuredHost: configuredHostsModel.get(index)
|
||||
|
||||
property var tabSettings: Settings {
|
||||
category: "tabSettings" + index
|
||||
property string lastConnectedHost
|
||||
property int currentMainViewIndex: -1
|
||||
}
|
||||
|
||||
Engine {
|
||||
id: engineObject
|
||||
}
|
||||
readonly property Engine engine: engineObject
|
||||
readonly property Engine _engine: engineObject // In case a child cannot use "engine"
|
||||
property int connectionTabIndex: index
|
||||
// onConnectionTabIndexChanged: tabSettings.lastConnectedHost = engine.jsonRpcClient.url
|
||||
readonly property Engine engine: configuredHost.engine
|
||||
readonly property Engine _engine: configuredHost.engine // In case a child cannot use "engine"
|
||||
|
||||
Binding {
|
||||
target: nymeaDiscovery
|
||||
@ -173,9 +121,9 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
setupPushNotifications();
|
||||
if (tabSettings.lastConnectedHost.length > 0) {
|
||||
print("Last connected host was", tabSettings.lastConnectedHost)
|
||||
var cachedHost = nymeaDiscovery.nymeaHosts.find(tabSettings.lastConnectedHost);
|
||||
if (configuredHost.uuid.toString() !== "{00000000-0000-0000-0000-000000000000}") {
|
||||
print("Configured host id is", configuredHost.uuid)
|
||||
var cachedHost = nymeaDiscovery.nymeaHosts.find(configuredHost.uuid);
|
||||
if (cachedHost) {
|
||||
engine.jsonRpcClient.connectToHost(cachedHost)
|
||||
return;
|
||||
@ -201,7 +149,6 @@ Item {
|
||||
pageStack.clear()
|
||||
if (!engine.jsonRpcClient.currentHost) {
|
||||
print("pushing ConnectPage")
|
||||
tabSettings.lastConnectedHost = ""
|
||||
pageStack.push(Configuration.connectionWizard)
|
||||
PlatformHelper.hideSplashScreen();
|
||||
return;
|
||||
@ -213,7 +160,7 @@ Item {
|
||||
print("opening push button auth")
|
||||
var page = pageStack.push(Qt.resolvedUrl("PushButtonAuthPage.qml"))
|
||||
page.backPressed.connect(function() {
|
||||
tabSettings.lastConnectedHost = "";
|
||||
// tabSettings.lastConnectedHost = "";
|
||||
engine.jsonRpcClient.disconnectFromHost();
|
||||
init();
|
||||
})
|
||||
@ -222,7 +169,7 @@ Item {
|
||||
if (engine.jsonRpcClient.initialSetupRequired) {
|
||||
var page = pageStack.push(Qt.resolvedUrl("connection/SetupWizard.qml"));
|
||||
page.backPressed.connect(function() {
|
||||
tabSettings.lastConnectedHost = "";
|
||||
// tabSettings.lastConnectedHost = "";
|
||||
engine.jsonRpcClient.disconnectFromHost()
|
||||
init();
|
||||
})
|
||||
@ -231,7 +178,7 @@ Item {
|
||||
|
||||
var page = pageStack.push(Qt.resolvedUrl("connection/LoginPage.qml"));
|
||||
page.backPressed.connect(function() {
|
||||
tabSettings.lastConnectedHost = "";
|
||||
// tabSettings.lastConnectedHost = "";
|
||||
engine.jsonRpcClient.disconnectFromHost()
|
||||
init();
|
||||
})
|
||||
@ -240,6 +187,7 @@ Item {
|
||||
}
|
||||
|
||||
if (engine.jsonRpcClient.connected) {
|
||||
print("Connected to", engine.jsonRpcClient.currentHost.uuid, engine.jsonRpcClient.currentHost.name)
|
||||
pageStack.push(Qt.resolvedUrl("MainPage.qml"))
|
||||
return;
|
||||
}
|
||||
@ -350,7 +298,8 @@ Item {
|
||||
print("json client connected changed", engine.jsonRpcClient.connected)
|
||||
if (engine.jsonRpcClient.connected) {
|
||||
nymeaDiscovery.cacheHost(engine.jsonRpcClient.currentHost)
|
||||
tabSettings.lastConnectedHost = engine.jsonRpcClient.serverUuid
|
||||
configuredHost.uuid = engine.jsonRpcClient.serverUuid
|
||||
// tabSettings.lastConnectedHost = engine.jsonRpcClient.serverUuid
|
||||
}
|
||||
init();
|
||||
}
|
||||
@ -369,14 +318,14 @@ Item {
|
||||
popup.actualVersion = actualVersion;
|
||||
popup.minVersion = minVersion;
|
||||
popup.open()
|
||||
tabSettings.lastConnectedHost = ""
|
||||
// tabSettings.lastConnectedHost = ""
|
||||
}
|
||||
onInvalidMaximumVersion: {
|
||||
var popup = invalidVersionComponent.createObject(app.contentItem);
|
||||
popup.actualVersion = actualVersion;
|
||||
popup.maxVersion = maxVersion;
|
||||
popup.open()
|
||||
tabSettings.lastConnectedHost = ""
|
||||
// tabSettings.lastConnectedHost = ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,16 +426,16 @@ Item {
|
||||
Layout.fillWidth: true
|
||||
Material.elevation: 2
|
||||
position: TabBar.Footer
|
||||
currentIndex: configuredHostsModel.currentIndex
|
||||
|
||||
Repeater {
|
||||
model: tabModel.count
|
||||
model: configuredHostsModel
|
||||
|
||||
delegate: TabButton {
|
||||
id: hostTabButton
|
||||
property var engine: mainRepeater.itemAt(index)._engine
|
||||
property string serverName: engine.nymeaConfiguration.serverName
|
||||
readonly property ConfiguredHost configuredHost: configuredHostsModel.get(index)
|
||||
Material.elevation: index
|
||||
width: Math.max(150, tabbar.width / tabModel.count)
|
||||
width: Math.max(150, tabbar.width / configuredHostsModel.count)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
@ -494,49 +443,19 @@ Item {
|
||||
opacity: 0.06
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: hostTabButton.serverName !== "" ? hostTabButton.serverName : qsTr("New connection")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
ColorIcon {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: height
|
||||
visible: tabModel.count > 1
|
||||
name: "../images/close.svg"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: tabModel.removeTab(index)
|
||||
}
|
||||
}
|
||||
contentItem: Label {
|
||||
Layout.fillWidth: true
|
||||
text: hostTabButton.configuredHost.name !== "" ? hostTabButton.configuredHost.name : qsTr("New connection")
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
swipeView.currentIndex = index
|
||||
configuredHostsModel.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pane {
|
||||
Layout.preferredHeight: tabbar.height
|
||||
Layout.preferredWidth: height
|
||||
Material.elevation: 2
|
||||
padding: 0
|
||||
|
||||
TabButton {
|
||||
anchors.fill: parent
|
||||
contentItem: ColorIcon {
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
name: "../images/tab-new.svg"
|
||||
}
|
||||
onClicked: {
|
||||
tabModel.addTab()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,4 +98,8 @@ Item {
|
||||
|
||||
readonly property color red: "#952727"
|
||||
readonly property color white: "white"
|
||||
|
||||
readonly property int fastAnimationDuration: 100
|
||||
readonly property int animationDuration: 150
|
||||
readonly property int slowAnimationDuration: 300
|
||||
}
|
||||
|
||||
@ -65,9 +65,7 @@ Item {
|
||||
buttonDelegate.longpressed = false
|
||||
}
|
||||
onReleased: {
|
||||
print("onReleased!")
|
||||
if (!containsMouse) {
|
||||
print("cancelled")
|
||||
buttonDelegate.longpressed = false;
|
||||
return;
|
||||
}
|
||||
@ -80,7 +78,6 @@ Item {
|
||||
root.clicked();
|
||||
}
|
||||
buttonDelegate.longpressed = false
|
||||
print("released end")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,15 +25,28 @@ Page {
|
||||
anchors.fill: parent
|
||||
spacing: Style.margins
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.margins
|
||||
text: root.title
|
||||
font: Style.largeFont
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
RowLayout {
|
||||
ProgressButton {
|
||||
imageSource: "/ui/images/navigation-menu.svg"
|
||||
longpressEnabled: false
|
||||
onClicked: mainMenu.open()
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Style.margins
|
||||
text: root.title
|
||||
font: Style.largeFont
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
Item {
|
||||
Layout.preferredHeight: Style.iconSize + Style.smallMargins * 2
|
||||
Layout.preferredWidth: Style.iconSize + Style.smallMargins * 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Label {
|
||||
id: textLabel
|
||||
Layout.fillWidth: true
|
||||
|
||||
@ -146,7 +146,8 @@ WizardPageBase {
|
||||
WizardPageBase {
|
||||
title: qsTr("Connection")
|
||||
text: qsTr("Connecting to the nymea system.")
|
||||
showNextButton: false
|
||||
nextButtonText: qsTr("Manual connection")
|
||||
onNext: pageStack.push(manualConnectionComponent)
|
||||
|
||||
onBack: pageStack.pop()
|
||||
|
||||
@ -248,6 +249,95 @@ WizardPageBase {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: manualConnectionComponent
|
||||
WizardPageBase {
|
||||
title: qsTr("Manual connection")
|
||||
text: qsTr("Please enter the connection information for your nymea system")
|
||||
onBack: pageStack.pop()
|
||||
|
||||
onNext: {
|
||||
var rpcUrl
|
||||
var hostAddress
|
||||
var port
|
||||
|
||||
// Set default to placeholder
|
||||
if (addressTextInput.text === "") {
|
||||
hostAddress = addressTextInput.placeholderText
|
||||
} else {
|
||||
hostAddress = addressTextInput.text
|
||||
}
|
||||
|
||||
if (portTextInput.text === "") {
|
||||
port = portTextInput.placeholderText
|
||||
} else {
|
||||
port = portTextInput.text
|
||||
}
|
||||
|
||||
if (connectionTypeComboBox.currentIndex == 0) {
|
||||
if (secureCheckBox.checked) {
|
||||
rpcUrl = "nymeas://" + hostAddress + ":" + port
|
||||
} else {
|
||||
rpcUrl = "nymea://" + hostAddress + ":" + port
|
||||
}
|
||||
} else if (connectionTypeComboBox.currentIndex == 1) {
|
||||
if (secureCheckBox.checked) {
|
||||
rpcUrl = "wss://" + hostAddress + ":" + port
|
||||
} else {
|
||||
rpcUrl = "ws://" + hostAddress + ":" + port
|
||||
}
|
||||
}
|
||||
|
||||
print("Try to connect ", rpcUrl)
|
||||
var host = nymeaDiscovery.nymeaHosts.createWanHost("Manual connection", rpcUrl);
|
||||
engine.jsonRpcClient.connectToHost(host)
|
||||
}
|
||||
|
||||
content: ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.margins
|
||||
GridLayout {
|
||||
columns: 2
|
||||
|
||||
Label {
|
||||
text: qsTr("Protocol")
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: connectionTypeComboBox
|
||||
Layout.fillWidth: true
|
||||
model: [ qsTr("TCP"), qsTr("Websocket") ]
|
||||
}
|
||||
|
||||
Label { text: qsTr("Address:") }
|
||||
TextField {
|
||||
id: addressTextInput
|
||||
objectName: "addressTextInput"
|
||||
Layout.fillWidth: true
|
||||
placeholderText: "127.0.0.1"
|
||||
}
|
||||
|
||||
Label { text: qsTr("Port:") }
|
||||
TextField {
|
||||
id: portTextInput
|
||||
Layout.fillWidth: true
|
||||
placeholderText: connectionTypeComboBox.currentIndex === 0 ? "2222" : "4444"
|
||||
validator: IntValidator{bottom: 1; top: 65535;}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Encrypted connection:")
|
||||
}
|
||||
CheckBox {
|
||||
id: secureCheckBox
|
||||
checked: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: wiredInstructionsComponent
|
||||
WizardPageBase {
|
||||
|
||||
Reference in New Issue
Block a user