Move files for QML architecture

This commit is contained in:
Arnaud 2026-01-30 21:15:18 +04:00
parent aca1eeed0b
commit 4df4f78694
No known key found for this signature in database
GPG Key ID: 20E40A5D3110766F
17 changed files with 549 additions and 310 deletions

View File

@ -12,17 +12,15 @@
"build": {
"type": "cmake",
"files": [
"src/storage_ui_plugin.cpp",
"src/storage_ui_plugin.h",
"src/storagewindow.cpp",
"src/storagewindow.h",
"src/storagewidget.cpp",
"src/storagewidget.h",
"src/storage_ui_resources.qrc"
"src/StorageUIPlugin.cpp",
"src/StorageUIPlugin.h",
"src/StorageBackend.cpp",
"src/StorageBackend.h",
"src/storage_resources.qrc"
]
},
"capabilities": [
"ui_components",
"storage"
]
}
}

View File

@ -1,44 +0,0 @@
#include "StorageUIPlugin.h"
#include "src/StorageBackend.h"
#include <QQuickWidget>
#include <QQmlContext>
#include <QQmlEngine>
#include <QDebug>
#include <QFileInfo>
#include <QFile>
QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) {
qDebug() << "StorageUIPlugin::createWidget called";
QQuickWidget* quickWidget = new QQuickWidget();
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
// Register StorageBackend type with QML engine to expose the enum
qmlRegisterType<StorageBackend>("StorageBackend", 1, 0, "StorageBackend");
// Create backend instance
StorageBackend* backend = new StorageBackend(logosAPI, quickWidget);
// Set backend as context property
quickWidget->rootContext()->setContextProperty("backend", backend);
// For development: check environment variable, otherwise use qrc
QString qmlPath = "qrc:/StorageView.qml";
QString envPath = qgetenv("STORAGE_UI_QML_PATH");
if (!envPath.isEmpty() && QFile::exists(envPath)) {
qmlPath = QUrl::fromLocalFile(QFileInfo(envPath).absoluteFilePath()).toString();
qDebug() << "Loading QML from file system:" << qmlPath;
}
quickWidget->setSource(QUrl(qmlPath));
if (quickWidget->status() == QQuickWidget::Error) {
qWarning() << "StorageUIPlugin: Failed to load QML:" << quickWidget->errors();
}
return quickWidget;
}
void StorageUIPlugin::destroyWidget(QWidget* widget) {
delete widget;
}

View File

@ -1,38 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import StorageBackend
Item {
id: root
Rectangle {
anchors.fill: parent
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.topMargin: 0
anchors.bottomMargin: 0
color: "#202428"
}
Text {
text: qsTr("Storage UI")
color: "black"
anchors.centerIn: parent
font.pointSize: 20
}
Text {
objectName: "status"
text: "..."
color: "white"
font.pointSize: 20
anchors.topMargin: 32
}
Button {
objectName: "startButton"
anchors.leftMargin: 50
text: "Stop"
}
}

View File

@ -1,97 +0,0 @@
#include "StorageBackend.h"
#include <QDebug>
#include <QDateTime>
#include <QLocale>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
StorageBackend::StorageBackend(LogosAPI* logosAPI, QObject* parent)
: QObject(parent),
m_status(NotStarted),
m_logosAPI(nullptr),
m_logos(nullptr)
{
qDebug() << "Initializing StorageBackend...";
if (logosAPI) {
m_logosAPI = logosAPI;
} else {
m_logosAPI = new LogosAPI("core", this);
}
m_logos = new LogosModules(m_logosAPI);
}
StorageBackend::~StorageBackend()
{
stopStorage();
}
void StorageBackend::setStatus(StorageStatus newStatus)
{
if (m_status != newStatus) {
m_status = newStatus;
emit statusChanged();
qDebug() << "StorageBackend: Status changed to" << m_status;
}
}
void StorageBackend::startStorage()
{
setStatus(Starting);
auto& storageModule = m_logos->storage_module;
QString configStr = R"({
})";
if (!storageModule.initStorage(configStr)) {
setStatus(Error);
return;
}
// Subscribe to connectedPeersResponse events
// if (!storageModule.on("connectedPeersResponse", [this](const QVariantList& data) {
// if (data.size() < 1) {
// qWarning() << "StorageBackend: connectedPeersResponse payload missing fields";
// return;
// }
// onConnectedPeersResponse(data);
// })) {
// qWarning() << "StorageBackend: failed to subscribe to connectedPeersResponse events";
// }
if (!storageModule.startStorage()) {
setStatus(Error);
return;
}
setStatus(Running);
// Refresh peers and metrics after a delay to allow Storage to fully start
// QTimer::singleShot(1000, this, [this]() {
// refreshPeers();
// refreshMetrics();
// });
}
void StorageBackend::stopStorage()
{
if (m_status != Running && m_status != Starting) {
return;
}
setStatus(Stopping);
auto& storageModule = m_logos->storage_module;
if (!storageModule.stopStorage()) {
qWarning() << "StorageBackend::stopStorage: stopStorage() returned false";
setStatus(Error);
return;
}
setStatus(Stopped);
}

View File

@ -1,48 +0,0 @@
#pragma once
#include <QObject>
#include <QString>
#include <QStringList>
#include <QTimer>
#include "logos_api.h"
#include "logos_api_client.h"
#include "logos_sdk.h"
class StorageBackend : public QObject {
Q_OBJECT
public:
enum StorageStatus {
NotStarted = 0,
Starting,
Running,
Stopping,
Stopped,
Error
};
Q_ENUM(StorageStatus)
Q_PROPERTY(StorageStatus status READ status NOTIFY statusChanged)
explicit StorageBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr);
~StorageBackend();
StorageStatus status() const { return m_status; }
public slots:
Q_INVOKABLE void startStorage();
Q_INVOKABLE void stopStorage();
signals:
void statusChanged();
private slots:
// void onConnectedPeersResponse(const QVariantList& data);
private:
void setStatus(StorageStatus newStatus);
StorageStatus m_status;
LogosAPI* m_logosAPI;
LogosModules* m_logos;
};

View File

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/">
<file>StorageView.qml</file>
</qresource>
</RCC>

View File

@ -1,42 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(qml VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Quick)
qt_standard_project_setup(REQUIRES 6.8)
qt_add_executable(appqml
main.cpp
)
qt_add_qml_module(appqml
URI qml
VERSION 1.0
QML_FILES
Main.qml
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(appqml PROPERTIES
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appqml
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
target_link_libraries(appqml
PRIVATE Qt6::Quick
)
include(GNUInstallDirs)
install(TARGETS appqml
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@ -1,8 +0,0 @@
import QtQuick
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
}

156
src/StorageBackend.cpp Normal file
View File

@ -0,0 +1,156 @@
#include "StorageBackend.h"
#include <QDateTime>
#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLocale>
StorageBackend::StorageBackend(LogosAPI* logosAPI, QObject* parent)
: QObject(parent), m_status(Destroyed), m_logosAPI(nullptr), m_logos(nullptr) {
qDebug() << "Initializing StorageBackend...";
if (logosAPI) {
m_logosAPI = logosAPI;
} else {
m_logosAPI = new LogosAPI("core", this);
}
m_logos = new LogosModules(m_logosAPI);
initStorage();
}
StorageBackend::~StorageBackend()
{
m_logosAPI = nullptr;
m_logos = nullptr;
}
void StorageBackend::initStorage() {
qDebug() << "StorageBackend::initStorage called";
bool result = m_logos->storage_module.init("{}");
qDebug() << "StorageBackend::initStorage: init result =" << result;
if (!result) {
qDebug() << "StorageBackend: Failed to initialise Storage module.";
setStatus(Destroyed, "Failed to initialise Storage module.");
return;
}
setStatus(Stopped, "Storage module ready.");
if (!m_logos->storage_module.on("storageStart", [this](const QVariantList& data) {
int code = data[0].toInt();
if (code != RET_OK) {
qDebug() << "StorageBackend: storageStart event failure with code" << code;
setStatus(Stopped, "Failed to start Storage module.");
} else {
qDebug() << "StorageBackend: storageStart event success";
setStatus(Running, "Storage module started.");
}
})) {
qWarning() << "StorageWidget: failed to subscribe to storageStart events";
}
if (!m_logos->storage_module.on("storageStop", [this](const QVariantList& data) {
int code = data[0].toInt();
if (code != RET_OK) {
qDebug() << "StorageBackend: storageStop event failure with code" << code;
setStatus(Running, "Failed to stop Storage module.");
} else {
qDebug() << "StorageBackend: storageStop event success";
setStatus(Stopped, "Storage module stopped.");
emit stopped();
}
})) {
qWarning() << "StorageWidget: failed to subscribe to storageStop events";
}
startStop();
}
void StorageBackend::setStatus(StorageStatus newStatus, QString statusText) {
if (m_status != newStatus || m_statusText != statusText) {
m_status = newStatus;
m_statusText = statusText;
emit statusChanged();
qDebug() << "StorageBackend: Status changed to" << m_status;
}
}
void StorageBackend::startStop() {
qDebug() << "StorageBackend: startStop method called";
if (m_status == Destroyed || m_status == Starting || m_status == Stopping) {
qDebug() << "StorageBackend: Cannot start/stop Storage in current state:" << m_status;
return;
}
if (m_status != Running) {
qDebug() << "StorageBackend: Starting Storage...";
setStatus(Starting, "Starting Storage module...");
bool result = m_logos->storage_module.start();
if (!result) {
qDebug() << "StorageBackend: Failed to start Storage.";
setStatus(Stopped, "Failed to start Storage module.");
return;
}
qDebug() << "StorageBackend: start command sent, waiting for events.";
} else {
stop();
}
}
void StorageBackend::stop() {
qDebug() << "StorageBackend: Stopping Storage...";
setStatus(Stopping, "Stopping Storage module...");
bool result = m_logos->storage_module.stop();
if (!result) {
qDebug() << "StorageBackend: Failed to stop Storage.";
setStatus(Running, "Failed to stop Storage module.");
return;
}
qDebug() << "StorageBackend: stop command sent, waiting for events.";
}
void StorageBackend::destroy() {
qDebug() << "StorageBackend: destroy method called";
StorageStatus status = m_status;
int result = m_logos->storage_module.destroy();
if (!result) {
qDebug() << "StorageBackend: Failed to destroy Storage module." << result;
setStatus(status, "Failed to destroy Storage module.");
return;
}
qDebug() << "StorageBackend: Storage module destroyed.";
}
QString StorageBackend::statusText() const { return m_statusText; }
QString StorageBackend::startStopText() const {
if (m_status != Running) {
return "Start";
} else {
return "Stop";
}
}
bool StorageBackend::canStartStop() const { return m_status == Running || m_status == Stopped; }
bool StorageBackend::isRunning() { return m_status == Running; }
bool StorageBackend::isInitialised() { return m_status != Destroyed; }

54
src/StorageBackend.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "logos_api.h"
#include "logos_sdk.h"
#include <QObject>
#include <QString>
#include <QStringList>
#include <QTimer>
#include <QtQml/qqml.h>
static const int RET_OK = 0;
class StorageBackend : public QObject {
Q_OBJECT
QML_ELEMENT
public:
enum StorageStatus { Stopped = 0, Starting, Running, Stopping, Destroyed };
Q_ENUM(StorageStatus)
Q_PROPERTY(bool canStartStop READ canStartStop NOTIFY statusChanged)
bool canStartStop() const;
Q_PROPERTY(QString startStopText READ startStopText NOTIFY statusChanged)
QString startStopText() const;
Q_PROPERTY(QString statusText READ statusText NOTIFY statusChanged)
QString statusText() const;
explicit StorageBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr);
~StorageBackend();
public slots:
void startStop();
void destroy();
bool isRunning();
bool isInitialised();
void stop();
signals:
void statusChanged();
void stopped();
private slots:
private:
void setStatus(StorageStatus newStatus, QString statusText);
void initStorage();
StorageStatus m_status;
LogosAPI* m_logosAPI;
LogosModules* m_logos;
QString m_statusText;
};

115
src/StorageUIPlugin.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "StorageUIPlugin.h"
#include "StorageBackend.h"
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
#include <QQuickWidget>
QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) {
qDebug() << "StorageUIPlugin::createWidget called";
QQuickWidget* quickWidget = new QQuickWidget();
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
QString qmlPath = "qrc:/StorageView.qml";
quickWidget->setSource(QUrl(qmlPath));
if (quickWidget->status() == QQuickWidget::Error) {
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)));
return quickWidget;
}
// Destroy the widget and clean up the backend.
// It will block the event loop up to 2 seconds to ensure proper cleanup.
// It will try to stop the backend if it is running.`
void StorageUIPlugin::destroyWidget(QWidget* widget) {
qDebug() << "StorageUIPlugin: Destroy widget";
auto* quickWidget = qobject_cast<QQuickWidget*>(widget);
if (!quickWidget) {
delete widget;
return;
}
QQuickItem* root = quickWidget->rootObject();
if (!root) {
qWarning() << "StorageUIPlugin::destroyWidget: No rootObject, deleting widget";
quickWidget->deleteLater();
return;
}
// Disable QML to ensure that not updated are pushed in the UI
root->setEnabled(false);
// Retrieve the backend object from the root element
// as it was set in createWidget
QObject* value = root->property("backend").value<QObject*>();
auto* backend = qobject_cast<StorageBackend*>(value);
if (!backend) {
qWarning() << "StorageUIPlugin::destroyWidget: No backend found on root property 'backend'.";
quickWidget->deleteLater();
return;
}
if (!backend->isInitialised()) {
qDebug() << "StorageUIPlugin::destroyWidget: backend is not initialised so let's detroy it.";
quickWidget->deleteLater();
return;
}
if (!backend->isRunning()) {
qDebug() << "StorageUIPlugin::destroyWidget: backend is not running so let's detroy it.";
backend->destroy();
quickWidget->deleteLater();
return;
}
qDebug() << "StorageUIPlugin::destroyWidget: backend is running so let's stop it.";
// Here we create a QEventLoop to wait for the stopped signal
QEventLoop loop;
QTimer timeout;
// Single shot means that the timer will only fire once.
timeout.setSingleShot(true);
// Connect to timeout and unblock the event loop after 2 seconds
QObject::connect(&timeout, &QTimer::timeout, &loop, [&]() {
qWarning() << "StorageUIPlugin::destroyWidget: stop timeout";
loop.quit();
});
// Connect to stop signal
QObject::connect(backend, &StorageBackend::stopped, &loop, [&]() { loop.quit(); }, Qt::QueuedConnection);
// Call the stop method asynchronously
QMetaObject::invokeMethod(backend, "stop", Qt::QueuedConnection);
// Set the timeout to 2 sec
timeout.start(2000);
// Block
loop.exec();
// Try to cleanup, event if the stop method failed
backend->destroy();
delete quickWidget;
}

View File

@ -10,5 +10,5 @@ class StorageUIPlugin : public QObject, public IComponent {
public:
Q_INVOKABLE QWidget* createWidget(LogosAPI* logosAPI = nullptr) override;
void destroyWidget(QWidget* widget) override;
};
Q_INVOKABLE void destroyWidget(QWidget* widget) override;
};

View File

@ -1,17 +0,0 @@
#include <QApplication>
#include <QDebug>
#include "StorageWindow.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
qDebug() << "Starting Storage Qt Application";
// Create and show the main window
StorageWindow mainWindow;
mainWindow.setWindowTitle("Logos Storage App");
mainWindow.resize(800, 600);
mainWindow.show();
return app.exec();
}

147
src/qml/CMakeLists.txt Normal file
View File

@ -0,0 +1,147 @@
cmake_minimum_required(VERSION 3.16)
project(qml VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
########### DEPENDENCIES ###########
# This section locates the required dependencies in 3 different ways:
# 1- With NIX, the root folders (LOGOS_LIBLOGOS_ROOT, LOGOS_CPP_SDK_ROO)
# are defined and point to the correct locations in
# the Nix store.
# 2- If the root folders are fetched from source (basically using git) in the
# parent folder, this is detected and used.
# 3- If none of the above apply, the vendor folders inside this project are used,
# meaning the dependencies need to be fetched using git submodules.
# Locate logos-cpp-sdk
if(NOT DEFINED LOGOS_CPP_SDK_ROOT)
set(_parent_cpp_sdk "${CMAKE_SOURCE_DIR}/../../../logos-cpp-sdk")
set(_use_vendor ${LOGOS_STORAGE_UI_USE_VENDOR})
if(NOT _use_vendor)
if(NOT EXISTS "${_parent_cpp_sdk}/cpp/logos_api.h")
set(_use_vendor ON)
endif()
endif()
if(_use_vendor)
set(LOGOS_CPP_SDK_ROOT "${CMAKE_SOURCE_DIR}/../../vendor/logos-cpp-sdk")
else()
set(LOGOS_CPP_SDK_ROOT "${_parent_cpp_sdk}")
endif()
endif()
# Locate the logos_api header file.
# If the file is found, the sdk is considered found.
set(_cpp_sdk_found FALSE)
if(EXISTS "${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.h")
set(_cpp_sdk_found TRUE)
set(_cpp_sdk_is_source TRUE)
elseif(EXISTS "${LOGOS_CPP_SDK_ROOT}/include/cpp/logos_api.h")
set(_cpp_sdk_found TRUE)
set(_cpp_sdk_is_source FALSE)
endif()
# Fails if the SDK is not found.
if(NOT _cpp_sdk_found)
message(FATAL_ERROR
"logos-cpp-sdk not found at ${LOGOS_CPP_SDK_ROOT}. "
"Set LOGOS_CPP_SDK_ROOT or run git submodule update --init --recursive."
)
endif()
########### DEPENDENCIES END ###########
########### QML DEFINITION ###########
set(PLUGIN_UI_BUILD_DIR "../../build/generated_code")
list(APPEND SOURCES
${PLUGIN_UI_BUILD_DIR}/logos_sdk.cpp
)
# Create a library with the Logos SDK and generated sources to keep them separate
add_library(storage_generated STATIC
${PLUGIN_UI_BUILD_DIR}/logos_sdk.cpp
${PLUGIN_UI_BUILD_DIR}/storage_module_api.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_client.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/module_proxy.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/token_manager.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_consumer.cpp
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.cpp
)
# Define the dependencies needed for storage_generated
target_link_libraries(storage_generated PUBLIC
Qt6::Core
Qt6::RemoteObjects
)
# Discover the required dependencies
find_package(Qt6 REQUIRED COMPONENTS Quick RemoteObjects)
# Standard project setup for Qt applications
qt_standard_project_setup(REQUIRES 6.8)
# Add the Qt Quick application executable
qt_add_executable(appqml
main.cpp
)
# Use these required dependencies.
target_link_libraries(appqml PRIVATE
Qt6::Quick
Qt6::Qml
storage_generated
)
# Define the qml module and the StorageBackend sources.
qt_add_qml_module(appqml
URI StorageBackend
VERSION 1.0
SOURCES
../src/StorageBackend.cpp
../src/StorageBackend.h
QML_FILES
StorageView.qml
)
########### QML DEFINITION END ###########
########### HEADERS ###########
target_include_directories(storage_generated PUBLIC
"${PLUGIN_UI_BUILD_DIR}"
"${PLUGIN_UI_BUILD_DIR}/include"
)
# Include directories
if(_cpp_sdk_is_source)
target_include_directories(storage_generated PUBLIC
${LOGOS_CPP_SDK_ROOT}/cpp
${LOGOS_CPP_SDK_ROOT}/cpp/generated
)
else()
target_include_directories(storage_generated PUBLIC
${LOGOS_CPP_SDK_ROOT}/include
${LOGOS_CPP_SDK_ROOT}/include/cpp
${LOGOS_CPP_SDK_ROOT}/include/core
${PLUGIN_UI_BUILD_DIR}/include
)
endif()
# Import the application headers.
target_include_directories(appqml PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../src
${PLUGINS_OUTPUT_DIR}
)
########### HEADERS END ###########
message(STATUS "Qt Quick app configured successfully")

63
src/qml/StorageView.qml Normal file
View File

@ -0,0 +1,63 @@
import QtQuick
import QtQuick.Controls
//import QtQuick.Layouts
Item {
property var backend: mockBackend
readonly property int stopped: 0
readonly property int starting: 1
readonly property int running: 2
readonly property int stopping: 3
readonly property int destroyed: 4
id: root
width: 400
height: 300
QtObject {
id: mockBackend
property var status: root.stopped
property var statusText: "Destroyed"
property var startStopText: "Start"
property var canStartStop: true
function startStop() {
if (status == root.running) {
status = root.stopped
statusText = "Stopped"
startStopText = "Start"
} else {
status = root.running
statusText = "Started"
startStopText = "Stop"
}
}
}
Rectangle {
anchors.fill: parent
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.topMargin: 0
anchors.bottomMargin: 0
color: "#202428"
}
Text {
objectName: "status"
text: root.backend.statusText
color: "white"
font.pointSize: 20
anchors.centerIn: parent
anchors.topMargin: 0
}
Button {
objectName: "startStopButton"
anchors.leftMargin: 50
text: root.backend.startStopText
enabled: root.backend.canStartStop
onClicked: root.backend.startStop()
}
}

View File

@ -1,5 +1,6 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
int main(int argc, char* argv[]) {
QGuiApplication app(argc, argv);
@ -8,7 +9,6 @@ int main(int argc, char* argv[]) {
QObject::connect(
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.loadFromModule("qml", "Main");
return app.exec();
}

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file alias="StorageView.qml">qml/StorageView.qml</file>
</qresource>
</RCC>