commit da055ad72ed45c916057af04208dd4ea7b8ddc83 Author: Khushboo Mehta Date: Wed Feb 11 20:39:32 2026 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de7c99f --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +build/ +result +*.dylib +*.so +*.dll +*.a +CMakeCache.txt +CMakeFiles/ +*.cmake +generated_code/ +db/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..43bd1da --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,273 @@ +cmake_minimum_required(VERSION 3.16) +project(BlockchainUIPlugin VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +# Allow override from environment or command line +if(NOT DEFINED LOGOS_LIBLOGOS_ROOT) + set(_parent_liblogos "${CMAKE_SOURCE_DIR}/../logos-liblogos") + set(_use_vendor ${LOGOS_BLOCKCHAIN_UI_USE_VENDOR}) + if(NOT _use_vendor) + if(NOT EXISTS "${_parent_liblogos}/interface.h") + set(_use_vendor ON) + endif() + endif() + if(_use_vendor) + set(LOGOS_LIBLOGOS_ROOT "${CMAKE_SOURCE_DIR}/vendor/logos-liblogos") + else() + set(LOGOS_LIBLOGOS_ROOT "${_parent_liblogos}") + endif() +endif() + +if(NOT DEFINED LOGOS_CPP_SDK_ROOT) + set(_parent_cpp_sdk "${CMAKE_SOURCE_DIR}/../logos-cpp-sdk") + set(_use_vendor ${LOGOS_BLOCKCHAIN_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() + +# Check if dependencies are available (support both source and installed layouts) +set(_liblogos_found FALSE) +if(EXISTS "${LOGOS_LIBLOGOS_ROOT}/interface.h") + set(_liblogos_found TRUE) + set(_liblogos_is_source TRUE) +elseif(EXISTS "${LOGOS_LIBLOGOS_ROOT}/include/interface.h") + set(_liblogos_found TRUE) + set(_liblogos_is_source FALSE) +endif() + +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() + +if(NOT _liblogos_found) + message(FATAL_ERROR "logos-liblogos not found at ${LOGOS_LIBLOGOS_ROOT}. " + "Set LOGOS_LIBLOGOS_ROOT or run git submodule update --init --recursive.") +endif() + +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() + +# Find Qt packages +find_package(Qt6 REQUIRED COMPONENTS Core Widgets RemoteObjects Quick QuickWidgets) + +# Get the real path to handle symlinks correctly +get_filename_component(REAL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH) + +# Try to find the component-interfaces package first +find_package(component-interfaces QUIET) + +# If not found, use the local interfaces folder +if(NOT component-interfaces_FOUND) + # Include the local interfaces directory + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces) + + # Create a component-interfaces library + add_library(component-interfaces INTERFACE) + target_include_directories(component-interfaces INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/interfaces) +endif() + +# Source files +set(SOURCES + src/BlockchainPlugin.cpp + src/BlockchainPlugin.h + src/BlockchainBackend.cpp + src/BlockchainBackend.h + src/LogModel.cpp + src/LogModel.h + src/blockchain_resources.qrc +) + +# Add SDK sources (only if source layout, installed layout uses the library) +if(_cpp_sdk_is_source) + list(APPEND SOURCES + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.h + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_client.cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_client.h + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_consumer.cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_consumer.h + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.h + ${LOGOS_CPP_SDK_ROOT}/cpp/token_manager.cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/token_manager.h + ${LOGOS_CPP_SDK_ROOT}/cpp/module_proxy.cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/module_proxy.h + ) +endif() + +# Run Logos C++ generator on metadata before compilation (only for source layout) +set(METADATA_JSON "${CMAKE_CURRENT_SOURCE_DIR}/metadata.json") + +# Only run generator for source layout - nix builds already have generated files +if(_cpp_sdk_is_source) + # Source layout: build and run the generator + # Generate into build directory + set(PLUGINS_OUTPUT_DIR "${CMAKE_BINARY_DIR}/generated_code") + set(CPP_GENERATOR_BUILD_DIR "${LOGOS_CPP_SDK_ROOT}/../build/cpp-generator") + set(CPP_GENERATOR "${CPP_GENERATOR_BUILD_DIR}/bin/logos-cpp-generator") + + if(NOT TARGET cpp_generator_build) + add_custom_target(cpp_generator_build + COMMAND bash "${LOGOS_CPP_SDK_ROOT}/cpp-generator/compile.sh" + WORKING_DIRECTORY "${LOGOS_CPP_SDK_ROOT}/.." + COMMENT "Building logos-cpp-generator via ${LOGOS_CPP_SDK_ROOT}/cpp-generator/compile.sh" + VERBATIM + ) + endif() + + add_custom_target(run_cpp_generator_blockchain_ui + COMMAND "${CPP_GENERATOR}" --metadata "${METADATA_JSON}" --general-only --output-dir "${PLUGINS_OUTPUT_DIR}" + WORKING_DIRECTORY "${LOGOS_CPP_SDK_ROOT}/.." + COMMENT "Running logos-cpp-generator on ${METADATA_JSON} with output-dir ${PLUGINS_OUTPUT_DIR}" + VERBATIM + ) + add_dependencies(run_cpp_generator_blockchain_ui cpp_generator_build) + + # Add generated logos_sdk.cpp - will be generated by run_cpp_generator_blockchain_ui + list(APPEND SOURCES ${PLUGINS_OUTPUT_DIR}/logos_sdk.cpp) + # Mark as generated so CMake knows to wait for it + set_source_files_properties( + ${PLUGINS_OUTPUT_DIR}/logos_sdk.cpp + PROPERTIES GENERATED TRUE + ) +else() + # Installed/nix layout: lib.nix preConfigure populates generated_code before CMake. + # May be overridden by -DPLUGINS_OUTPUT_DIR= when source tree is read-only (e.g. Nix sandbox). + set(PLUGINS_OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated_code" CACHE PATH "Generated code directory (nix layout)") + list(APPEND SOURCES ${PLUGINS_OUTPUT_DIR}/include/logos_sdk.cpp) +endif() + +# Create the plugin library +add_library(blockchain_ui SHARED ${SOURCES}) + +# Set output name without lib prefix and with correct name for generator +set_target_properties(blockchain_ui PROPERTIES + PREFIX "" + OUTPUT_NAME "blockchain_ui" +) + +# Ensure generator runs before building the plugin (only for source layout) +if(_cpp_sdk_is_source) + add_dependencies(blockchain_ui run_cpp_generator_blockchain_ui) +endif() + +# Include directories +target_include_directories(blockchain_ui PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR} + ${PLUGINS_OUTPUT_DIR} +) + +# Add include directories based on layout type +if(_liblogos_is_source) + target_include_directories(blockchain_ui PRIVATE ${LOGOS_LIBLOGOS_ROOT}) +else() + target_include_directories(blockchain_ui PRIVATE ${LOGOS_LIBLOGOS_ROOT}/include) +endif() + +if(_cpp_sdk_is_source) + target_include_directories(blockchain_ui PRIVATE + ${LOGOS_CPP_SDK_ROOT}/cpp + ${LOGOS_CPP_SDK_ROOT}/cpp/generated + ) +else() + # For nix builds, also include the include subdirectory + # (lib.nix moves header files to ./generated_code/include/) + target_include_directories(blockchain_ui PRIVATE + ${LOGOS_CPP_SDK_ROOT}/include + ${LOGOS_CPP_SDK_ROOT}/include/cpp + ${LOGOS_CPP_SDK_ROOT}/include/core + ${PLUGINS_OUTPUT_DIR}/include + ) +endif() + +# Link against libraries +target_link_libraries(blockchain_ui PRIVATE + Qt6::Core + Qt6::Widgets + Qt6::RemoteObjects + Qt6::Quick + Qt6::QuickWidgets + component-interfaces +) + +# Link SDK library if using installed layout +if(NOT _cpp_sdk_is_source) + find_library(LOGOS_SDK_LIB logos_sdk PATHS ${LOGOS_CPP_SDK_ROOT}/lib NO_DEFAULT_PATH REQUIRED) + target_link_libraries(blockchain_ui PRIVATE ${LOGOS_SDK_LIB}) +endif() + +# Link against Abseil libraries if found +find_package(absl QUIET) +if(absl_FOUND) + target_link_libraries(blockchain_ui PRIVATE + absl::base + absl::strings + absl::log + absl::check + ) +endif() + +# Set common properties for both platforms +set_target_properties(blockchain_ui PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/modules" # For Windows .dll + BUILD_WITH_INSTALL_RPATH TRUE + SKIP_BUILD_RPATH FALSE) + +if(APPLE) + # macOS specific settings + set_target_properties(blockchain_ui PROPERTIES + INSTALL_RPATH "@loader_path" + INSTALL_NAME_DIR "@rpath" + BUILD_WITH_INSTALL_NAME_DIR TRUE) + + add_custom_command(TARGET blockchain_ui POST_BUILD + COMMAND install_name_tool -id "@rpath/blockchain_ui.dylib" $ + COMMENT "Updating library paths for macOS" + ) +else() + # Linux specific settings + set_target_properties(blockchain_ui PROPERTIES + INSTALL_RPATH "$ORIGIN" + INSTALL_RPATH_USE_LINK_PATH FALSE) +endif() + +install(TARGETS blockchain_ui + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/logos/modules + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/logos/modules + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/logos/modules +) + +install(FILES ${METADATA_JSON} + DESTINATION ${CMAKE_INSTALL_DATADIR}/logos-blockchain-ui-new +) + +install(DIRECTORY "${PLUGINS_OUTPUT_DIR}/" + DESTINATION ${CMAKE_INSTALL_DATADIR}/logos-blockchain-ui-new/generated + OPTIONAL +) + +# Print status messages +message(STATUS "Blockchain UI Plugin configured successfully") diff --git a/README.md b/README.md new file mode 100644 index 0000000..f04238d --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +# logos-blockchain-ui-new + +A Qt UI plugin for the Logos Blockchain Module, providing a graphical interface to control and monitor the Logos blockchain node. + +## Features + +- Start/Stop blockchain node +- Configure node parameters (config path, deployment) +- Check wallet balances +- Monitor node status and information + +## How to Build + +### Using Nix (Recommended) + +#### Build Complete UI Plugin + +```bash +# Build everything (default) +nix build + +# Or explicitly +nix build '.#default' +``` + +The result will include: +- `/lib/blockchain_ui.dylib` (or `.so` on Linux) - The Blockchain UI plugin + +#### Build Individual Components + +```bash +# Build only the library (plugin) +nix build '.#lib' + +# Build the standalone Qt application +nix build '.#app' +``` + +#### Development Shell + +```bash +# Enter development shell with all dependencies +nix develop +``` + +**Note:** In zsh, you need to quote the target (e.g., `'.#default'`) to prevent glob expansion. + +If you don't have flakes enabled globally, add experimental flags: + +```bash +nix build --extra-experimental-features 'nix-command flakes' +``` + +The compiled artifacts can be found at `result/` + +#### Running the Standalone App + +After building the app with `nix build '.#app'`, you can run it: + +```bash +# Run the standalone Qt application +./result/bin/logos-blockchain-ui-app +``` + +The app will automatically load the required modules (capability_module, liblogos_blockchain_module) and the blockchain_ui Qt plugin. All dependencies are bundled in the Nix store layout. + +#### Nix Organization + +The nix build system is organized into modular files in the `/nix` directory: +- `nix/default.nix` - Common configuration (dependencies, flags, metadata) +- `nix/lib.nix` - UI plugin compilation +- `nix/app.nix` - Standalone Qt application compilation + +## Output Structure + +When built with Nix: + +**Library build (`nix build '.#lib'`):** +``` +result/ +└── lib/ + └── blockchain_ui.dylib # Logos Blockchain UI plugin +``` + +**App build (`nix build '.#app'`):** +``` +result/ +├── bin/ +│ ├── logos-blockchain-ui-app # Standalone Qt application +│ ├── logos_host # Logos host executable (for plugins) +│ └── logoscore # Logos core executable +├── lib/ +│ ├── liblogos_core.dylib # Logos core library +│ ├── liblogos_sdk.dylib # Logos SDK library +│ └── Logos/DesignSystem/ # QML design system +├── modules/ +│ ├── capability_module_plugin.dylib +│ ├── liblogos_blockchain_module.dylib +│ └── liblogos_blockchain.dylib +└── blockchain_ui.dylib # Qt plugin (loaded by app) +``` + +## Configuration + +### Blockchain Node Configuration + +The blockchain node can be configured in two ways: + +1. **Via UI**: Enter the config path in the "Config Path" field +2. **Via Environment Variable**: Set `LB_CONFIG_PATH` to your configuration file path + +Example configuration file can be found in the logos-blockchain-module repository at `config/node_config.yaml`. + +### QML Hot Reload + +During development, you can enable QML hot reload by setting an environment variable: +```bash +export BLOCKCHAIN_UI_QML_PATH=/path/to/logos-blockchain-ui/src/qml +``` +This allows you to edit the QML file and see changes by reloading the plugin without recompiling. \ No newline at end of file diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000..bdb008d --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,84 @@ +cmake_minimum_required(VERSION 3.16) +project(LogosBlockchainUIApp LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# Find Qt packages +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Widgets) + +# Find logos-liblogos +if(NOT DEFINED LOGOS_LIBLOGOS_ROOT) + message(FATAL_ERROR "LOGOS_LIBLOGOS_ROOT must be defined") +endif() + +# Find logos-cpp-sdk +if(NOT DEFINED LOGOS_CPP_SDK_ROOT) + message(FATAL_ERROR "LOGOS_CPP_SDK_ROOT must be defined") +endif() + +message(STATUS "Using logos-liblogos at: ${LOGOS_LIBLOGOS_ROOT}") +message(STATUS "Using logos-cpp-sdk at: ${LOGOS_CPP_SDK_ROOT}") + +# Check if logos_sdk library exists +if(NOT EXISTS "${LOGOS_CPP_SDK_ROOT}/lib/liblogos_sdk.a" AND NOT EXISTS "${LOGOS_CPP_SDK_ROOT}/lib/liblogos_sdk.dylib" AND NOT EXISTS "${LOGOS_CPP_SDK_ROOT}/lib/liblogos_sdk.so") + message(WARNING "logos_sdk library not found in ${LOGOS_CPP_SDK_ROOT}/lib/") + message(STATUS "Available files in ${LOGOS_CPP_SDK_ROOT}/lib/:") + file(GLOB SDK_LIB_FILES "${LOGOS_CPP_SDK_ROOT}/lib/*") + foreach(file ${SDK_LIB_FILES}) + message(STATUS " ${file}") + endforeach() +endif() + +# Include directories - the new structure has headers in /include with subdirectories +include_directories( + ${LOGOS_LIBLOGOS_ROOT}/include + ${LOGOS_CPP_SDK_ROOT}/include + ${LOGOS_CPP_SDK_ROOT}/include/cpp + ${LOGOS_CPP_SDK_ROOT}/include/core +) + +# Link directories +link_directories( + ${LOGOS_LIBLOGOS_ROOT}/lib + ${LOGOS_CPP_SDK_ROOT}/lib +) + +# Set output directories +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +# Create the executable +add_executable(logos-blockchain-ui-app + main.cpp + mainwindow.cpp + mainwindow.h +) + +# Link libraries +target_link_libraries(logos-blockchain-ui-app PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Widgets + logos_core + logos_sdk +) + +# Set RPATH settings for the executable +if(APPLE) + set_target_properties(logos-blockchain-ui-app PROPERTIES + INSTALL_RPATH "@executable_path/../lib" + BUILD_WITH_INSTALL_RPATH TRUE + ) +elseif(UNIX) + set_target_properties(logos-blockchain-ui-app PROPERTIES + INSTALL_RPATH "$ORIGIN/../lib" + BUILD_WITH_INSTALL_RPATH TRUE + ) +endif() + +# Install rules +install(TARGETS logos-blockchain-ui-app + RUNTIME DESTINATION bin +) diff --git a/app/main.cpp b/app/main.cpp new file mode 100644 index 0000000..6c0ba25 --- /dev/null +++ b/app/main.cpp @@ -0,0 +1,56 @@ +#include "mainwindow.h" + +#include +#include +#include +#include +#include + +// CoreManager C API functions +extern "C" { + void logos_core_set_plugins_dir(const char* plugins_dir); + void logos_core_start(); + void logos_core_cleanup(); + char** logos_core_get_loaded_plugins(); + int logos_core_load_plugin(const char* plugin_name); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QString pluginsDir = QDir::cleanPath(QCoreApplication::applicationDirPath() + "/../modules"); + logos_core_set_plugins_dir(pluginsDir.toUtf8().constData()); + + logos_core_start(); + + if (!logos_core_load_plugin("capability_module")) { + qWarning() << "Failed to load capability_module plugin"; + } + + if (!logos_core_load_plugin("liblogos_blockchain_module")) { + qWarning() << "Failed to load blockchain module plugin"; + } + + char** loadedPlugins = logos_core_get_loaded_plugins(); + int count = 0; + if (loadedPlugins) { + qInfo() << "Currently loaded plugins:"; + for (char** p = loadedPlugins; *p != nullptr; ++p) { + qInfo() << " -" << *p; + ++count; + } + qInfo() << "Total plugins:" << count; + } else { + qInfo() << "No plugins loaded."; + } + + MainWindow window; + window.show(); + + int result = app.exec(); + + logos_core_cleanup(); + + return result; +} diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp new file mode 100644 index 0000000..b749dce --- /dev/null +++ b/app/mainwindow.cpp @@ -0,0 +1,66 @@ +#include +#include "mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + setupUi(); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::setupUi() +{ + // Determine the appropriate plugin extension based on the platform + QString pluginExtension; + #if defined(Q_OS_WIN) + pluginExtension = ".dll"; + #elif defined(Q_OS_MAC) + pluginExtension = ".dylib"; + #else // Linux and other Unix-like systems + pluginExtension = ".so"; + #endif + + QString pluginPath = QCoreApplication::applicationDirPath() + "/../blockchain_ui" + pluginExtension; + QPluginLoader loader(pluginPath); + + QWidget* blockchainWidget = nullptr; + + if (loader.load()) { + QObject* plugin = loader.instance(); + if (plugin) { + // Try to create the blockchain widget using the plugin's createWidget method + QMetaObject::invokeMethod(plugin, "createWidget", + Qt::DirectConnection, + Q_RETURN_ARG(QWidget*, blockchainWidget)); + } + } + + if (blockchainWidget) { + setCentralWidget(blockchainWidget); + } else { + qWarning() << "================================================"; + qWarning() << "Failed to load blockchain UI plugin from:" << pluginPath; + qWarning() << "Error:" << loader.errorString(); + qWarning() << "================================================"; + + // Fallback: show a message when plugin is not found + QWidget* fallbackWidget = new QWidget(this); + QVBoxLayout* layout = new QVBoxLayout(fallbackWidget); + + QLabel* messageLabel = new QLabel("Blockchain UI module not loaded", fallbackWidget); + QFont font = messageLabel->font(); + font.setPointSize(14); + messageLabel->setFont(font); + messageLabel->setAlignment(Qt::AlignCenter); + + layout->addWidget(messageLabel); + setCentralWidget(fallbackWidget); + } + + // Set window title and size + setWindowTitle("Logos Blockchain UI App"); + resize(800, 600); +} diff --git a/app/mainwindow.h b/app/mainwindow.h new file mode 100644 index 0000000..c90ddc9 --- /dev/null +++ b/app/mainwindow.h @@ -0,0 +1,18 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + void setupUi(); +}; + +#endif // MAINWINDOW_H diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..451c2f7 --- /dev/null +++ b/flake.lock @@ -0,0 +1,1411 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1769737823, + "narHash": "sha256-DrBaNpZ+sJ4stXm+0nBX7zqZT9t9P22zbk6m5YhQxS4=", + "owner": "ipetkov", + "repo": "crane", + "rev": "b2f45c3830aa96b7456a4c4bc327d04d7a43e1ba", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "logos-blockchain": { + "inputs": { + "crane": "crane", + "logos-blockchain-circuits": "logos-blockchain-circuits", + "nixpkgs": "nixpkgs_2", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1770888466, + "narHash": "sha256-7IJz+UIwa8QPg81cvqunpnpO87VUdWt0TcPz7HGBnYE=", + "owner": "logos-blockchain", + "repo": "logos-blockchain", + "rev": "3ef7a137b91c4a5a7708405815354ff58e0e179c", + "type": "github" + }, + "original": { + "owner": "logos-blockchain", + "repo": "logos-blockchain", + "type": "github" + } + }, + "logos-blockchain-circuits": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1769780029, + "narHash": "sha256-B2CYcJWuJIXAJaWgBcY4k0FTxo62mI8Hd9RqBECfq4o=", + "owner": "logos-blockchain", + "repo": "logos-blockchain-circuits", + "rev": "480b9bc4fddb4643f528d607f046f27610439a78", + "type": "github" + }, + "original": { + "owner": "logos-blockchain", + "repo": "logos-blockchain-circuits", + "type": "github" + } + }, + "logos-blockchain-module": { + "inputs": { + "logos-blockchain": "logos-blockchain", + "logos-core": "logos-core", + "logos-liblogos": "logos-liblogos", + "logos-module-viewer": "logos-module-viewer", + "nixpkgs": [ + "logos-blockchain-module", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770934619, + "narHash": "sha256-DyksgOrea/gktElcOZmMDUcYW45JPpkDA5BnPkwVmmc=", + "owner": "logos-blockchain", + "repo": "logos-blockchain-module", + "rev": "578308270ecfe7463a94ac50cae0584451c135ef", + "type": "github" + }, + "original": { + "owner": "logos-blockchain", + "repo": "logos-blockchain-module", + "rev": "578308270ecfe7463a94ac50cae0584451c135ef", + "type": "github" + } + }, + "logos-capability-module": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk", + "logos-liblogos": "logos-liblogos_2", + "nixpkgs": [ + "logos-blockchain-module", + "logos-liblogos", + "logos-capability-module", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767809111, + "narHash": "sha256-jehjsB+BpDJlVu3I7x+vFVOdXmy9MDmFTJtRqzFUONo=", + "owner": "logos-co", + "repo": "logos-capability-module", + "rev": "7b35383e0aa4e28a4633ed18a87efb57636939b1", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-capability-module", + "type": "github" + } + }, + "logos-capability-module_2": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_5", + "logos-liblogos": "logos-liblogos_3", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-capability-module", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767809111, + "narHash": "sha256-jehjsB+BpDJlVu3I7x+vFVOdXmy9MDmFTJtRqzFUONo=", + "owner": "logos-co", + "repo": "logos-capability-module", + "rev": "7b35383e0aa4e28a4633ed18a87efb57636939b1", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-capability-module", + "type": "github" + } + }, + "logos-capability-module_3": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_8", + "logos-liblogos": "logos-liblogos_5", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-liblogos", + "logos-capability-module", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767809111, + "narHash": "sha256-jehjsB+BpDJlVu3I7x+vFVOdXmy9MDmFTJtRqzFUONo=", + "owner": "logos-co", + "repo": "logos-capability-module", + "rev": "7b35383e0aa4e28a4633ed18a87efb57636939b1", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-capability-module", + "type": "github" + } + }, + "logos-capability-module_4": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_14", + "logos-liblogos": "logos-liblogos_7", + "nixpkgs": [ + "logos-capability-module", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767809111, + "narHash": "sha256-jehjsB+BpDJlVu3I7x+vFVOdXmy9MDmFTJtRqzFUONo=", + "owner": "logos-co", + "repo": "logos-capability-module", + "rev": "7b35383e0aa4e28a4633ed18a87efb57636939b1", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-capability-module", + "type": "github" + } + }, + "logos-capability-module_5": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_17", + "logos-liblogos": "logos-liblogos_9", + "nixpkgs": [ + "logos-liblogos", + "logos-capability-module", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767809111, + "narHash": "sha256-jehjsB+BpDJlVu3I7x+vFVOdXmy9MDmFTJtRqzFUONo=", + "owner": "logos-co", + "repo": "logos-capability-module", + "rev": "7b35383e0aa4e28a4633ed18a87efb57636939b1", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-capability-module", + "type": "github" + } + }, + "logos-core": { + "inputs": { + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1770132997, + "narHash": "sha256-Iv0QMXMD6kf+y2Qx37jXR7Ik6h1dqOzuxBzCdc5S6KA=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "30ef7986f4b65b7dcf43af84bb073233b1b77821", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk": { + "inputs": { + "nixpkgs": "nixpkgs_4" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_10": { + "inputs": { + "nixpkgs": "nixpkgs_13" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_11": { + "inputs": { + "nixpkgs": "nixpkgs_14" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_12": { + "inputs": { + "nixpkgs": "nixpkgs_15" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_13": { + "inputs": { + "nixpkgs": "nixpkgs_16" + }, + "locked": { + "lastModified": 1764699992, + "narHash": "sha256-nCmK9C9F31cHvy6lWKR5WGl99aJbS3kIsROAoZ4OrwI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "5d0bbd0d1e00aad0532ffa7c8bf2c80f460a4f6d", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_14": { + "inputs": { + "nixpkgs": "nixpkgs_18" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_15": { + "inputs": { + "nixpkgs": "nixpkgs_19" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_16": { + "inputs": { + "nixpkgs": "nixpkgs_20" + }, + "locked": { + "lastModified": 1770132997, + "narHash": "sha256-Iv0QMXMD6kf+y2Qx37jXR7Ik6h1dqOzuxBzCdc5S6KA=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "30ef7986f4b65b7dcf43af84bb073233b1b77821", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_17": { + "inputs": { + "nixpkgs": "nixpkgs_21" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_18": { + "inputs": { + "nixpkgs": "nixpkgs_22" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_19": { + "inputs": { + "nixpkgs": "nixpkgs_23" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_2": { + "inputs": { + "nixpkgs": "nixpkgs_5" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_20": { + "inputs": { + "nixpkgs": "nixpkgs_24" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_3": { + "inputs": { + "nixpkgs": "nixpkgs_6" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_4": { + "inputs": { + "nixpkgs": "nixpkgs_7" + }, + "locked": { + "lastModified": 1767724329, + "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_5": { + "inputs": { + "nixpkgs": "nixpkgs_8" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_6": { + "inputs": { + "nixpkgs": "nixpkgs_9" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_7": { + "inputs": { + "nixpkgs": "nixpkgs_10" + }, + "locked": { + "lastModified": 1770132997, + "narHash": "sha256-Iv0QMXMD6kf+y2Qx37jXR7Ik6h1dqOzuxBzCdc5S6KA=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "30ef7986f4b65b7dcf43af84bb073233b1b77821", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_8": { + "inputs": { + "nixpkgs": "nixpkgs_11" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_9": { + "inputs": { + "nixpkgs": "nixpkgs_12" + }, + "locked": { + "lastModified": 1761230734, + "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "4b143922c190df00bb3835441c9f0075cb28283b", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-design-system": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770997148, + "narHash": "sha256-plHuPEFyOPrUv1Dyk/2D9Ppc71Xby0LiCIOAzbFCi+I=", + "owner": "logos-co", + "repo": "logos-design-system", + "rev": "ede76f156852321f3793fa417295813994e6c9e4", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-design-system", + "type": "github" + } + }, + "logos-liblogos": { + "inputs": { + "logos-capability-module": "logos-capability-module", + "logos-cpp-sdk": "logos-cpp-sdk_3", + "logos-module": "logos-module", + "nixpkgs": [ + "logos-blockchain-module", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770837874, + "narHash": "sha256-wr75lv1q4U1FS5+l/6ypwzJFJe06l2RyUvx1npoRS88=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "e3741c01fd3abf6b7bd9ff2fa8edf89c41fc0cea", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_2": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_2", + "nixpkgs": [ + "logos-blockchain-module", + "logos-liblogos", + "logos-capability-module", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761845775, + "narHash": "sha256-ulK8xq05ejK6qIgZ7WtWb/MJt2rk5BKfDA2z7mM3wq8=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "a92c2c1268bc70764c8f73c7bce07d21024f5af9", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_3": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_6", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-capability-module", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761845775, + "narHash": "sha256-ulK8xq05ejK6qIgZ7WtWb/MJt2rk5BKfDA2z7mM3wq8=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "a92c2c1268bc70764c8f73c7bce07d21024f5af9", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_4": { + "inputs": { + "logos-capability-module": "logos-capability-module_3", + "logos-cpp-sdk": "logos-cpp-sdk_10", + "logos-module": "logos-module_2", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770154824, + "narHash": "sha256-WGI+3FkPdeytfLJ3ZJYr1O8esUnQjcmMJEYwB/EBZMs=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "901dd86d47216b15b6f1260b7b6bb4ecd88a8f9d", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_5": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_9", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-liblogos", + "logos-capability-module", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761845775, + "narHash": "sha256-ulK8xq05ejK6qIgZ7WtWb/MJt2rk5BKfDA2z7mM3wq8=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "a92c2c1268bc70764c8f73c7bce07d21024f5af9", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_6": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_13", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-package-manager", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768343028, + "narHash": "sha256-4LvsuZTDTlLtfMF4C69ls+lmkYJWD7LZitS04Mc+8UI=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "a76d33f5519af0ee12317c8f149eee2ac5d292a0", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_7": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_15", + "nixpkgs": [ + "logos-capability-module", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761845775, + "narHash": "sha256-ulK8xq05ejK6qIgZ7WtWb/MJt2rk5BKfDA2z7mM3wq8=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "a92c2c1268bc70764c8f73c7bce07d21024f5af9", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_8": { + "inputs": { + "logos-capability-module": "logos-capability-module_5", + "logos-cpp-sdk": "logos-cpp-sdk_19", + "logos-module": "logos-module_3", + "nixpkgs": [ + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770837874, + "narHash": "sha256-wr75lv1q4U1FS5+l/6ypwzJFJe06l2RyUvx1npoRS88=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "e3741c01fd3abf6b7bd9ff2fa8edf89c41fc0cea", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-liblogos_9": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_18", + "nixpkgs": [ + "logos-liblogos", + "logos-capability-module", + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761845775, + "narHash": "sha256-ulK8xq05ejK6qIgZ7WtWb/MJt2rk5BKfDA2z7mM3wq8=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "a92c2c1268bc70764c8f73c7bce07d21024f5af9", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "logos-module": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_4", + "nixpkgs": [ + "logos-blockchain-module", + "logos-liblogos", + "logos-module", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770062426, + "narHash": "sha256-zc7ZxDTlqOCYGyEHhrTA/7GS1EWh7+4amdPUKh+gGds=", + "owner": "logos-co", + "repo": "logos-module", + "rev": "f7ee69d9ad9f27c84f04f59896e9194125e951dc", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-module", + "type": "github" + } + }, + "logos-module-viewer": { + "inputs": { + "logos-capability-module": "logos-capability-module_2", + "logos-cpp-sdk": "logos-cpp-sdk_7", + "logos-liblogos": "logos-liblogos_4", + "logos-package-manager": "logos-package-manager", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770804615, + "narHash": "sha256-0DuGGEgGHpRcVElWlQXqgseGN+xZ6cqXplRayqdNZQY=", + "owner": "logos-co", + "repo": "logos-module-viewer", + "rev": "2ed9def5db6d5b8d83e5a9671ce5c571bc86deff", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-module-viewer", + "type": "github" + } + }, + "logos-module_2": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_11", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-liblogos", + "logos-module", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770062426, + "narHash": "sha256-zc7ZxDTlqOCYGyEHhrTA/7GS1EWh7+4amdPUKh+gGds=", + "owner": "logos-co", + "repo": "logos-module", + "rev": "f7ee69d9ad9f27c84f04f59896e9194125e951dc", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-module", + "type": "github" + } + }, + "logos-module_3": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_20", + "nixpkgs": [ + "logos-liblogos", + "logos-module", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770062426, + "narHash": "sha256-zc7ZxDTlqOCYGyEHhrTA/7GS1EWh7+4amdPUKh+gGds=", + "owner": "logos-co", + "repo": "logos-module", + "rev": "f7ee69d9ad9f27c84f04f59896e9194125e951dc", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-module", + "type": "github" + } + }, + "logos-package": { + "inputs": { + "nixpkgs": "nixpkgs_17" + }, + "locked": { + "lastModified": 1768925546, + "narHash": "sha256-Y4sgYs9wtZ9sHAuKl9LUy//ReeF4/AyK8HlnZsYrSqg=", + "owner": "logos-co", + "repo": "logos-package", + "rev": "9230ae37c9d289c0c355dcf9fa40fd3be2e99f17", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-package", + "type": "github" + } + }, + "logos-package-manager": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_12", + "logos-liblogos": "logos-liblogos_6", + "logos-package": "logos-package", + "nixpkgs": [ + "logos-blockchain-module", + "logos-module-viewer", + "logos-package-manager", + "logos-liblogos", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770753928, + "narHash": "sha256-61+3D+svB2mqyLpDFlHoIN+hBlbRGZUaueKysEiorNE=", + "owner": "logos-co", + "repo": "logos-package-manager-module", + "rev": "0cbf250ad2fec20c79dc5f61729a07c3a2bd50e1", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-package-manager-module", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_10": { + "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_11": { + "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_12": { + "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_13": { + "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_14": { + "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_15": { + "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_16": { + "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_17": { + "locked": { + "lastModified": 1768127708, + "narHash": "sha256-1Sm77VfZh3mU0F5OqKABNLWxOuDeHIlcFjsXeeiPazs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ffbc9f8cbaacfb331b6017d5a5abb21a492c9a38", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_18": { + "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_19": { + "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_2": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_20": { + "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_21": { + "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_22": { + "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_23": { + "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_24": { + "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_3": { + "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_4": { + "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_5": { + "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_6": { + "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_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": 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_9": { + "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" + } + }, + "root": { + "inputs": { + "logos-blockchain-module": "logos-blockchain-module", + "logos-capability-module": "logos-capability-module_4", + "logos-cpp-sdk": "logos-cpp-sdk_16", + "logos-design-system": "logos-design-system", + "logos-liblogos": "logos-liblogos_8", + "nixpkgs": [ + "logos-liblogos", + "nixpkgs" + ] + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "logos-blockchain-module", + "logos-blockchain", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769742225, + "narHash": "sha256-roSD/OJ3x9nF+Dxr+/bLClX3U8FP9EkCQIFpzxKjSUM=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "bcdd8d37594f0e201639f55889c01c827baf5c75", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..6c28395 --- /dev/null +++ b/flake.nix @@ -0,0 +1,84 @@ +{ + description = "Logos Blockchain UI - A Qt UI plugin for Logos Blockchain Module"; + + inputs = { + # Follow the same nixpkgs as logos-liblogos to ensure compatibility + nixpkgs.follows = "logos-liblogos/nixpkgs"; + logos-cpp-sdk.url = "github:logos-co/logos-cpp-sdk"; + logos-liblogos.url = "github:logos-co/logos-liblogos"; + logos-blockchain-module.url = "github:logos-blockchain/logos-blockchain-module/578308270ecfe7463a94ac50cae0584451c135ef"; + logos-capability-module.url = "github:logos-co/logos-capability-module"; + logos-design-system.url = "github:logos-co/logos-design-system"; + logos-design-system.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { self, nixpkgs, logos-cpp-sdk, logos-liblogos, logos-blockchain-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 { + pkgs = import nixpkgs { inherit system; }; + logosSdk = logos-cpp-sdk.packages.${system}.default; + logosLiblogos = logos-liblogos.packages.${system}.default; + logosBlockchainModule = logos-blockchain-module.packages.${system}.default; + logosCapabilityModule = logos-capability-module.packages.${system}.default; + logosDesignSystem = logos-design-system.packages.${system}.default; + }); + in + { + packages = forAllSystems ({ pkgs, logosSdk, logosLiblogos, logosBlockchainModule, logosCapabilityModule, logosDesignSystem }: + let + # Common configuration + common = import ./nix/default.nix { + inherit pkgs logosSdk logosLiblogos; + }; + src = ./.; + + # Library package (default blockchain-module has lib + include via symlinkJoin) + lib = import ./nix/lib.nix { + inherit pkgs common src logosBlockchainModule logosSdk; + }; + + # App package + app = import ./nix/app.nix { + inherit pkgs common src logosLiblogos logosSdk logosBlockchainModule logosCapabilityModule logosDesignSystem; + logosBlockchainUI = lib; + }; + in + { + # Individual outputs + logos-blockchain-ui-lib = lib; + app = app; + lib = lib; + + # Default package + default = lib; + } + ); + + devShells = forAllSystems ({ pkgs, logosSdk, logosLiblogos, logosBlockchainModule, logosCapabilityModule, logosDesignSystem }: { + default = pkgs.mkShell { + nativeBuildInputs = [ + pkgs.cmake + pkgs.ninja + pkgs.pkg-config + ]; + buildInputs = [ + pkgs.qt6.qtbase + pkgs.qt6.qtremoteobjects + pkgs.zstd + pkgs.krb5 + pkgs.abseil-cpp + ]; + + shellHook = '' + export LOGOS_CPP_SDK_ROOT="${logosSdk}" + export LOGOS_LIBLOGOS_ROOT="${logosLiblogos}" + export LOGOS_DESIGN_SYSTEM_ROOT="${logosDesignSystem}" + echo "Logos Blockchain UI development environment" + echo "LOGOS_CPP_SDK_ROOT: $LOGOS_CPP_SDK_ROOT" + echo "LOGOS_LIBLOGOS_ROOT: $LOGOS_LIBLOGOS_ROOT" + ''; + }; + }); + }; +} diff --git a/interfaces/IComponent.h b/interfaces/IComponent.h new file mode 100644 index 0000000..06ad57a --- /dev/null +++ b/interfaces/IComponent.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +class LogosAPI; + +class IComponent { +public: + virtual ~IComponent() = default; + virtual QWidget* createWidget(LogosAPI* logosAPI = nullptr) = 0; + virtual void destroyWidget(QWidget* widget) = 0; +}; + +#define IComponent_iid "com.logos.component.IComponent" +Q_DECLARE_INTERFACE(IComponent, IComponent_iid) diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..60ecd3b --- /dev/null +++ b/metadata.json @@ -0,0 +1,26 @@ +{ + "name": "blockchain_ui", + "version": "1.0.0", + "description": "Blockchain UI module for the Logos application", + "author": "Logos Blockchain Team", + "type": "ui", + "main": "blockchain_ui", + "dependencies": ["liblogos_blockchain_module"], + "category": "blockchain", + "build": { + "type": "cmake", + "files": [ + "src/BlockchainPlugin.cpp", + "src/BlockchainPlugin.h", + "src/BlockchainBackend.cpp", + "src/BlockchainBackend.h", + "src/LogModel.cpp", + "src/LogModel.h", + "src/blockchain_resources.qrc" + ] + }, + "capabilities": [ + "ui_components", + "blockchain" + ] +} diff --git a/nix/app.nix b/nix/app.nix new file mode 100644 index 0000000..00ebdc3 --- /dev/null +++ b/nix/app.nix @@ -0,0 +1,250 @@ +# Builds the logos-blockchain-ui-app standalone application +{ pkgs, common, src, logosLiblogos, logosSdk, logosBlockchainModule, logosCapabilityModule, logosBlockchainUI, logosDesignSystem }: + +pkgs.stdenv.mkDerivation rec { + pname = "logos-blockchain-ui-app"; + version = common.version; + + inherit src; + inherit (common) buildInputs cmakeFlags meta; + + # Add logosSdk to nativeBuildInputs for logos-cpp-generator + nativeBuildInputs = common.nativeBuildInputs ++ [ logosSdk pkgs.patchelf pkgs.removeReferencesTo ]; + + # Provide Qt/GL runtime paths so the wrapper can inject them + qtLibPath = pkgs.lib.makeLibraryPath ( + [ + pkgs.qt6.qtbase + pkgs.qt6.qtremoteobjects + pkgs.zstd + pkgs.krb5 + pkgs.zlib + pkgs.glib + pkgs.stdenv.cc.cc + pkgs.freetype + pkgs.fontconfig + ] + ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ + pkgs.libglvnd + pkgs.mesa.drivers + pkgs.xorg.libX11 + pkgs.xorg.libXext + pkgs.xorg.libXrender + pkgs.xorg.libXrandr + pkgs.xorg.libXcursor + pkgs.xorg.libXi + pkgs.xorg.libXfixes + pkgs.xorg.libxcb + ] + ); + qtPluginPath = "${pkgs.qt6.qtbase}/lib/qt-6/plugins"; + qmlImportPath = "${placeholder "out"}/lib:${pkgs.qt6.qtbase}/lib/qt-6/qml"; + + # This is a GUI application, enable Qt wrapping + dontWrapQtApps = false; + + # This is an aggregate runtime layout; avoid stripping to prevent hook errors + dontStrip = true; + + # Ensure proper Qt environment setup via wrapper + qtWrapperArgs = [ + "--prefix" "LD_LIBRARY_PATH" ":" qtLibPath + "--prefix" "QT_PLUGIN_PATH" ":" qtPluginPath + "--prefix" "QML2_IMPORT_PATH" ":" qmlImportPath + ]; + + preConfigure = '' + runHook prePreConfigure + + # Set macOS deployment target to match Qt frameworks + export MACOSX_DEPLOYMENT_TARGET=12.0 + + # Copy logos-cpp-sdk headers to expected location + echo "Copying logos-cpp-sdk headers for app..." + mkdir -p ./logos-cpp-sdk/include/cpp + cp -r ${logosSdk}/include/cpp/* ./logos-cpp-sdk/include/cpp/ + + # Also copy core headers + echo "Copying core headers..." + mkdir -p ./logos-cpp-sdk/include/core + cp -r ${logosSdk}/include/core/* ./logos-cpp-sdk/include/core/ + + # Copy SDK library files to lib directory + echo "Copying SDK library files..." + mkdir -p ./logos-cpp-sdk/lib + if [ -f "${logosSdk}/lib/liblogos_sdk.dylib" ]; then + cp "${logosSdk}/lib/liblogos_sdk.dylib" ./logos-cpp-sdk/lib/ + elif [ -f "${logosSdk}/lib/liblogos_sdk.so" ]; then + cp "${logosSdk}/lib/liblogos_sdk.so" ./logos-cpp-sdk/lib/ + elif [ -f "${logosSdk}/lib/liblogos_sdk.a" ]; then + cp "${logosSdk}/lib/liblogos_sdk.a" ./logos-cpp-sdk/lib/ + fi + + runHook postPreConfigure + ''; + + # Additional environment variables for Qt and RPATH cleanup + preFixup = '' + runHook prePreFixup + + # Set up Qt environment variables + export QT_PLUGIN_PATH="${pkgs.qt6.qtbase}/lib/qt-6/plugins" + export QML_IMPORT_PATH="${pkgs.qt6.qtbase}/lib/qt-6/qml" + + # Remove any remaining references to /build/ in binaries and set proper RPATH + find $out -type f -executable -exec sh -c ' + if file "$1" | grep -q "ELF.*executable"; then + # Use patchelf to clean up RPATH if it contains /build/ + if patchelf --print-rpath "$1" 2>/dev/null | grep -q "/build/"; then + echo "Cleaning RPATH for $1" + patchelf --remove-rpath "$1" 2>/dev/null || true + fi + # Set proper RPATH for the main binary + if echo "$1" | grep -q "/logos-blockchain-ui-app$"; then + echo "Setting RPATH for $1" + patchelf --set-rpath "$out/lib" "$1" 2>/dev/null || true + fi + fi + ' _ {} \; + + # Also clean up shared libraries + find $out -name "*.so" -exec sh -c ' + if patchelf --print-rpath "$1" 2>/dev/null | grep -q "/build/"; then + echo "Cleaning RPATH for $1" + patchelf --remove-rpath "$1" 2>/dev/null || true + fi + ' _ {} \; + + runHook prePostFixup + ''; + + configurePhase = '' + runHook preConfigure + + echo "Configuring logos-blockchain-ui-app..." + echo "liblogos: ${logosLiblogos}" + echo "cpp-sdk: ${logosSdk}" + echo "blockchain-module: ${logosBlockchainModule}" + echo "capability-module: ${logosCapabilityModule}" + echo "blockchain-ui: ${logosBlockchainUI}" + echo "logos-design-system: ${logosDesignSystem}" + + # Verify that the built components exist + test -d "${logosLiblogos}" || (echo "liblogos not found" && exit 1) + test -d "${logosSdk}" || (echo "cpp-sdk not found" && exit 1) + test -d "${logosBlockchainModule}" || (echo "blockchain-module not found" && exit 1) + test -d "${logosCapabilityModule}" || (echo "capability-module not found" && exit 1) + test -d "${logosBlockchainUI}" || (echo "blockchain-ui not found" && exit 1) + test -d "${logosDesignSystem}" || (echo "logos-design-system not found" && exit 1) + + cmake -S app -B build \ + -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 \ + -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE \ + -DCMAKE_INSTALL_RPATH="" \ + -DCMAKE_SKIP_BUILD_RPATH=TRUE \ + -DLOGOS_LIBLOGOS_ROOT=${logosLiblogos} \ + -DLOGOS_CPP_SDK_ROOT=$(pwd)/logos-cpp-sdk + + runHook postConfigure + ''; + + buildPhase = '' + runHook preBuild + + cmake --build build + echo "logos-blockchain-ui-app built successfully!" + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + # Create output directories + mkdir -p $out/bin $out/lib $out/modules + + # Install our app binary + if [ -f "build/bin/logos-blockchain-ui-app" ]; then + cp build/bin/logos-blockchain-ui-app "$out/bin/" + echo "Installed logos-blockchain-ui-app binary" + fi + + # Copy the core binaries from liblogos + if [ -f "${logosLiblogos}/bin/logoscore" ]; then + cp -L "${logosLiblogos}/bin/logoscore" "$out/bin/" + echo "Installed logoscore binary" + fi + if [ -f "${logosLiblogos}/bin/logos_host" ]; then + cp -L "${logosLiblogos}/bin/logos_host" "$out/bin/" + echo "Installed logos_host binary" + fi + + # Copy required shared libraries from liblogos + if ls "${logosLiblogos}/lib/"liblogos_core.* >/dev/null 2>&1; then + cp -L "${logosLiblogos}/lib/"liblogos_core.* "$out/lib/" || true + fi + + # Copy SDK library if it exists + if ls "${logosSdk}/lib/"liblogos_sdk.* >/dev/null 2>&1; then + cp -L "${logosSdk}/lib/"liblogos_sdk.* "$out/lib/" || true + fi + + # Determine platform-specific plugin extension + OS_EXT="so" + case "$(uname -s)" in + Darwin) OS_EXT="dylib";; + Linux) OS_EXT="so";; + MINGW*|MSYS*|CYGWIN*) OS_EXT="dll";; + esac + + # Copy module plugins into the modules directory + if [ -f "${logosCapabilityModule}/lib/capability_module_plugin.$OS_EXT" ]; then + cp -L "${logosCapabilityModule}/lib/capability_module_plugin.$OS_EXT" "$out/modules/" + fi + if [ -f "${logosBlockchainModule}/lib/liblogos_blockchain_module.$OS_EXT" ]; then + cp -L "${logosBlockchainModule}/lib/liblogos_blockchain_module.$OS_EXT" "$out/modules/" + fi + + # Copy liblogos_blockchain library to modules directory (needed by blockchain module) + if [ -f "${logosBlockchainModule}/lib/liblogos_blockchain.$OS_EXT" ]; then + cp -L "${logosBlockchainModule}/lib/liblogos_blockchain.$OS_EXT" "$out/modules/" + fi + + # Copy blockchain_ui Qt plugin to root directory (not modules, as it's loaded differently) + if [ -f "${logosBlockchainUI}/lib/blockchain_ui.$OS_EXT" ]; then + cp -L "${logosBlockchainUI}/lib/blockchain_ui.$OS_EXT" "$out/" + fi + + # Copy design system QML module (Logos/DesignSystem) for runtime + if [ -d "${logosDesignSystem}/lib/Logos/DesignSystem" ]; then + mkdir -p "$out/lib/Logos" + cp -R "${logosDesignSystem}/lib/Logos/DesignSystem" "$out/lib/Logos/" + echo "Copied Logos Design System to lib/Logos/DesignSystem/" + fi + + # Create a README for reference + cat > $out/README.txt < +#include +#include + +BlockchainBackend::BlockchainBackend(LogosAPI* logosAPI, QObject* parent) + : QObject(parent), + m_status(NotStarted), + m_configPath(""), + m_logModel(new LogModel(this)), + m_logos(nullptr), + m_blockchainModule(nullptr) +{ + + m_configPath = QString::fromUtf8(qgetenv("LB_CONFIG_PATH")); + + if (!logosAPI) { + logosAPI = new LogosAPI("core", this); + } + + m_logos = new LogosModules(logosAPI); + + if (!m_logos) { + setStatus(ErrorNotInitialized); + return; + } + + m_blockchainModule = &m_logos->liblogos_blockchain_module; + + if (m_blockchainModule && !m_blockchainModule->on("newBlock", [this](const QVariantList& data) { + onNewBlock(data); + })) { + setStatus(ErrorSubscribeFailed); + } +} + +BlockchainBackend::~BlockchainBackend() +{ + stopBlockchain(); +} + +void BlockchainBackend::setStatus(BlockchainStatus newStatus) +{ + if (m_status != newStatus) { + m_status = newStatus; + emit statusChanged(); + } +} + +void BlockchainBackend::setConfigPath(const QString& path) +{ + const QString localPath = QUrl::fromUserInput(path).toLocalFile(); + if (m_configPath != localPath) { + m_configPath = localPath; + emit configPathChanged(); + } +} + +void BlockchainBackend::clearLogs() +{ + m_logModel->clear(); +} + +QString BlockchainBackend::getBalance(const QString& addressHex) +{ + if (!m_blockchainModule) { + return QStringLiteral("Error: Module not initialized."); + } + // The generated proxy converts C pointer params (uint8_t*, BalanceResult*) to QVariant, + // which cannot carry raw C pointers. The module needs to expose a QString-based + // wrapper (e.g. getWalletBalanceQ) for this to work through the proxy. + Q_UNUSED(addressHex) + return QStringLiteral("Not yet available: module needs Qt-friendly wallet API."); +} + +QString BlockchainBackend::transferFunds(const QString& fromKeyHex, const QString& toKeyHex, const QString& amountStr) +{ + if (!m_blockchainModule) { + return QStringLiteral("Error: Module not initialized."); + } + // Same limitation: TransferFundsArguments and Hash are C types that cannot + // pass through the QVariant-based generated proxy. + Q_UNUSED(fromKeyHex) + Q_UNUSED(toKeyHex) + Q_UNUSED(amountStr) + return QStringLiteral("Not yet available: module needs Qt-friendly wallet API."); +} + +void BlockchainBackend::startBlockchain() +{ + if (!m_blockchainModule) { + setStatus(ErrorNotInitialized); + return; + } + + setStatus(Starting); + + int result = m_blockchainModule->start(m_configPath, QString()); + + if (result == 0 || result == 1) { + setStatus(Running); + } else if (result == 2) { + setStatus(ErrorConfigMissing); + } else if (result == 3) { + setStatus(ErrorStartFailed); + } else { + setStatus(ErrorStartFailed); + } +} + +void BlockchainBackend::stopBlockchain() +{ + if (m_status != Running && m_status != Starting) { + return; + } + + if (!m_blockchainModule) { + setStatus(ErrorNotInitialized); + return; + } + + setStatus(Stopping); + + int result = m_blockchainModule->stop(); + + if (result == 0 || result == 1) { + setStatus(Stopped); + } else { + setStatus(ErrorStopFailed); + } +} + +void BlockchainBackend::onNewBlock(const QVariantList& data) +{ + QString timestamp = QDateTime::currentDateTime().toString("HH:mm:ss"); + QString line; + if (!data.isEmpty()) { + QString blockInfo = data.first().toString(); + QString shortInfo = blockInfo.left(80); + if (blockInfo.length() > 80) { + shortInfo += "..."; + } + line = QString("[%1] 📦 New block: %2").arg(timestamp, shortInfo); + } else { + line = QString("[%1] 📦 New block (no data)").arg(timestamp); + } + m_logModel->append(line); +} diff --git a/src/BlockchainBackend.h b/src/BlockchainBackend.h new file mode 100644 index 0000000..c6b6dc9 --- /dev/null +++ b/src/BlockchainBackend.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include "logos_api.h" +#include "logos_api_client.h" +#include "logos_sdk.h" +#include "LogModel.h" + +// Type of the blockchain module proxy (has start(), stop(), on() etc.) +using BlockchainModuleProxy = std::remove_reference_t().liblogos_blockchain_module)>; + +class BlockchainBackend : public QObject { + Q_OBJECT + +public: + enum BlockchainStatus { + NotStarted = 0, + Starting, + Running, + Stopping, + Stopped, + Error, + ErrorNotInitialized, + ErrorConfigMissing, + ErrorStartFailed, + ErrorStopFailed, + ErrorSubscribeFailed + }; + Q_ENUM(BlockchainStatus) + + Q_PROPERTY(BlockchainStatus status READ status NOTIFY statusChanged) + Q_PROPERTY(QString configPath READ configPath WRITE setConfigPath NOTIFY configPathChanged) + Q_PROPERTY(LogModel* logModel READ logModel CONSTANT) + + explicit BlockchainBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr); + ~BlockchainBackend(); + + BlockchainStatus status() const { return m_status; } + QString configPath() const { return m_configPath; } + LogModel* logModel() const { return m_logModel; } + + void setConfigPath(const QString& path); + Q_INVOKABLE void clearLogs(); + Q_INVOKABLE QString getBalance(const QString& addressHex); + Q_INVOKABLE QString transferFunds(const QString& fromKeyHex, const QString& toKeyHex, const QString& amountStr); + Q_INVOKABLE void startBlockchain(); + Q_INVOKABLE void stopBlockchain(); + +public slots: + void onNewBlock(const QVariantList& data); + +signals: + void statusChanged(); + void configPathChanged(); + +private: + void setStatus(BlockchainStatus newStatus); + + BlockchainStatus m_status; + QString m_configPath; + LogModel* m_logModel; + + LogosModules* m_logos; + BlockchainModuleProxy* m_blockchainModule; +}; diff --git a/src/BlockchainPlugin.cpp b/src/BlockchainPlugin.cpp new file mode 100644 index 0000000..b52f7a6 --- /dev/null +++ b/src/BlockchainPlugin.cpp @@ -0,0 +1,54 @@ +#include "BlockchainPlugin.h" +#include "BlockchainBackend.h" +#include "LogModel.h" +#include +#include +#include +#include +#include +#include +#include +#include + +QWidget* BlockchainPlugin::createWidget(LogosAPI* logosAPI) { + qDebug() << "BlockchainPlugin::createWidget called"; + + QQuickWidget* quickWidget = new QQuickWidget(); + quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + qmlRegisterType("BlockchainBackend", 1, 0, "BlockchainBackend"); + qmlRegisterType("BlockchainBackend", 1, 0, "LogModel"); + + BlockchainBackend* backend = new BlockchainBackend(logosAPI, quickWidget); + quickWidget->rootContext()->setContextProperty("backend", backend); + + QString qmlSource = "qrc:/qml/BlockchainView.qml"; + QString importPath = "qrc:/qml"; + + QString envPath = QString::fromUtf8(qgetenv("BLOCKCHAIN_UI_QML_PATH")).trimmed(); + if (!envPath.isEmpty()) { + QFileInfo info(envPath); + if (info.isDir()) { + QString main = QDir(info.absoluteFilePath()).absoluteFilePath("BlockchainView.qml"); + if (QFile::exists(main)) { + importPath = info.absoluteFilePath(); + qmlSource = QUrl::fromLocalFile(main).toString(); + } else { + qWarning() << "BLOCKCHAIN_UI_QML_PATH: BlockchainView.qml not found in" << info.absoluteFilePath(); + } + } + } + + quickWidget->engine()->addImportPath(importPath); + quickWidget->setSource(QUrl(qmlSource)); + + if (quickWidget->status() == QQuickWidget::Error) { + qWarning() << "BlockchainPlugin: Failed to load QML:" << quickWidget->errors(); + } + + return quickWidget; +} + +void BlockchainPlugin::destroyWidget(QWidget* widget) { + delete widget; +} diff --git a/src/BlockchainPlugin.h b/src/BlockchainPlugin.h new file mode 100644 index 0000000..0480555 --- /dev/null +++ b/src/BlockchainPlugin.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +class BlockchainPlugin : public QObject, public IComponent { + Q_OBJECT + Q_INTERFACES(IComponent) + Q_PLUGIN_METADATA(IID IComponent_iid FILE "metadata.json") + +public: + Q_INVOKABLE QWidget* createWidget(LogosAPI* logosAPI = nullptr) override; + void destroyWidget(QWidget* widget) override; +}; diff --git a/src/LogModel.cpp b/src/LogModel.cpp new file mode 100644 index 0000000..35d9281 --- /dev/null +++ b/src/LogModel.cpp @@ -0,0 +1,43 @@ +#include "LogModel.h" + +int LogModel::rowCount(const QModelIndex& parent) const +{ + if (parent.isValid()) + return 0; + return m_lines.size(); +} + +QVariant LogModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_lines.size()) + return QVariant(); + if (role == TextRole || role == Qt::DisplayRole) + return m_lines.at(index.row()); + return QVariant(); +} + +QHash LogModel::roleNames() const +{ + QHash names; + names[TextRole] = "text"; + return names; +} + +void LogModel::append(const QString& line) +{ + const int row = m_lines.size(); + beginInsertRows(QModelIndex(), row, row); + m_lines.append(line); + endInsertRows(); + emit countChanged(); +} + +void LogModel::clear() +{ + if (m_lines.isEmpty()) + return; + beginResetModel(); + m_lines.clear(); + endResetModel(); + emit countChanged(); +} diff --git a/src/LogModel.h b/src/LogModel.h new file mode 100644 index 0000000..215de63 --- /dev/null +++ b/src/LogModel.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +class LogModel : public QAbstractListModel { + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) +public: + enum Roles { TextRole = Qt::UserRole + 1 }; + + explicit LogModel(QObject* parent = nullptr) : QAbstractListModel(parent) {} + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + + Q_INVOKABLE void append(const QString& line); + Q_INVOKABLE void clear(); + +signals: + void countChanged(); + +private: + QStringList m_lines; +}; diff --git a/src/blockchain_resources.qrc b/src/blockchain_resources.qrc new file mode 100644 index 0000000..d60a6e9 --- /dev/null +++ b/src/blockchain_resources.qrc @@ -0,0 +1,11 @@ + + + qml/BlockchainView.qml + qml/controls/qmldir + qml/controls/LogosButton.qml + qml/views/qmldir + qml/views/StatusConfigView.qml + qml/views/LogsView.qml + qml/views/WalletView.qml + + diff --git a/src/qml/BlockchainView.qml b/src/qml/BlockchainView.qml new file mode 100644 index 0000000..86d6a52 --- /dev/null +++ b/src/qml/BlockchainView.qml @@ -0,0 +1,110 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import QtCore + +import BlockchainBackend +import Logos.DesignSystem + +import views + +Rectangle { + id: root + + QtObject { + id: _d + function getStatusString(status) { + switch(status) { + case BlockchainBackend.NotStarted: return qsTr("Not Started"); + case BlockchainBackend.Starting: return qsTr("Starting..."); + case BlockchainBackend.Running: return qsTr("Running"); + case BlockchainBackend.Stopping: return qsTr("Stopping..."); + case BlockchainBackend.Stopped: return qsTr("Stopped"); + case BlockchainBackend.Error: return qsTr("Error"); + case BlockchainBackend.ErrorNotInitialized: return qsTr("Error: Module not initialized"); + case BlockchainBackend.ErrorConfigMissing: return qsTr("Error: Config path missing"); + case BlockchainBackend.ErrorStartFailed: return qsTr("Error: Failed to start node"); + case BlockchainBackend.ErrorStopFailed: return qsTr("Error: Failed to stop node"); + case BlockchainBackend.ErrorSubscribeFailed: return qsTr("Error: Failed to subscribe to events"); + default: return qsTr("Unknown"); + } + } + function getStatusColor(status) { + switch(status) { + case BlockchainBackend.Running: return Theme.palette.success; + case BlockchainBackend.Starting: return Theme.palette.warning; + case BlockchainBackend.Stopping: return Theme.palette.warning; + case BlockchainBackend.NotStarted: return Theme.palette.error; + case BlockchainBackend.Stopped: return Theme.palette.error; + case BlockchainBackend.Error: + case BlockchainBackend.ErrorNotInitialized: + case BlockchainBackend.ErrorConfigMissing: + case BlockchainBackend.ErrorStartFailed: + case BlockchainBackend.ErrorStopFailed: + case BlockchainBackend.ErrorSubscribeFailed: return Theme.palette.error; + default: return Theme.palette.textSecondary; + } + } + } + + color: Theme.palette.background + + SplitView { + anchors.fill: parent + anchors.margins: Theme.spacing.large + orientation: Qt.Vertical + + // Top: Status/Config + Wallet side-by-side + RowLayout { + SplitView.fillWidth: true + SplitView.minimumHeight: 200 + + StatusConfigView { + Layout.preferredWidth: parent.width / 2 + statusText: _d.getStatusString(backend.status) + statusColor: _d.getStatusColor(backend.status) + configPath: backend.configPath + canStart: !!backend.configPath + && backend.status !== BlockchainBackend.Starting + && backend.status !== BlockchainBackend.Stopping + isRunning: backend.status === BlockchainBackend.Running + + onStartRequested: backend.startBlockchain() + onStopRequested: backend.stopBlockchain() + onChangeConfigRequested: fileDialog.open() + } + + WalletView { + id: walletView + Layout.preferredWidth: parent.width / 2 + + onGetBalanceRequested: function(addressHex) { + walletView.setBalanceResult(backend.getBalance(addressHex)) + } + onTransferRequested: function(fromKeyHex, toKeyHex, amount) { + walletView.setTransferResult(backend.transferFunds(fromKeyHex, toKeyHex, amount)) + } + } + } + + // Bottom: Logs + LogsView { + SplitView.fillWidth: true + SplitView.minimumHeight: 150 + + logModel: backend.logModel + onClearRequested: backend.clearLogs() + } + } + + FileDialog { + id: fileDialog + modality: Qt.NonModal + nameFilters: ["YAML files (*.yaml)"] + currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0] + onAccepted: { + backend.configPath = selectedFile + } + } +} diff --git a/src/qml/controls/LogosButton.qml b/src/qml/controls/LogosButton.qml new file mode 100644 index 0000000..bcb820e --- /dev/null +++ b/src/qml/controls/LogosButton.qml @@ -0,0 +1,20 @@ +import QtQuick +import QtQuick.Controls + +import Logos.DesignSystem + +Button { + implicitWidth: 200 + implicitHeight: 50 + + background: Rectangle { + color: parent.pressed || parent.hovered ? + Theme.palette.backgroundMuted : + Theme.palette.backgroundSecondary + radius: Theme.spacing.radiusXlarge + border.color: parent.pressed || parent.hovered ? + Theme.palette.overlayOrange : + Theme.palette.border + border.width: 1 + } +} diff --git a/src/qml/controls/qmldir b/src/qml/controls/qmldir new file mode 100644 index 0000000..57997a8 --- /dev/null +++ b/src/qml/controls/qmldir @@ -0,0 +1,2 @@ +module controls +LogosButton 1.0 LogosButton.qml diff --git a/src/qml/views/LogsView.qml b/src/qml/views/LogsView.qml new file mode 100644 index 0000000..e265e96 --- /dev/null +++ b/src/qml/views/LogsView.qml @@ -0,0 +1,92 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Logos.DesignSystem + +import controls + +Control { + id: root + + // --- Public API --- + required property var logModel // LogModel (QAbstractListModel with "text" role) + + signal clearRequested() + + background: Rectangle { + color: Theme.palette.background + } + + ColumnLayout { + anchors.fill: parent + anchors.topMargin: Theme.spacing.large + spacing: Theme.spacing.medium + + // Header + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: implicitHeight + spacing: Theme.spacing.medium + + Text { + text: qsTr("Logs") + font.pixelSize: Theme.typography.secondaryText + font.bold: true + color: Theme.palette.text + } + + Item { Layout.fillWidth: true } + + LogosButton { + text: qsTr("Clear") + Layout.preferredWidth: 80 + Layout.preferredHeight: 32 + onClicked: root.clearRequested() + } + } + + // Log list + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + color: Theme.palette.backgroundSecondary + radius: Theme.spacing.radiusLarge + border.color: Theme.palette.border + border.width: 1 + + ListView { + id: logsListView + anchors.fill: parent + clip: true + model: root.logModel + spacing: 2 + + delegate: Text { + text: model.text + font.pixelSize: Theme.typography.secondaryText + font.family: Theme.typography.publicSans + color: Theme.palette.text + width: logsListView.width + wrapMode: Text.Wrap + } + + Text { + visible: !root.logModel || root.logModel.count === 0 + anchors.centerIn: parent + text: qsTr("No logs yet...") + font.pixelSize: Theme.typography.secondaryText + color: Theme.palette.textSecondary + } + + Connections { + target: root.logModel + function onCountChanged() { + if (root.logModel.count > 0) + logsListView.positionViewAtEnd() + } + } + } + } + } +} diff --git a/src/qml/views/StatusConfigView.qml b/src/qml/views/StatusConfigView.qml new file mode 100644 index 0000000..f71f42b --- /dev/null +++ b/src/qml/views/StatusConfigView.qml @@ -0,0 +1,117 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Logos.DesignSystem +import controls + +ColumnLayout { + id: root + + // --- Public API --- + required property string statusText + required property color statusColor + required property string configPath + required property bool canStart + required property bool isRunning + + signal startRequested() + signal stopRequested() + signal changeConfigRequested() + + spacing: Theme.spacing.large + + // Status Card + Rectangle { + Layout.alignment: Qt.AlignTop + Layout.preferredWidth: parent.width * 0.9 + Layout.preferredHeight: implicitHeight + implicitHeight: statusContent.implicitHeight + 2 * Theme.spacing.large + color: Theme.palette.backgroundTertiary + radius: Theme.spacing.radiusLarge + border.color: Theme.palette.border + border.width: 1 + + ColumnLayout { + id: statusContent + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Theme.spacing.large + spacing: Theme.spacing.medium + + Text { + Layout.alignment: Qt.AlignLeft + font.pixelSize: Theme.typography.primaryText + font.bold: true + text: root.statusText + color: root.statusColor + } + + Text { + Layout.alignment: Qt.AlignLeft + Layout.topMargin: -Theme.spacing.medium + text: qsTr("Mainnet - chain ID 1") + font.pixelSize: Theme.typography.secondaryText + color: Theme.palette.textSecondary + } + + LogosButton { + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: parent.width + Layout.preferredHeight: 50 + enabled: root.canStart + text: root.isRunning ? qsTr("Stop Node") : qsTr("Start Node") + onClicked: root.isRunning ? root.stopRequested() : root.startRequested() + } + } + } + + // Config Card + Rectangle { + Layout.preferredWidth: parent.width * 0.9 + Layout.preferredHeight: implicitHeight + implicitHeight: configContent.implicitHeight + 2 * Theme.spacing.large + color: Theme.palette.backgroundTertiary + radius: Theme.spacing.radiusLarge + border.color: Theme.palette.border + border.width: 1 + + ColumnLayout { + id: configContent + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: Theme.spacing.large + spacing: Theme.spacing.medium + + Text { + text: qsTr("Current Config: ") + font.pixelSize: Theme.typography.primaryText + font.bold: true + color: Theme.palette.text + } + + Text { + Layout.fillWidth: true + Layout.topMargin: -Theme.spacing.medium + text: root.configPath || qsTr("No file selected") + font.pixelSize: Theme.typography.secondaryText + color: Theme.palette.textSecondary + wrapMode: Text.WordWrap + } + + LogosButton { + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: parent.width + Layout.preferredHeight: 50 + text: qsTr("Change") + onClicked: root.changeConfigRequested() + } + } + } + + Item { Layout.fillHeight: true } +} diff --git a/src/qml/views/WalletView.qml b/src/qml/views/WalletView.qml new file mode 100644 index 0000000..31297f5 --- /dev/null +++ b/src/qml/views/WalletView.qml @@ -0,0 +1,141 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import Logos.DesignSystem + +import controls + +ColumnLayout { + id: root + + // --- Public API --- + signal getBalanceRequested(string addressHex) + signal transferRequested(string fromKeyHex, string toKeyHex, string amount) + + // Call these from the parent to display results + function setBalanceResult(text) { + balanceResultText.text = text + } + function setTransferResult(text) { + transferResultText.text = text + } + + spacing: Theme.spacing.medium + + // Get balance card + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: balanceCol.implicitHeight + color: Theme.palette.backgroundTertiary + radius: Theme.spacing.radiusLarge + border.color: Theme.palette.border + border.width: 1 + + ColumnLayout { + id: balanceCol + anchors.fill: parent + anchors.margins: Theme.spacing.large + spacing: Theme.spacing.large + + Text { + text: qsTr("Get balance") + font.pixelSize: Theme.typography.secondaryText + font.bold: true + color: Theme.palette.text + } + + CustomTextFeild { + id: balanceAddressField + placeholderText: qsTr("Wallet address (64 hex chars)") + } + + LogosButton { + text: qsTr("Get balance") + Layout.alignment: Qt.AlignRight + onClicked: root.getBalanceRequested(balanceAddressField.text) + } + + Text { + id: balanceResultText + Layout.fillWidth: true + font.pixelSize: Theme.typography.secondaryText + color: Theme.palette.textSecondary + wrapMode: Text.WordWrap + } + } + } + + // Transfer funds card + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: transferCol.height + color: Theme.palette.backgroundTertiary + radius: Theme.spacing.radiusLarge + border.color: Theme.palette.border + border.width: 1 + + ColumnLayout { + id: transferCol + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Theme.spacing.large + spacing: Theme.spacing.large + + Text { + text: qsTr("Transfer funds") + font.pixelSize: Theme.typography.secondaryText + font.bold: true + color: Theme.palette.text + } + + CustomTextFeild { + placeholderText: qsTr("From key (64 hex chars)") + } + + CustomTextFeild { + id: transferToField + placeholderText: qsTr("To key (64 hex chars)") + } + + CustomTextFeild { + placeholderText: qsTr("Amount") + } + + LogosButton { + text: qsTr("Transfer") + Layout.alignment: Qt.AlignRight + onClicked: root.transferRequested(transferFromField.text, transferToField.text, transferAmountField.text) + } + + Text { + id: transferResultText + Layout.fillWidth: true + font.pixelSize: Theme.typography.secondaryText + color: Theme.palette.textSecondary + wrapMode: Text.WordWrap + } + } + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: Theme.spacing.small + } + + component CustomTextFeild: TextField { + id: textField + Layout.fillWidth: true + placeholderText: qsTr("From key (64 hex chars)") + font.pixelSize: Theme.typography.secondaryText + + background: Rectangle { + radius: Theme.spacing.radiusSmall + color: Theme.palette.backgroundSecondary + border.color: textField.activeFocus ? + Theme.palette.overlayOrange : + Theme.palette.backgroundElevated + } + } +} diff --git a/src/qml/views/qmldir b/src/qml/views/qmldir new file mode 100644 index 0000000..8de2446 --- /dev/null +++ b/src/qml/views/qmldir @@ -0,0 +1,4 @@ +module views +StatusConfigView 1.0 StatusConfigView.qml +LogsView 1.0 LogsView.qml +WalletView 1.0 WalletView.qml \ No newline at end of file