diff --git a/src/StorageBackend.cpp b/src/StorageBackend.cpp index b61432b..34393e9 100644 --- a/src/StorageBackend.cpp +++ b/src/StorageBackend.cpp @@ -10,6 +10,7 @@ #include #include #include +#include // StorageBackend is responsible for managing the interaction with the storage module. // It is mocked in the QML. @@ -30,6 +31,8 @@ StorageBackend::StorageBackend(LogosAPI* logosAPI, QObject* parent) } m_logos = new LogosModules(m_logosAPI); + + emit ready(); } StorageBackend::~StorageBackend() @@ -38,20 +41,24 @@ StorageBackend::~StorageBackend() m_logos = nullptr; } -LogosResult StorageBackend::init(const QString& configJson = "{}") { +LogosResult StorageBackend::init(const QString& configJson) { qDebug() << "StorageBackend::initStorage called"; - if (configJson != "{}") { - m_configJson = configJson; + m_config = QJsonDocument::fromJson(configJson.toUtf8()); + if (m_config.isNull()) { + qDebug() << "StorageBackend::initStorage invalid json config" << configJson; + emit initFailed(); + return {false, "", "Failed to create the storage, invalid json config"}; } - bool result = m_logos->storage_module.init(m_configJson); + bool result = m_logos->storage_module.init(configJson); qDebug() << "StorageBackend::initStorage: init"; if (!result) { setStatus(Destroyed); debug("Failed to init storage"); + emit initFailed(); return {false, "", "Filed to init storage"}; } @@ -197,13 +204,8 @@ LogosResult StorageBackend::init(const QString& configJson = "{}") { qWarning() << "StorageWidget: failed to subscribe to storageDownloadProgress events"; } - if (configJson != "{}") { - m_configJson = configJson; - emit configJsonChanged(); - debug("new config is: " + m_configJson); - } - emit initCompleted(); + debug("new config is: " + configJson); return {true, ""}; } @@ -725,12 +727,7 @@ void StorageBackend::space() { static constexpr qint64 DEFAULT_QUOTA = 20LL * 1024 * 1024 * 1024; // 20 GB // Check config for a quota-max-bytes override - qint64 configQuota = 0; - QJsonDocument doc = QJsonDocument::fromJson(m_configJson.toUtf8()); - if (!doc.isNull()) { - configQuota = doc.object().value("quota-max-bytes").toVariant().toLongLong(); - } - + qint64 configQuota = m_config.object().value("quota-max-bytes").toVariant().toLongLong(); qint64 apiQuota = result.getInt("quotaMaxBytes"); m_quotaMaxBytes = apiQuota > 0 ? apiQuota : (configQuota > 0 ? configQuota : DEFAULT_QUOTA); m_quotaUsedBytes = result.getInt("quotaUsedBytes"); @@ -764,30 +761,26 @@ StorageBackend::StorageStatus StorageBackend::status() const { return m_status; QString StorageBackend::cid() const { return m_cid; } -QString StorageBackend::configJson() const { return m_configJson; } +QString StorageBackend::configJson() const { return QString::fromUtf8(m_config.toJson(QJsonDocument::Compact)); } int StorageBackend::uploadProgress() const { return m_uploadProgress; } QString StorageBackend::uploadStatus() const { return m_uploadStatus; } void StorageBackend::reloadIfChanged(const QString& configJson) { - if (configJson == m_configJson) { + QJsonDocument config = QJsonDocument::fromJson(configJson.toUtf8()); + if (config.isNull()) { + debug("Invalid json detected !"); + return; + } + + if (m_config == config) { debug("No change detected in the config"); return; } debug("New config detected"); - QJsonDocument doc = QJsonDocument::fromJson(configJson.toUtf8()); - if (doc.isNull()) { - debug("Invalid json detected !"); - - m_configJson = configJson; - emit configJsonChanged(); - - return; - } - if (m_status == StorageStatus::Running || m_status == StorageStatus::Stopping || m_status == StorageStatus::Starting) { debug("Cannot reload the config while running, stopping or starting..."); @@ -805,154 +798,124 @@ void StorageBackend::reloadIfChanged(const QString& configJson) { } } - bool result = m_logos->storage_module.init(configJson); + LogosResult result = init(configJson); - if (!result) { - debug("Failed to init context with new config, will rollback."); - - bool result = m_logos->storage_module.init(m_configJson); - - if (!result) { - debug("Failed to init context with old config, that's a serious issue."); - } else { - debug("Old config restored"); - setStatus(StorageStatus::Stopped); - - m_configJson = configJson; - emit configJsonChanged(); - } + if (!result.success) { + debug("Failed to init context with new config: " + result.getError()); return; } debug("New config loaded successfully"); - m_configJson = configJson; + m_config = config; setStatus(StorageStatus::Stopped); - emit configJsonChanged(); +} + +void StorageBackend::saveCurrentConfig() { + qDebug() << "StorageBackend::saveUserConfig"; + saveUserConfig(QString::fromUtf8(m_config.toJson(QJsonDocument::Compact))); } void StorageBackend::saveUserConfig(const QString& configJson) { qDebug() << "StorageBackend::saveUserConfig"; - QString configPath = getUserConfigPath(); - QString folderPath = QFileInfo(configPath).absolutePath(); + QString folderPath = QFileInfo(USER_CONFIG_PATH).absolutePath(); QDir().mkpath(folderPath); - QFile file(configPath); + QFile file(USER_CONFIG_PATH); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { file.write(configJson.toUtf8()); file.close(); - debug("Config saved to " + configPath); + debug("Config saved to " + USER_CONFIG_PATH); } else { - debug("Failed to save config to " + configPath); + debug("Failed to save config to " + USER_CONFIG_PATH); } } -QString StorageBackend::buildConfig(const QString& dataDir, int discPort, int tcpPort) { - debug("StorageBackend::updateBasicConfig called with dataDir=" + dataDir); - - QJsonDocument doc = QJsonDocument::fromJson(m_configJson.toUtf8()); +QJsonDocument StorageBackend::defaultConfig() { + QJsonDocument doc = QJsonDocument(); QJsonObject obj = doc.object(); - obj["data-dir"] = dataDir; - obj["disc-port"] = discPort; - - QJsonArray listenAddrs = {QString("/ip4/0.0.0.0/tcp/%1").arg(tcpPort)}; - obj["listen-addrs"] = listenAddrs; - QJsonArray bootstrapArray; for (const QString& node : BOOTSTRAP_NODES) { bootstrapArray.append(node); } obj["bootstrap-node"] = bootstrapArray; - return QJsonDocument(obj).toJson(QJsonDocument::Indented); + obj["data-dir"] = DEFAULT_DATA_DIR; + + return QJsonDocument(obj); } -QString StorageBackend::buildUpnpConfig(const QString& dataDir) { - debug("StorageBackend::buildUpnpConfig called with dataDir=" + dataDir); +void StorageBackend::enableUpnpConfig() { + debug("StorageBackend::enableUpnpConfig called"); - QJsonDocument doc = QJsonDocument::fromJson(m_configJson.toUtf8()); + QJsonDocument doc = defaultConfig(); QJsonObject obj = doc.object(); - obj["data-dir"] = dataDir; - - QJsonArray bootstrapArray; - for (const QString& node : BOOTSTRAP_NODES) { - bootstrapArray.append(node); - } obj["nat"] = "upnp"; - return QJsonDocument(obj).toJson(QJsonDocument::Indented); + reloadIfChanged(QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact))); } -QString StorageBackend::buildNatExtConfig(const QString& dataDir, int tcpPort) { - debug("StorageBackend::buildUpnpConfig called with dataDir=" + dataDir + - " and tcpPort=" + QString::number(tcpPort)); +void StorageBackend::enableNatExtConfig(int tcpPort) { + qDebug() << "StorageBackend::enableNatExtConfig called with tcpPort" << tcpPort; - QJsonDocument doc = QJsonDocument::fromJson(m_configJson.toUtf8()); + QJsonDocument doc = defaultConfig(); QJsonObject obj = doc.object(); - obj["data-dir"] = dataDir; + QJsonArray listenAddrs = {QString("/ip4/0.0.0.0/tcp/%1").arg(tcpPort)}; + obj["listen-addrs"] = listenAddrs; - QJsonArray bootstrapArray; - for (const QString& node : BOOTSTRAP_NODES) { - bootstrapArray.append(node); - } + qDebug() << "StorageBackend::enableNatExtConfig Retrieving the public IP"; - debug("Retrieving the public IP"); + // Create the network manager + QNetworkAccessManager* manager = new QNetworkAccessManager(this); + QNetworkRequest request(QUrl("https://echo.codex.storage/")); + request.setRawHeader("Accept", "text/plain"); + QNetworkReply* reply = manager->get(request); - QNetworkAccessManager manager; - QEventLoop loop; - QNetworkReply* reply = manager.get(QNetworkRequest(QUrl("https://echo.codex.storage/"))); - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); + connect(reply, &QNetworkReply::finished, this, [this, reply, manager, obj]() { + reply->deleteLater(); + manager->deleteLater(); - QString ip = reply->readAll().trimmed(); - reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + emit natExtConfigFailed(reply->errorString()); + return; + } - debug("Public IP detected:" + ip); + QString ip = reply->readAll().trimmed(); - obj["nat"] = "extip:" + ip; + qDebug() << "StorageBackend::enableNatExtConfig ip=" << ip; - return QJsonDocument(obj).toJson(QJsonDocument::Indented); -} + obj["nat"] = "extip:" + ip; -QString StorageBackend::buildConfigFromFile(const QString& path) { - qDebug() << "StorageBackend::buildConfigFromFile called"; + qDebug() << "StorageBackend::enableNatExtConfig config=" + << QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact)); - QFile file(path); - if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QString configJson = QString::fromUtf8(file.readAll()); + reloadIfChanged(QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact))); - debug("StorageUIPlugin: config.json is found, configJson=" + configJson); - - return configJson; - } - - debug("StorageUIPlugin: Failed to load config.json"); - return "{}"; + emit natExtConfigCompleted(); + }); } void StorageBackend::status(StorageStatus status) { m_status = status; } -QString StorageBackend::getUserConfigPath() { return QDir::homePath() + "/.logos_storage/config.json"; } +void StorageBackend::loadUserConfig() { + qDebug() << "StorageBackend::loadUserConfig called."; + + QFile file(USER_CONFIG_PATH); + LogosResult result; -QString StorageBackend::getUserConfig() { - QFile file(getUserConfigPath()); if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return QString::fromUtf8(file.readAll()); + result = init(QString::fromUtf8(file.readAll())); + } else { + qWarning() << "StorageBackend::loadUserConfig Failed to read the user config file, fallback to default config"; + result = init(QString::fromUtf8(defaultConfig().toJson(QJsonDocument::Compact))); } - return "{}"; -} - -QString StorageBackend::defaultDataDir() { - QString home = QDir::homePath(); -#ifdef Q_OS_WIN - return home + "/AppData/Roaming/Storage"; -#elif defined(Q_OS_MACOS) - return home + "/Library/Application Support/Storage"; -#else - return home + "/.cache/storage"; -#endif + if (!result.success) { + qWarning() << "StorageBackend::loadUserConfig Failed to load the user config: " + result.getError(); + } else { + debug("User config loaded successfully"); + } } diff --git a/src/StorageBackend.h b/src/StorageBackend.h index d31109c..39db7f7 100644 --- a/src/StorageBackend.h +++ b/src/StorageBackend.h @@ -1,6 +1,7 @@ #pragma once #include "logos_api.h" #include "logos_sdk.h" +#include #include #include #include @@ -10,6 +11,10 @@ static const int RET_OK = 0; static const int RET_PROGRESS = 3; +static const QUrl ECHO_PROVIDER("https://echo.codex.storage/"); +static const QString APP_HOME = QDir::homePath() + "/.logos_storage"; +static const QString DEFAULT_DATA_DIR = APP_HOME + "/data"; +static const QString USER_CONFIG_PATH = APP_HOME + "/config.json"; // Add manual SPR from https://spr.codex.storage/devnet static const QStringList BOOTSTRAP_NODES = { @@ -30,7 +35,6 @@ class StorageBackend : public QObject { Q_PROPERTY(QString debugLogs READ debugLogs NOTIFY debugLogsChanged) Q_PROPERTY(StorageStatus status READ status WRITE status NOTIFY statusChanged) Q_PROPERTY(QString cid READ cid NOTIFY cidChanged) - Q_PROPERTY(QString configJson READ configJson NOTIFY configJsonChanged) Q_PROPERTY(int uploadProgress READ uploadProgress NOTIFY uploadProgressChanged) Q_PROPERTY(QString uploadStatus READ uploadStatus NOTIFY uploadStatusChanged) Q_PROPERTY(QVariantList manifests READ manifests NOTIFY manifestsChanged) @@ -39,7 +43,20 @@ class StorageBackend : public QObject { Q_PROPERTY(qint64 quotaReservedBytes READ quotaReservedBytes NOTIFY quotaChanged) public: - enum StorageStatus { Stopped = 0, Starting, Running, Stopping, Destroyed }; + enum StorageStatus { + // Stopped means that the context is created but the module is not started + Stopped = 0, + + Starting, + + // Running means the module is started + Running, + + Stopping, + + // Destroyed means the context is not created (or has been destroyed). + Destroyed + }; Q_ENUM(StorageStatus) QString cid() const; @@ -53,9 +70,7 @@ class StorageBackend : public QObject { qint64 quotaUsedBytes() const; qint64 quotaReservedBytes() const; - Q_INVOKABLE static QString defaultDataDir(); - static QString getUserConfig(); - static QString getUserConfigPath(); + static QJsonDocument defaultConfig(); explicit StorageBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr); ~StorageBackend(); @@ -82,27 +97,58 @@ class StorageBackend : public QObject { void space(); LogosResult init(const QString& configJson); void updateLogLevel(const QString& logLevel); - void reloadIfChanged(const QString& configJson); void status(StorageStatus status); - QString buildConfig(const QString& dataDir, int discPort, int tcpPort); - QString buildUpnpConfig(const QString& dataDir); - QString buildNatExtConfig(const QString& dataDir, int tcpPort); - QString buildConfigFromFile(const QString& path); + + // Save the user config passed in parameter + // into the user config json. void saveUserConfig(const QString& configJson); + // Save the current config object + // into the user config json. + void saveCurrentConfig(); + + // Load the user config saved previously + void loadUserConfig(); + + // Take a new config json and reload the Storage context + // if the configuration has changed. + // + // This method cannot be used if the Storage Module + // is running, starting or stopping. + // + // If the Storage Module was already created, + // it will be destroyed first. + // + // On success, the status will be set to Stopped. + // + // Emit initCompleted on success. + // Emit initFailed on failure. + void reloadIfChanged(const QString& configJson); + + // Enables the upnp in the config + // and re-create a context with the new configuration + void enableUpnpConfig(); + + // Enables the net external in the config + // and re-create a context with the new configuration + void enableNatExtConfig(int tcpPort); + signals: + void ready(); void startCompleted(); void startFailed(const QString& error); void statusChanged(); void debugLogsChanged(); void stopCompleted(); void cidChanged(); - void configJsonChanged(); void uploadProgressChanged(); void uploadStatusChanged(); void manifestsChanged(); void quotaChanged(); void initCompleted(); + void initFailed(); + void natExtConfigFailed(const QString& error); + void natExtConfigCompleted(); private slots: @@ -116,7 +162,6 @@ class StorageBackend : public QObject { StorageStatus m_status; QString m_debugLogs; QString m_cid; - QString m_configJson; int m_uploadProgress = 0; QString m_uploadStatus = ""; qint64 m_uploadTotalBytes = 0; @@ -125,4 +170,5 @@ class StorageBackend : public QObject { qint64 m_quotaMaxBytes = 0; qint64 m_quotaUsedBytes = 0; qint64 m_quotaReservedBytes = 0; + QJsonDocument m_config; }; diff --git a/src/StorageUIPlugin.cpp b/src/StorageUIPlugin.cpp index 09ffcfd..622a6a3 100644 --- a/src/StorageUIPlugin.cpp +++ b/src/StorageUIPlugin.cpp @@ -54,29 +54,19 @@ QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) { root->setProperty("backend", QVariant::fromValue(static_cast(backend))); + backend->ready(); + // Storage init is done in the QML // Build config from settings if onboarding was done, otherwise use empty config - QString configJson = StorageBackend::getUserConfig(); - qDebug() << "UserConfig" << StorageBackend::getUserConfigPath(); - qDebug() << "configJson" << configJson; - // if (onboardingCompleted && !dataDir.isEmpty()) { - // configJson = backend->buildConfig(dataDir, discoveryPort, tcpPort); + // QString configJson = StorageBackend::getUserConfig(); + // qDebug() << "UserConfig" << StorageBackend::getUserConfigPath(); + // qDebug() << "configJson" << configJson; + + // LogosResult result = backend->init(configJson); + + // if (!result.success) { + // qWarning() << "StorageUIPlugin: Failed to init backend:" << result.getError(); // } - // config.json overrides everything (dev/debug use) - // QFileInfo info("config.json"); - // if (info.exists() && info.isFile()) { - // qWarning() << "StorageUIPlugin: config.json found — overriding settings config"; - // configJson = backend->buildConfigFromFile("config.json"); - // } - - // qDebug() << "StorageUIPlugin: configJson=" << configJson; - - LogosResult result = backend->init(configJson); - - if (!result.success) { - qWarning() << "StorageUIPlugin: Failed to init backend:" << result.getError(); - } - return quickWidget; } diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt index e08a675..a373110 100644 --- a/src/qml/CMakeLists.txt +++ b/src/qml/CMakeLists.txt @@ -132,7 +132,6 @@ qt_add_qml_module(appqml StartNode.qml LogosTextField.qml LogosStorageButton.qml - Nat.qml LogosStorageLayout.qml PortForwarding.qml ) diff --git a/src/qml/Main.qml b/src/qml/Main.qml index 01c193e..83fa598 100644 --- a/src/qml/Main.qml +++ b/src/qml/Main.qml @@ -25,19 +25,17 @@ Item { console.log("mock start called") } - function defaultDataDir() { - return ".cache/storage" - } - - function buildConfig() {} - function saveUserConfig() {} + function loadUserConfig() {} + function reloadIfChanged() {} - function buildUpnpConfig() {} + function enableUpnpConfig() {} - function buildNatExtConfig() {} + function enableNatExtConfig() {} + + function saveCurrentConfig() {} function stop() {} } @@ -51,6 +49,10 @@ Item { property string dataDir: "" property bool onboardingCompleted: false property string natStrategy: "any" + + Component.onCompleted: { + console.info("Settings completed") + } } StackView { @@ -63,33 +65,9 @@ Item { id: onboardingComponent OnBoarding { - backend: root.backend - // discoveryPort: settings.discoveryPort - // tcpPort: settings.tcpPort - dataDir: settings.dataDir - - onCompleted: { - // settings.discoveryPort = discoveryPort - settings.dataDir = dataDir - // settings.tcpPort = tcpPort - settings.onboardingCompleted = true - - stackView.push(natComponent) - } - } - } - - Component { - id: natComponent - - Nat { - onCompleted: function (enabled) { - if (enabled) { - settings.natStrategy = "upnp" - let config = root.backend.buildUpnpConfig(settings.dataDir) - root.backend.reloadIfChanged(config) - root.backend.start() - stackView.push(startNodeComponent) + onCompleted: function (upnpEnabled) { + if (upnpEnabled) { + root.backend.enableUpnpConfig() } else { stackView.push(portForwardingComponent) } @@ -117,6 +95,8 @@ Item { } onNext: { + settings.onboardingCompleted = true + root.backend.saveCurrentConfig() stackView.push(storageComponent) } } @@ -126,14 +106,8 @@ Item { id: portForwardingComponent PortForwarding { - onPortTcpSelected: function (port) { - settings.tcpPort = port - settings.natStrategy = "extip" - let config = root.backend.buildNatExtConfig(settings.dataDir, - port) - root.backend.reloadIfChanged(config) - root.backend.start() - stackView.push(startNodeComponent) + onCompleted: function (port) { + root.backend.enableNatExtConfig(port) } } } @@ -145,11 +119,23 @@ Item { stackView.pop() } - function onInitCompleted() { + function onInitCompleted() {} + + function onReady() { + console.info("i am ready") if (settings.onboardingCompleted) { + console.info("onboardingCompleted completed") + root.backend.loadUserConfig() root.backend.start() stackView.replace(storageComponent, StackView.Immediate) } } + + function onNatExtConfigFailed(error) {} + + function onNatExtConfigCompleted(error) { + root.backend.start() + stackView.push(startNodeComponent) + } } } diff --git a/src/qml/Nat.qml b/src/qml/Nat.qml deleted file mode 100644 index d3a9f0f..0000000 --- a/src/qml/Nat.qml +++ /dev/null @@ -1,45 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import Logos.Theme -import Logos.Controls - -LogosStorageLayout { - id: root - - signal completed(bool enabled) - - ColumnLayout { - anchors.centerIn: parent - spacing: Theme.spacing.medium - width: 400 - - LogosText { - id: questionText - font.pixelSize: Theme.typography.titleText - text: "Is UPnP enabled on your router ?" - Layout.alignment: Qt.AlignCenter - } - - LogosText { - id: questionDescriptionText - font.pixelSize: Theme.typography.primaryText - text: "UPnP simplifies configuration by handling port forwarding automatically." - Layout.alignment: Qt.AlignCenter - } - - RowLayout { - spacing: Theme.spacing.medium - Layout.alignment: Qt.AlignCenter - - LogosStorageButton { - text: "No / I don't know" - onClicked: root.completed(false) - } - - LogosStorageButton { - text: "Yes, I use UPnP" - onClicked: root.completed(true) - } - } - } -} diff --git a/src/qml/OnBoarding.qml b/src/qml/OnBoarding.qml index e3fef3c..7856356 100644 --- a/src/qml/OnBoarding.qml +++ b/src/qml/OnBoarding.qml @@ -7,125 +7,169 @@ import Logos.Controls LogosStorageLayout { id: root - property int discoveryPort: 8090 - property int tcpPort: 0 - property var backend: mockBackend - property var local: false - property string dataDir: backend.defaultDataDir() - - signal completed - - QtObject { - id: mockBackend - - function defaultDataDir() { - return ".cache/storage" - } - } + signal completed(bool enabled) ColumnLayout { - anchors.centerIn: parent spacing: Theme.spacing.medium + Layout.fillWidth: true + anchors.centerIn: parent LogosText { id: titleText font.pixelSize: Theme.typography.titleText - text: "Logos Storage" + text: "Welcome to Logos Storage" Layout.alignment: Qt.AlignCenter } LogosText { id: questionText font.pixelSize: Theme.typography.titleText - text: "First, let's choose the storage folder" + text: "Is UPnP enabled on your router ?" Layout.alignment: Qt.AlignCenter } - // ColumnLayout { - // id: discoveryPortColumn - // spacing: Theme.spacing.tiny - // Layout.fillWidth: true - - // LogosText { - // text: "Discovery port" - // font.pixelSize: Theme.typography.secondaryText - // color: Theme.palette.text - // } - - // LogosTextField { - // isValid: acceptableInput && text.length > 0 - // id: discoveryPortTextField - // placeholderText: "Enter the discovery port" - // text: root.discoveryPort - // validator: IntValidator { - // bottom: 1 - // top: 65535 - // } - // onTextChanged: { - // if (isValid) { - // root.discoveryPort = parseInt(text) - // } - // } - // } - // } - ColumnLayout { - spacing: Theme.spacing.tiny - Layout.fillWidth: true - - RowLayout { - spacing: Theme.spacing.tiny - - LogosTextField { - isValid: text.trim().length > 0 - id: dataDirTextField - placeholderText: "Enter the data dir" - text: root.dataDir - Layout.fillWidth: true - onTextChanged: { - root.dataDir = text - } - } - - LogosStorageButton { - text: "Choose" - onClicked: folderDialog.open() - } - } - - FolderDialog { - id: folderDialog - onAccepted: { - dataDirTextField.text = selectedFolder - } - } + LogosText { + id: questionDescriptionText + font.pixelSize: Theme.typography.primaryText + text: "UPnP simplifies configuration by handling port forwarding automatically." + Layout.alignment: Qt.AlignCenter } - // Column { - // CheckBox { - // text: "Do you want to connect to a local network ?" - // checked: false - // onCheckedChanged: root.local = checked - // } + RowLayout { + spacing: Theme.spacing.medium + Layout.alignment: Qt.AlignCenter - // LogosText { - // font.pixelSize: Theme.typography.secondaryText - // text: "You will not " - // Layout.alignment: Qt.AlignCenter - // } - // } - } + LogosStorageButton { + text: "No / I don't know" + onClicked: root.completed(false) + } - LogosStorageButton { - text: "Next" - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.bottomMargin: 10 - anchors.rightMargin: 10 - enabled: dataDirTextField.isValid - // enabled: discoveryPortTextField.acceptableInput - // && tcpPortTextField.acceptableInput && dataDirTextField.isValid - onClicked: function () { - root.completed() + LogosStorageButton { + text: "Yes, I use UPnP" + onClicked: root.completed(true) + } } } + + // property int discoveryPort: 8090 + // property int tcpPort: 0 + // property var backend: mockBackend + // property var local: false + // property string dataDir: backend.defaultDataDir() + + // signal completed + + // QtObject { + // id: mockBackend + + // function defaultDataDir() { + // return ".cache/storage" + // } + // } + + // ColumnLayout { + // anchors.centerIn: parent + // spacing: Theme.spacing.medium + + // LogosText { + // id: titleText + // font.pixelSize: Theme.typography.titleText + // text: "Logos Storage" + // Layout.alignment: Qt.AlignCenter + // } + + // LogosText { + // id: questionText + // font.pixelSize: Theme.typography.titleText + // text: "First, let's choose the storage folder" + // Layout.alignment: Qt.AlignCenter + // } + + // // ColumnLayout { + // // id: discoveryPortColumn + // // spacing: Theme.spacing.tiny + // // Layout.fillWidth: true + + // // LogosText { + // // text: "Discovery port" + // // font.pixelSize: Theme.typography.secondaryText + // // color: Theme.palette.text + // // } + + // // LogosTextField { + // // isValid: acceptableInput && text.length > 0 + // // id: discoveryPortTextField + // // placeholderText: "Enter the discovery port" + // // text: root.discoveryPort + // // validator: IntValidator { + // // bottom: 1 + // // top: 65535 + // // } + // // onTextChanged: { + // // if (isValid) { + // // root.discoveryPort = parseInt(text) + // // } + // // } + // // } + // // } + // ColumnLayout { + // spacing: Theme.spacing.tiny + // Layout.fillWidth: true + + // RowLayout { + // spacing: Theme.spacing.tiny + + // LogosTextField { + // isValid: text.trim().length > 0 + // id: dataDirTextField + // placeholderText: "Enter the data dir" + // text: root.dataDir + // Layout.fillWidth: true + // onTextChanged: { + // root.dataDir = text + // } + // } + + // LogosStorageButton { + // text: "Choose" + // onClicked: folderDialog.open() + // } + // } + + // FolderDialog { + // id: folderDialog + // onAccepted: { + // dataDirTextField.text = selectedFolder + // } + // } + // } + + // // Column { + // // CheckBox { + // // text: "Do you want to connect to a local network ?" + // // checked: false + // // onCheckedChanged: root.local = checked + // // } + + // // LogosText { + // // font.pixelSize: Theme.typography.secondaryText + // // text: "You will not " + // // Layout.alignment: Qt.AlignCenter + // // } + // // } + // } + + // LogosStorageButton { + // text: "Next" + // anchors.bottom: parent.bottom + // anchors.right: parent.right + // anchors.bottomMargin: 10 + // anchors.rightMargin: 10 + // enabled: dataDirTextField.isValid + // // enabled: discoveryPortTextField.acceptableInput + // // && tcpPortTextField.acceptableInput && dataDirTextField.isValid + // onClicked: function () { + // root.completed() + // } + // } } diff --git a/src/qml/PortForwarding.qml b/src/qml/PortForwarding.qml index b6102a1..8e2a334 100644 --- a/src/qml/PortForwarding.qml +++ b/src/qml/PortForwarding.qml @@ -8,12 +8,13 @@ LogosStorageLayout { property var tcpPort: 0 - signal portTcpSelected(int port) + signal completed(int port) ColumnLayout { anchors.centerIn: parent spacing: Theme.spacing.medium width: 400 + Layout.fillWidth: true LogosText { id: questionText @@ -30,6 +31,7 @@ LogosStorageLayout { } LogosTextField { + Layout.fillWidth: true isValid: acceptableInput && text.length > 0 id: tcpPortTextField placeholderText: "Enter the TCP port" @@ -44,15 +46,12 @@ LogosStorageLayout { } } } - } - LogosStorageButton { - text: "Next" - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.bottomMargin: 10 - anchors.rightMargin: 10 - enabled: tcpPortTextField.isValid - onClicked: root.portTcpSelected(root.tcpPort) + LogosStorageButton { + text: "Next" + + enabled: tcpPortTextField.isValid + onClicked: root.completed(root.tcpPort) + } } } diff --git a/src/qml/StartNode.qml b/src/qml/StartNode.qml index 9beddda..2ee5499 100644 --- a/src/qml/StartNode.qml +++ b/src/qml/StartNode.qml @@ -4,13 +4,8 @@ import QtQuick.Controls import Logos.Controls import Logos.Theme -Rectangle { +LogosStorageLayout { id: root - color: Theme.palette.background - Layout.fillWidth: true - Layout.fillHeight: true - implicitWidth: 600 - implicitHeight: 400 property var backend: mockBackend property string status: "" @@ -64,9 +59,8 @@ Rectangle { } ColumnLayout { - anchors.fill: parent - anchors.margins: 20 - anchors.bottomMargin: 60 + Layout.fillWidth: true + anchors.centerIn: parent spacing: Theme.spacing.medium LogosText { diff --git a/src/storage_resources.qrc b/src/storage_resources.qrc index 0ec01ad..fff4020 100644 --- a/src/storage_resources.qrc +++ b/src/storage_resources.qrc @@ -6,5 +6,7 @@ qml/StorageView.qml qml/LogosTextField.qml qml/LogosStorageButton.qml + qml/LogosStorageLayout.qml + qml/PortForwarding.qml