mirror of
https://github.com/logos-storage/logos-storage-app-skeleton.git
synced 2026-06-13 20:09:28 +00:00
commit
c7bb9560dd
@ -62,6 +62,23 @@ if(NOT DEFINED LOGOS_STORAGE_ROOT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED LOGOS_DESIGN_SYSTEM_ROOT)
|
||||
set(_parent_logos_design_system "${CMAKE_SOURCE_DIR}/../logos-design-system")
|
||||
set(_use_vendor ${LOGOS_STORAGE_UI_USE_VENDOR})
|
||||
|
||||
if(NOT _use_vendor)
|
||||
if(NOT EXISTS "${_parent_logos_design_system}/CMakeLists.txt")
|
||||
set(_use_vendor ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_use_vendor)
|
||||
set(LOGOS_DESIGN_SYSTEM_ROOT "${CMAKE_SOURCE_DIR}/vendor/logos-design-system")
|
||||
else()
|
||||
set(LOGOS_DESIGN_SYSTEM_ROOT "${_parent_logos_design_system}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(_liblogos_found FALSE)
|
||||
if(EXISTS "${LOGOS_LIBLOGOS_ROOT}/src/common/interface.h")
|
||||
set(_liblogos_found TRUE)
|
||||
@ -329,6 +346,32 @@ if(absl_FOUND)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set up QML module directory for runtime
|
||||
set(QML_THEME_DIR ${CMAKE_CURRENT_BINARY_DIR}/qml/Logos/Theme)
|
||||
set(QML_CONTROLS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qml/Logos/Controls)
|
||||
|
||||
# Detect if design system is source or installed layout
|
||||
set(_design_system_is_source FALSE)
|
||||
if(EXISTS "${LOGOS_DESIGN_SYSTEM_ROOT}/src/qml/theme")
|
||||
set(_design_system_is_source TRUE)
|
||||
set(DESIGN_SYSTEM_THEME_SRC "${LOGOS_DESIGN_SYSTEM_ROOT}/src/qml/theme")
|
||||
set(DESIGN_SYSTEM_CONTROLS_SRC "${LOGOS_DESIGN_SYSTEM_ROOT}/src/qml/controls")
|
||||
else()
|
||||
# Installed/Nix layout: files are in lib/Logos/Theme and lib/Logos/Controls
|
||||
set(DESIGN_SYSTEM_THEME_SRC "${LOGOS_DESIGN_SYSTEM_ROOT}/lib/Logos/Theme")
|
||||
set(DESIGN_SYSTEM_CONTROLS_SRC "${LOGOS_DESIGN_SYSTEM_ROOT}/lib/Logos/Controls")
|
||||
endif()
|
||||
|
||||
# Copy QML module files to runtime directory
|
||||
# Pure QML module - no library, just QML files + qmldir
|
||||
add_custom_command(TARGET storage_ui POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QML_THEME_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${DESIGN_SYSTEM_THEME_SRC}/ ${QML_THEME_DIR}/
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QML_CONTROLS_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${DESIGN_SYSTEM_CONTROLS_SRC}/ ${QML_CONTROLS_DIR}/
|
||||
COMMENT "Setting up Logos.Theme and Logos.Controls QML modules for the app"
|
||||
)
|
||||
|
||||
########### LIBRARY DEFINITION END ###########
|
||||
|
||||
########### HEADERS ###########
|
||||
|
||||
18
README.md
18
README.md
@ -62,7 +62,23 @@ After building the app with `nix build`, you can run it:
|
||||
./result/bin/logos-storage-ui-app
|
||||
```
|
||||
|
||||
The app will automatically load the required modules (capability_module, storage_module) and the storage_ui Qt plugin. All dependencies are bundled in the Nix store layout.
|
||||
## Configuration
|
||||
|
||||
After onboarding, settings are saved to a file whose location depends on the OS:
|
||||
|
||||
| OS | Path |
|
||||
|---------|--------------------------------------------------|
|
||||
| Linux | `~/.config/Logos/LogosStorage.conf` |
|
||||
| macOS | `~/Library/Preferences/Logos.LogosStorage.plist` |
|
||||
| Windows | `HKCU\Software\Logos\LogosStorage` (Registry) |
|
||||
|
||||
## Configuration Management
|
||||
|
||||
To restart the onboarding process, simply delete the configuration file and relaunch the application.
|
||||
|
||||
You can override the configuration by placing a `config.json` file in the app's startup folder. This file takes precedence over any existing configuration.
|
||||
|
||||
The application also provides a JSON editor in the debug panel for runtime configuration tweaks. To apply changes, restart the Storage Module.
|
||||
|
||||
#### Nix Organization
|
||||
|
||||
|
||||
@ -29,6 +29,11 @@ int main(int argc, char* argv[]) {
|
||||
// Create QApplication first
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Set application properties for Qt Settings
|
||||
QCoreApplication::setOrganizationName("Logos");
|
||||
QCoreApplication::setOrganizationDomain("logos.co");
|
||||
QCoreApplication::setApplicationName("LogosStorage");
|
||||
|
||||
// Set the plugins directory
|
||||
QString pluginsDir = QDir::cleanPath(QCoreApplication::applicationDirPath() + "/../modules");
|
||||
std::cout << "Setting plugins directory to: " << pluginsDir.toStdString() << std::endl;
|
||||
|
||||
53
flake.lock
generated
53
flake.lock
generated
@ -91,7 +91,7 @@
|
||||
},
|
||||
"logos-cpp-sdk_3": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1761230734,
|
||||
@ -109,7 +109,7 @@
|
||||
},
|
||||
"logos-cpp-sdk_4": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
"nixpkgs": "nixpkgs_5"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1761230734,
|
||||
@ -127,7 +127,7 @@
|
||||
},
|
||||
"logos-cpp-sdk_5": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_5"
|
||||
"nixpkgs": "nixpkgs_6"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767724329,
|
||||
@ -145,7 +145,7 @@
|
||||
},
|
||||
"logos-cpp-sdk_6": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_6"
|
||||
"nixpkgs": "nixpkgs_7"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767724329,
|
||||
@ -161,6 +161,24 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"logos-design-system": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1771237838,
|
||||
"narHash": "sha256-UcdHiZ5IdfCSOy17WTz04ZV1n4qqycVfwYzI7BkXeuc=",
|
||||
"owner": "logos-co",
|
||||
"repo": "logos-design-system",
|
||||
"rev": "596811cbb0a0644322267368e87fab80e34203d8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "logos-co",
|
||||
"repo": "logos-design-system",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"logos-liblogos": {
|
||||
"inputs": {
|
||||
"logos-cpp-sdk": "logos-cpp-sdk",
|
||||
@ -290,7 +308,7 @@
|
||||
},
|
||||
"logos-storage": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_7"
|
||||
"nixpkgs": "nixpkgs_8"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770982130,
|
||||
@ -369,16 +387,16 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1759036355,
|
||||
"narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
|
||||
"lastModified": 1751274312,
|
||||
"narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
|
||||
"rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixos-24.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@ -432,6 +450,22 @@
|
||||
}
|
||||
},
|
||||
"nixpkgs_7": {
|
||||
"locked": {
|
||||
"lastModified": 1759036355,
|
||||
"narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_8": {
|
||||
"locked": {
|
||||
"lastModified": 1751274312,
|
||||
"narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=",
|
||||
@ -451,6 +485,7 @@
|
||||
"inputs": {
|
||||
"logos-capability-module": "logos-capability-module",
|
||||
"logos-cpp-sdk": "logos-cpp-sdk_2",
|
||||
"logos-design-system": "logos-design-system",
|
||||
"logos-liblogos": "logos-liblogos_2",
|
||||
"logos-storage-module": "logos-storage-module",
|
||||
"nixpkgs": [
|
||||
|
||||
13
flake.nix
13
flake.nix
@ -10,13 +10,13 @@
|
||||
logos-storage-module.url = "github:logos-co/logos-storage-module";
|
||||
#logos-storage-module.url = "path:/home/arnaud/Work/logos/logos-storage-module";
|
||||
logos-capability-module.url = "github:logos-co/logos-capability-module";
|
||||
|
||||
logos-design-system.url = "github:logos-co/logos-design-system";
|
||||
logos-liblogos.inputs.logos-cpp-sdk.follows = "logos-cpp-sdk";
|
||||
logos-storage-module.inputs.logos-cpp-sdk.follows = "logos-cpp-sdk";
|
||||
logos-capability-module.inputs.logos-cpp-sdk.follows = "logos-cpp-sdk";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, logos-cpp-sdk, logos-liblogos, logos-storage-module, logos-capability-module }:
|
||||
outputs = { self, nixpkgs, logos-cpp-sdk, logos-liblogos, logos-storage-module, logos-capability-module, logos-design-system }:
|
||||
let
|
||||
systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f {
|
||||
@ -25,14 +25,15 @@
|
||||
logosLiblogos = logos-liblogos.packages.${system}.default;
|
||||
logosStorageModule = logos-storage-module.packages.${system}.default;
|
||||
logosCapabilityModule = logos-capability-module.packages.${system}.default;
|
||||
logosDesignSystem = logos-design-system.packages.${system}.default;
|
||||
});
|
||||
in
|
||||
{
|
||||
packages = forAllSystems ({ pkgs, logosSdk, logosLiblogos, logosStorageModule, logosCapabilityModule }:
|
||||
packages = forAllSystems ({ pkgs, logosSdk, logosLiblogos, logosStorageModule, logosCapabilityModule, logosDesignSystem }:
|
||||
let
|
||||
# Common configuration
|
||||
common = import ./nix/default.nix {
|
||||
inherit pkgs logosSdk logosLiblogos logosStorageModule;
|
||||
inherit pkgs logosSdk logosLiblogos logosStorageModule logosDesignSystem;
|
||||
};
|
||||
src = ./.;
|
||||
|
||||
@ -42,8 +43,8 @@
|
||||
};
|
||||
|
||||
# App package
|
||||
app = import ./nix/app.nix {
|
||||
inherit pkgs common src logosLiblogos logosSdk logosStorageModule logosCapabilityModule;
|
||||
app = import ./nix/app.nix {
|
||||
inherit pkgs common src logosLiblogos logosSdk logosStorageModule logosCapabilityModule logosDesignSystem;
|
||||
logosStorageUI = lib;
|
||||
};
|
||||
|
||||
|
||||
13
nix/app.nix
13
nix/app.nix
@ -1,5 +1,5 @@
|
||||
# Builds the logos-storage-ui-app standalone application
|
||||
{ pkgs, common, src, logosLiblogos, logosSdk, logosStorageModule, logosCapabilityModule, logosStorageUI }:
|
||||
{ pkgs, common, src, logosLiblogos, logosSdk, logosStorageModule, logosCapabilityModule, logosStorageUI, logosDesignSystem }:
|
||||
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
pname = "${common.pname}-app";
|
||||
@ -213,6 +213,17 @@ pkgs.stdenv.mkDerivation rec {
|
||||
cp -L "${logosStorageUI}/lib/storage_ui.$OS_EXT" "$out/"
|
||||
fi
|
||||
|
||||
# Copy QML modules from design system (Logos.Theme and Logos.Controls)
|
||||
if [ -d "${logosDesignSystem}/lib/Logos" ]; then
|
||||
echo "Installing QML modules from design system..."
|
||||
mkdir -p "$out/lib"
|
||||
cp -r "${logosDesignSystem}/lib/Logos" "$out/lib/"
|
||||
echo "Installed Logos QML modules:"
|
||||
ls -la "$out/lib/Logos/"
|
||||
else
|
||||
echo "Warning: Logos QML modules not found in design system at ${logosDesignSystem}/lib/Logos"
|
||||
fi
|
||||
|
||||
# Create a README for reference
|
||||
cat > $out/README.txt <<EOF
|
||||
Logos Storage UI App - Build Information
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
# Common build configuration shared across all packages
|
||||
{ pkgs, logosSdk, logosLiblogos, logosStorageModule }:
|
||||
{ pkgs, logosSdk, logosLiblogos, logosStorageModule, logosDesignSystem }:
|
||||
|
||||
{
|
||||
pname = "logos-storage-ui";
|
||||
@ -28,6 +28,7 @@
|
||||
"-DLOGOS_CPP_SDK_ROOT=${logosSdk}"
|
||||
"-DLOGOS_LIBLOGOS_ROOT=${logosLiblogos}"
|
||||
"-DLOGOS_STORAGE_ROOT=${logosStorageModule}"
|
||||
"-DLOGOS_DESIGN_SYSTEM_ROOT=${logosDesignSystem}"
|
||||
];
|
||||
|
||||
# Environment variables
|
||||
@ -35,6 +36,7 @@
|
||||
LOGOS_CPP_SDK_ROOT = "${logosSdk}";
|
||||
LOGOS_LIBLOGOS_ROOT = "${logosLiblogos}";
|
||||
LOGOS_STORAGE_ROOT = "${logosStorageModule}";
|
||||
LOGOS_DESIGN_SYSTEM_ROOT = "${logosDesignSystem}";
|
||||
};
|
||||
|
||||
# Metadata
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "StorageBackend.h"
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
@ -38,6 +39,10 @@ StorageBackend::~StorageBackend()
|
||||
LogosResult StorageBackend::init(const QString& configJson = "{}") {
|
||||
qDebug() << "StorageBackend::initStorage called";
|
||||
|
||||
if (configJson != "{}") {
|
||||
m_configJson = configJson;
|
||||
}
|
||||
|
||||
bool result = m_logos->storage_module.init(m_configJson);
|
||||
|
||||
qDebug() << "StorageBackend::initStorage: init";
|
||||
@ -57,9 +62,11 @@ LogosResult StorageBackend::init(const QString& configJson = "{}") {
|
||||
QString message = data[1].toString();
|
||||
setStatus(Stopped);
|
||||
debug("Failed to start Storage module:" + message);
|
||||
emit startFailed(message);
|
||||
} else {
|
||||
setStatus(Running);
|
||||
debug("Storage module started.");
|
||||
emit startCompleted();
|
||||
}
|
||||
})) {
|
||||
qWarning() << "StorageWidget: failed to subscribe to storageStart events";
|
||||
@ -75,8 +82,9 @@ LogosResult StorageBackend::init(const QString& configJson = "{}") {
|
||||
} else {
|
||||
setStatus(Stopped);
|
||||
debug("Storage module stopped.");
|
||||
emit stopped();
|
||||
}
|
||||
|
||||
emit stopCompleted();
|
||||
})) {
|
||||
qWarning() << "StorageWidget: failed to subscribe to storageStop events";
|
||||
}
|
||||
@ -183,10 +191,11 @@ LogosResult StorageBackend::init(const QString& configJson = "{}") {
|
||||
qWarning() << "StorageWidget: failed to subscribe to storageDownloadProgress events";
|
||||
}
|
||||
|
||||
m_configJson = configJson;
|
||||
emit configJsonChanged();
|
||||
|
||||
debug("config.json content is: " + m_configJson);
|
||||
if (configJson != "{}") {
|
||||
m_configJson = configJson;
|
||||
emit configJsonChanged();
|
||||
debug("new config is: " + m_configJson);
|
||||
}
|
||||
|
||||
return {true, ""};
|
||||
}
|
||||
@ -236,11 +245,13 @@ void StorageBackend::stop() {
|
||||
|
||||
if (m_status == StorageStatus::Stopping) {
|
||||
debug("The Storage Module is already stopping.");
|
||||
emit stopCompleted();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_status != StorageStatus::Running) {
|
||||
debug("The Storage Module is not started.");
|
||||
emit stopCompleted();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -698,6 +709,7 @@ QString StorageBackend::uploadStatus() const { return m_uploadStatus; }
|
||||
|
||||
void StorageBackend::reloadIfChanged(const QString& configJson) {
|
||||
if (configJson == m_configJson) {
|
||||
debug("No change detected in the config");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -753,4 +765,60 @@ void StorageBackend::reloadIfChanged(const QString& configJson) {
|
||||
|
||||
m_configJson = configJson;
|
||||
setStatus(StorageStatus::Stopped);
|
||||
emit configJsonChanged();
|
||||
}
|
||||
|
||||
bool StorageBackend::validateDataDir(const QString& path) {
|
||||
QFileInfo info(path);
|
||||
return info.exists() && info.isDir() && info.isReadable() && info.isWritable();
|
||||
}
|
||||
|
||||
QString StorageBackend::buildConfig(const QString& dataDir, int discPort, int tcpPort) {
|
||||
debug("StorageBackend::updateBasicConfig called with dataDir=" + dataDir);
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(m_configJson.toUtf8());
|
||||
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);
|
||||
}
|
||||
|
||||
QString StorageBackend::buildConfigFromFile(const QString& path) {
|
||||
qDebug() << "StorageBackend::buildConfigFromFile called";
|
||||
|
||||
QFile file(path);
|
||||
if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QString configJson = QString::fromUtf8(file.readAll());
|
||||
|
||||
debug("StorageUIPlugin: config.json is found, configJson=" + configJson);
|
||||
|
||||
return configJson;
|
||||
}
|
||||
|
||||
debug("StorageUIPlugin: Failed to load config.json");
|
||||
return "{}";
|
||||
}
|
||||
|
||||
void StorageBackend::status(StorageStatus status) { m_status = status; }
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "logos_api.h"
|
||||
#include "logos_sdk.h"
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
@ -10,11 +11,24 @@
|
||||
static const int RET_OK = 0;
|
||||
static const int RET_PROGRESS = 3;
|
||||
|
||||
// Add manual SPR from https://spr.codex.storage/devnet
|
||||
static const QStringList BOOTSTRAP_NODES = {
|
||||
"spr:CiUIAhIhA-VlcoiRm02KyIzrcTP-ljFpzTljfBRRKTIvhMIwqBqWEgIDARpJCicAJQgCEiED5WVyiJGbTYrIjOtxM_6WMWnNOWN8FFEpMi-"
|
||||
"EwjCoGpYQs8n8wQYaCwoJBHTKubmRAnU6GgsKCQR0yrm5kQJ1OipHMEUCIQDwUNsfReB4ty7JFS5WVQ6n1fcko89qVAOfQEHixa03rgIgan2-"
|
||||
"uFNDT-r4s9TOkLe9YBkCbsRWYCHGGVJ25rLj0QE",
|
||||
"spr:CiUIAhIhApIj9p6zJDRbw2NoCo-"
|
||||
"tj98Y760YbppRiEpGIE1yGaMzEgIDARpJCicAJQgCEiECkiP2nrMkNFvDY2gKj62P3xjvrRhumlGISkYgTXIZozMQvcz8wQYaCwoJBAWhF3WRAnVEG"
|
||||
"gsKCQQFoRd1kQJ1RCpGMEQCIFZB84O_nzPNuViqEGRL1vJTjHBJ-i5ZDgFL5XZxm4HAAiB8rbLHkUdFfWdiOmlencYVn0noSMRHzn4lJYoShuVzlw",
|
||||
"spr:CiUIAhIhApqRgeWRPSXocTS9RFkQmwTZRG-"
|
||||
"Cdt7UR2N7POoz606ZEgIDARpJCicAJQgCEiECmpGB5ZE9JehxNL1EWRCbBNlEb4J23tRHY3s86jPrTpkQj8_"
|
||||
"8wQYaCwoJBAXfEfiRAnVOGgsKCQQF3xH4kQJ1TipGMEQCIGWJMsF57N1iIEQgTH7IrVOgEgv0J2P2v3jvQr5Cjy-RAiAy4aiZ8QtyDvCfl_K_"
|
||||
"w6SyZ9csFGkRNTpirq_M_QNgKw"};
|
||||
|
||||
class StorageBackend : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(QString debugLogs READ debugLogs NOTIFY debugLogsChanged)
|
||||
Q_PROPERTY(StorageStatus status READ status NOTIFY statusChanged)
|
||||
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)
|
||||
@ -31,6 +45,8 @@ class StorageBackend : public QObject {
|
||||
int uploadProgress() const;
|
||||
QString uploadStatus() const;
|
||||
|
||||
Q_INVOKABLE static QString defaultDataDir();
|
||||
|
||||
explicit StorageBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr);
|
||||
~StorageBackend();
|
||||
|
||||
@ -54,13 +70,20 @@ class StorageBackend : public QObject {
|
||||
void downloadManifest(const QString& cid);
|
||||
void downloadManifests();
|
||||
void space();
|
||||
bool validateDataDir(const QString& path);
|
||||
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 buildConfigFromFile(const QString& path);
|
||||
|
||||
signals:
|
||||
void startCompleted();
|
||||
void startFailed(const QString& error);
|
||||
void statusChanged();
|
||||
void debugLogsChanged();
|
||||
void stopped();
|
||||
void stopCompleted();
|
||||
void cidChanged();
|
||||
void configJsonChanged();
|
||||
void uploadProgressChanged();
|
||||
@ -72,7 +95,6 @@ class StorageBackend : public QObject {
|
||||
void setStatus(StorageStatus newStatus);
|
||||
void peerConnect(const QString& peerId);
|
||||
void debug(const QString& log);
|
||||
void reloadIfChanged(const QString& configJson);
|
||||
|
||||
LogosAPI* m_logosAPI;
|
||||
LogosModules* m_logos;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "StorageUIPlugin.h"
|
||||
#include "StorageBackend.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
@ -7,14 +8,46 @@
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWidget>
|
||||
#include <QSettings>
|
||||
|
||||
QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) {
|
||||
qDebug() << "StorageUIPlugin::createWidget called";
|
||||
|
||||
QCoreApplication::setOrganizationName("Logos");
|
||||
QCoreApplication::setOrganizationDomain("logos.co");
|
||||
QCoreApplication::setApplicationName("LogosStorage");
|
||||
|
||||
QQuickWidget* quickWidget = new QQuickWidget();
|
||||
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
|
||||
QString qmlPath = "qrc:/StorageView.qml";
|
||||
// Add import path for Logos QML modules (Logos.Theme, Logos.Controls)
|
||||
QQmlEngine* engine = quickWidget->engine();
|
||||
QString qmlModulesPath = QCoreApplication::applicationDirPath() + "/../lib";
|
||||
engine->addImportPath(qmlModulesPath);
|
||||
|
||||
qDebug() << "StorageUIPlugin: Loading settings...";
|
||||
|
||||
QSettings settings("Logos", "LogosStorage");
|
||||
int discoveryPort = settings.value("Storage/discoveryPort", 0).toInt();
|
||||
int tcpPort = settings.value("Storage/tcpPort", 0).toInt();
|
||||
QString dataDir = settings.value("Storage/dataDir", "").toString();
|
||||
bool onboardingCompleted = settings.value("Storage/onboardingCompleted", false).toBool();
|
||||
|
||||
qDebug() << "StorageUIPlugin: Settings Loaded onboardingCompleted=" << onboardingCompleted;
|
||||
qDebug() << "StorageUIPlugin: Settings Loaded dataDir=" << dataDir;
|
||||
qDebug() << "StorageUIPlugin: Settings Loaded discoveryPort=" << discoveryPort;
|
||||
qDebug() << "StorageUIPlugin: Settings Loaded tcpPort=" << tcpPort;
|
||||
|
||||
QString qmlPath = "qrc:/Main.qml";
|
||||
|
||||
// Create backend instance
|
||||
StorageBackend* backend = new StorageBackend(logosAPI, quickWidget);
|
||||
|
||||
if (onboardingCompleted) {
|
||||
qmlPath = "qrc:/StorageView.qml";
|
||||
}
|
||||
|
||||
qDebug() << "StorageUIPlugin: qmlPath=" << qmlPath;
|
||||
|
||||
quickWidget->setSource(QUrl(qmlPath));
|
||||
|
||||
@ -22,41 +55,38 @@ QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) {
|
||||
qWarning() << "StorageUIPlugin: Failed to load QML:" << quickWidget->errors();
|
||||
}
|
||||
|
||||
// Create backend instance
|
||||
StorageBackend* backend = new StorageBackend(logosAPI, quickWidget);
|
||||
|
||||
// Set backend as context property
|
||||
QQuickItem* root = quickWidget->rootObject();
|
||||
Q_ASSERT(root);
|
||||
|
||||
root->setProperty("backend", QVariant::fromValue(static_cast<QObject*>(backend)));
|
||||
|
||||
QFileInfo info("config.json");
|
||||
QString configJson = "{}";
|
||||
|
||||
if (info.exists() && info.isFile()) {
|
||||
qDebug() << "StorageUIPlugin: config.json is found, let's try to load it...";
|
||||
|
||||
QFile file("config.json");
|
||||
if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
configJson = QString::fromUtf8(file.readAll());
|
||||
|
||||
qDebug() << "StorageUIPlugin: config.json is found, let's try to load it... configJson=" << configJson;
|
||||
} else {
|
||||
qDebug() << "StorageUIPlugin: Failed to load config.json";
|
||||
}
|
||||
if (onboardingCompleted) {
|
||||
configJson = backend->buildConfig(dataDir, discoveryPort, tcpPort);
|
||||
}
|
||||
|
||||
QFileInfo info("config.json");
|
||||
|
||||
if (info.exists() && info.isFile()) {
|
||||
qWarning()
|
||||
<< "StorageUIPlugin: config.json is found ! It will override the configuration loaded by the onboarding !";
|
||||
configJson = backend->buildConfigFromFile("config.json");
|
||||
}
|
||||
|
||||
qDebug() << "StorageUIPlugin: configuration loaded configLoaded=" << configJson;
|
||||
|
||||
LogosResult result = backend->init(configJson);
|
||||
|
||||
if (!result.success) {
|
||||
QString error = result.getError();
|
||||
qWarning() << "StorageUIPlugin: Failed to init backend, will use mock version:" << error;
|
||||
} else {
|
||||
result = backend->start();
|
||||
} else if (onboardingCompleted) {
|
||||
LogosResult result = backend->start();
|
||||
|
||||
if (!result.success) {
|
||||
qWarning() << "StorageUIPlugin: Failed to init backend, will use mock version:" << result.getError();
|
||||
qWarning() << "StorageUIPlugin: Failed to start the Storage Module.";
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +156,7 @@ void StorageUIPlugin::destroyWidget(QWidget* widget) {
|
||||
});
|
||||
|
||||
// Connect to stop signal
|
||||
QObject::connect(backend, &StorageBackend::stopped, &loop, [&]() { loop.quit(); }, Qt::QueuedConnection);
|
||||
QObject::connect(backend, &StorageBackend::stopCompleted, &loop, [&]() { loop.quit(); }, Qt::QueuedConnection);
|
||||
|
||||
// Call the stop method asynchronously
|
||||
QMetaObject::invokeMethod(backend, "stop", Qt::QueuedConnection);
|
||||
|
||||
@ -34,6 +34,23 @@ if(NOT DEFINED LOGOS_CPP_SDK_ROOT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED LOGOS_DESIGN_SYSTEM_ROOT)
|
||||
set(_parent_logos_design_system "${CMAKE_SOURCE_DIR}/../../../logos-design-system")
|
||||
set(_use_vendor ${LOGOS_STORAGE_UI_USE_VENDOR})
|
||||
|
||||
if(NOT _use_vendor)
|
||||
if(NOT EXISTS "${_parent_logos_design_system}/CMakeLists.txt")
|
||||
set(_use_vendor ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_use_vendor)
|
||||
set(LOGOS_DESIGN_SYSTEM_ROOT "${CMAKE_SOURCE_DIR}/../../vendor/logos-design-system")
|
||||
else()
|
||||
set(LOGOS_DESIGN_SYSTEM_ROOT "${_parent_logos_design_system}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Locate the logos_api header file.
|
||||
# If the file is found, the sdk is considered found.
|
||||
set(_cpp_sdk_found FALSE)
|
||||
@ -110,6 +127,26 @@ qt_add_qml_module(appqml
|
||||
../StorageBackend.h
|
||||
QML_FILES
|
||||
StorageView.qml
|
||||
OnBoarding.qml
|
||||
Main.qml
|
||||
StartNode.qml
|
||||
LogosTextField.qml
|
||||
LogosStorageButton.qml
|
||||
)
|
||||
|
||||
# Set up QML module directory for runtime
|
||||
set(DESIGN_SYSTEM_QML ${LOGOS_DESIGN_SYSTEM_ROOT}/src/qml)
|
||||
set(QML_THEME_DIR ${CMAKE_CURRENT_BINARY_DIR}/qml/Logos/Theme)
|
||||
set(QML_CONTROLS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qml/Logos/Controls)
|
||||
|
||||
# Copy QML module files to runtime directory
|
||||
# Pure QML module - no library, just QML files + qmldir
|
||||
add_custom_command(TARGET storage_generated POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QML_THEME_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${DESIGN_SYSTEM_QML}/theme/ ${QML_THEME_DIR}/
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QML_CONTROLS_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${DESIGN_SYSTEM_QML}/controls/ ${QML_CONTROLS_DIR}/
|
||||
COMMENT "Setting up Logos.Theme and Logos.Controls QML modules for the app"
|
||||
)
|
||||
|
||||
########### QML DEFINITION END ###########
|
||||
|
||||
39
src/qml/LogosStorageButton.qml
Normal file
39
src/qml/LogosStorageButton.qml
Normal file
@ -0,0 +1,39 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Logos.Theme
|
||||
|
||||
Button {
|
||||
id: control
|
||||
padding: Theme.spacing.small
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: Theme.typography.primaryText
|
||||
color: control.enabled ? Theme.palette.text : Theme.palette.textMuted
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: {
|
||||
if (!control.enabled)
|
||||
return Theme.palette.backgroundElevated
|
||||
if (control.hovered)
|
||||
return Theme.palette.backgroundTertiary
|
||||
return Theme.palette.backgroundSecondary
|
||||
}
|
||||
border.width: 1
|
||||
border.color: Theme.palette.border
|
||||
radius: Theme.spacing.tiny
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
27
src/qml/LogosTextField.qml
Normal file
27
src/qml/LogosTextField.qml
Normal file
@ -0,0 +1,27 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Logos.Theme
|
||||
|
||||
TextField {
|
||||
id: root
|
||||
|
||||
property bool isValid: acceptableInput && text.length > 0
|
||||
|
||||
placeholderTextColor: Theme.palette.textPlaceholder
|
||||
color: isValid ? Theme.palette.text : Theme.palette.error
|
||||
selectByMouse: true
|
||||
background: Rectangle {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Theme.palette.backgroundSecondary
|
||||
}
|
||||
|
||||
// Border bottom
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: root.isValid ? Theme.palette.textMuted : Theme.palette.error
|
||||
}
|
||||
}
|
||||
}
|
||||
136
src/qml/Main.qml
Normal file
136
src/qml/Main.qml
Normal file
@ -0,0 +1,136 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtCore
|
||||
import Logos.Theme
|
||||
import Logos.Controls
|
||||
|
||||
// qmllint disable unqualified
|
||||
Item {
|
||||
id: root
|
||||
implicitWidth: 600
|
||||
implicitHeight: 400
|
||||
|
||||
property var backend: mockBackend
|
||||
|
||||
Timer {
|
||||
readonly property int running: 2
|
||||
|
||||
id: timer
|
||||
interval: 2000
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
console.log("timer triggered")
|
||||
root.backend.status = running
|
||||
root.backend.startCompleted()
|
||||
console.info(root.backend.status)
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: mockBackend
|
||||
|
||||
property int status
|
||||
|
||||
signal startCompleted
|
||||
signal startFailed
|
||||
signal stopCompleted
|
||||
|
||||
function updateBasicConfig(dataDir, discPort) {
|
||||
console.log("updateBasicConfig", dataDir, discPort)
|
||||
}
|
||||
|
||||
function start() {
|
||||
timer.start()
|
||||
}
|
||||
|
||||
function stop() {
|
||||
root.backend.stopCompleted()
|
||||
}
|
||||
|
||||
function defaultDataDir() {
|
||||
return ".cache/storage"
|
||||
}
|
||||
|
||||
function buildConfig() {}
|
||||
|
||||
function reloadIfChanged() {}
|
||||
|
||||
function init() {}
|
||||
}
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
category: "Storage"
|
||||
|
||||
property int discoveryPort: 0
|
||||
property int tcpPort: 0
|
||||
property string dataDir: ""
|
||||
property bool onboardingCompleted: false
|
||||
|
||||
Component.onCompleted: {
|
||||
if (onboardingCompleted) {
|
||||
|
||||
// stackView.replace(storageView)
|
||||
// root.backend.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: stackView
|
||||
anchors.fill: parent
|
||||
initialItem: onboarding
|
||||
}
|
||||
|
||||
Component {
|
||||
id: onboarding
|
||||
|
||||
OnBoarding {
|
||||
id: onboardingInstance
|
||||
|
||||
onCompleted: {
|
||||
settings.discoveryPort = discoveryPort
|
||||
settings.dataDir = dataDir
|
||||
settings.tcpPort = tcpPort
|
||||
settings.onboardingCompleted = true
|
||||
|
||||
let config = root.backend.buildConfig(dataDir,
|
||||
discoveryPort, tcpPort)
|
||||
root.backend.reloadIfChanged(config)
|
||||
root.backend.start()
|
||||
|
||||
stackView.push(startNodeView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: storageView
|
||||
StorageView {
|
||||
backend: root.backend // @disable-check M228
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: startNodeView
|
||||
|
||||
StartNode {
|
||||
backend: root.backend
|
||||
|
||||
onBack: {
|
||||
root.backend.stop()
|
||||
}
|
||||
onNext: {
|
||||
stackView.push(storageView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
function onStopCompleted() {
|
||||
stackView.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
154
src/qml/OnBoarding.qml
Normal file
154
src/qml/OnBoarding.qml
Normal file
@ -0,0 +1,154 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Layouts
|
||||
import Logos.Theme
|
||||
import Logos.Controls
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: Theme.palette.background
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 600
|
||||
implicitHeight: 400
|
||||
|
||||
property int discoveryPort: 8090
|
||||
property int tcpPort: 0
|
||||
property var backend: mockBackend
|
||||
property string dataDir: backend.defaultDataDir()
|
||||
signal completed
|
||||
|
||||
QtObject {
|
||||
id: mockBackend
|
||||
|
||||
function validateDataDir(path) {
|
||||
return path != "error"
|
||||
}
|
||||
|
||||
function defaultDataDir() {
|
||||
return ".cache/storage"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacing.medium
|
||||
width: 400
|
||||
|
||||
LogosText {
|
||||
id: titleText
|
||||
font.pixelSize: Theme.typography.titleText
|
||||
text: "Logos Storage"
|
||||
// anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
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 {
|
||||
id: tcpPortColumn
|
||||
spacing: Theme.spacing.tiny
|
||||
Layout.fillWidth: true
|
||||
|
||||
LogosText {
|
||||
text: "TCP port"
|
||||
font.pixelSize: Theme.typography.secondaryText
|
||||
color: Theme.palette.text
|
||||
}
|
||||
|
||||
LogosTextField {
|
||||
isValid: acceptableInput && text.length > 0
|
||||
id: tcpPortTextField
|
||||
placeholderText: "Enter the TCP port"
|
||||
text: root.tcpPort
|
||||
validator: IntValidator {
|
||||
bottom: 0
|
||||
top: 65535
|
||||
}
|
||||
onTextChanged: {
|
||||
if (isValid) {
|
||||
root.tcpPort = parseInt(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Theme.spacing.tiny
|
||||
Layout.fillWidth: true
|
||||
|
||||
LogosText {
|
||||
text: "Data dir"
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Theme.spacing.tiny
|
||||
|
||||
LogosTextField {
|
||||
id: dataDirTextField
|
||||
placeholderText: "Enter the data dir"
|
||||
text: root.dataDir
|
||||
Layout.fillWidth: true
|
||||
onTextChanged: {
|
||||
if (text.length > 0) {
|
||||
isValid = root.backend.validateDataDir(text)
|
||||
} else {
|
||||
isValid = false
|
||||
}
|
||||
|
||||
root.dataDir = text
|
||||
}
|
||||
}
|
||||
|
||||
LogosStorageButton {
|
||||
text: "Choose"
|
||||
onClicked: folderDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
FolderDialog {
|
||||
id: folderDialog
|
||||
onAccepted: {
|
||||
dataDirTextField.text = selectedFolder
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogosStorageButton {
|
||||
text: "Next"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.bottomMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
enabled: discoveryPortTextField.acceptableInput
|
||||
&& tcpPortTextField.acceptableInput && dataDirTextField.isValid
|
||||
onClicked: root.completed()
|
||||
}
|
||||
}
|
||||
78
src/qml/StartNode.qml
Normal file
78
src/qml/StartNode.qml
Normal file
@ -0,0 +1,78 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Logos.Controls
|
||||
import Logos.Theme
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: Theme.palette.background
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 600
|
||||
implicitHeight: 400
|
||||
|
||||
property var backend
|
||||
property string status: ""
|
||||
property bool starting: true
|
||||
property bool success: false
|
||||
|
||||
signal back
|
||||
signal next
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
function onStartCompleted() {
|
||||
console.log("onStartCompleted received")
|
||||
root.starting = false
|
||||
root.status = "Logos Storage started successfully."
|
||||
root.success = true
|
||||
}
|
||||
|
||||
function onStartFailed(error) {
|
||||
console.log("onStartFailed received")
|
||||
root.starting = false
|
||||
root.status = "Failed to start: " + error
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacing.medium
|
||||
width: 400
|
||||
|
||||
LogosText {
|
||||
id: titleText
|
||||
font.pixelSize: Theme.typography.titleText
|
||||
text: "Starting your node...."
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
LogosText {
|
||||
id: statusText
|
||||
font.pixelSize: Theme.typography.primaryText
|
||||
text: root.status
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
LogosStorageButton {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.bottomMargin: 10
|
||||
anchors.leftMargin: 10
|
||||
text: "Back"
|
||||
onClicked: root.back()
|
||||
enabled: root.starting == false
|
||||
}
|
||||
|
||||
LogosStorageButton {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.bottomMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
text: "Next"
|
||||
onClicked: root.next()
|
||||
enabled: root.success == true
|
||||
}
|
||||
}
|
||||
@ -5,8 +5,10 @@ import QtQuick.Layouts
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 400
|
||||
height: 700
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: 600
|
||||
implicitHeight: 400
|
||||
color: "#000000"
|
||||
|
||||
property var backend: mockBackend
|
||||
@ -538,6 +540,7 @@ Rectangle {
|
||||
color: "#d4d4d4"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
wrapMode: Text.WrapAnywhere
|
||||
|
||||
background: Rectangle {
|
||||
color: "#1e1e1e"
|
||||
|
||||
@ -5,10 +5,18 @@
|
||||
int main(int argc, char* argv[]) {
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QCoreApplication::setOrganizationName("Logos");
|
||||
QCoreApplication::setOrganizationDomain("logos.co");
|
||||
QCoreApplication::setApplicationName("LogosStorage");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
QObject::connect(
|
||||
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
|
||||
engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml");
|
||||
engine.loadFromModule("StorageBackend", "OnBoarding");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="Main.qml">qml/Main.qml</file>
|
||||
<file alias="StartNode.qml">qml/StartNode.qml</file>
|
||||
<file alias="OnBoarding.qml">qml/OnBoarding.qml</file>
|
||||
<file alias="StorageView.qml">qml/StorageView.qml</file>
|
||||
<file alias="LogosTextField.qml">qml/LogosTextField.qml</file>
|
||||
<file alias="LogosStorageButton.qml">qml/LogosStorageButton.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user