From 1e8c8512831555df67195c53754b4e8877fcb8d4 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 10 May 2022 23:10:34 +0300 Subject: [PATCH] chore(CPP): Basic project configuration setup using Qt6 Considerations - Use versioned files. Versioned Qt CMake APIs are disabled to force explicit calls and say that we don't support older `QT`s - Don't use blobbing. Use `target_sources` and `qt_target_qml_sources` - Distribute `CMake` definitions closer to the context: main folders with their own `CMakeLists.txt` - Everything in libraries under `Status` namespace for cleaner code. - Includes are exposed with Module folder externally and without prefix internally - File/Folders name matches definitions they contain for uniformity that leads to cleaner code - All source files (cpp, qml, js ...) have to be added to one of the CMakeLists.txt files to be tracked by CMake build system. - Use BUILD_DEBUG, BUILD_RELEASE and BUILD_DEVELOPMENT variables from Helpers library - Avoid Include directories. Not needed anymore CMake `target_*` APIs handles this through `INTERFACE`, `PUBLIC` and `PRIVATE` scope identifiers - `StatusQ` is meant to be compiled as an external library, therefore StatusQ tests are kept inside its own directory - Forced CMake version to `3.21` for the latest features and fixes. It is desired to be kept as recent as possible due to its backward compatibility. Following Qt's shipped version might be an option - Depends on status-go changes to allow forcing of arm for apple silicon Found limitations to CMake Qt API with Qt 6.3 - Having `0` as major version when using `qt_add_qml_module` doesn't work. Qml engine reports loading the `qmldir` but won't load the plugin library and no error is reported outside that exposed types are not found. - `qt_target_qml_sources` doesn't work now, it generate a double copy error when deploying qml files in bin-directory. For now we stick with adding files using `qt_add_qml_module` central place - Need to add `OUTPUT_DIRECTORY` to `qt_add_qml_module` to use the workaround - If `MACOSX_BUNDLE` target property is set breaks importing of QML files. Disabled until fixed or workaround found - For an unknown reason application executable tries to include the `QML_ELEMENT` include files, therefore for now I include all the C++ qml elements in INTERFACE --- CMakeLists.txt | 162 +++--------------- README.md | 66 ------- app/CMakeLists.txt | 66 +++++++ app/README.md | 59 +++++++ app/qml/CMakeLists.txt | 15 ++ app/qml/Status/Application/CMakeLists.txt | 12 ++ .../Application/Decorators/SplashScreen.qml | 37 ++++ app/qml/Status/Application/MainShortcuts.qml | 39 +++++ .../Status/Application/MainView/MainView.qml | 35 ++++ .../Status/Application/StatusContentView.qml | 66 +++++++ app/qml/Status/Application/StatusWindow.qml | 59 +++++++ .../Application/System/StatusTrayIcon.qml | 43 +++++ app/qml/main.qml | 18 ++ app/res/CMakeLists.txt | 15 ++ app/res/app.qrc | 5 + app/res/qtquickcontrols2.conf | 2 + app/src/Application/ApplicationController.cpp | 7 + app/src/Application/ApplicationController.h | 19 ++ app/src/Application/CMakeLists.txt | 13 ++ app/src/CMakeLists.txt | 13 ++ app/src/main.cpp | 61 +++++++ cmake/platform_specific.cmake | 5 + cmake/platform_specific/macos.cmake | 11 ++ cmake/platform_specific/windows.cmake | 7 + libs/Assets/CMakeLists.txt | 39 +++++ libs/Assets/qml/Status/Assets/Resources.qml | 17 ++ libs/CMakeLists.txt | 6 + libs/Core/CMakeLists.txt | 32 ++++ libs/Core/res/CMakeLists.txt | 4 + libs/Core/src/CMakeLists.txt | 14 ++ libs/Core/src/Core/CMakeLists.txt | 5 + libs/Helpers/CMakeLists.txt | 57 ++++++ libs/Helpers/src/CMakeLists.txt | 8 + libs/Helpers/src/Helpers/CMakeLists.txt | 7 + libs/Helpers/src/Helpers/helpers.h | 19 ++ .../Helpers/src/Helpers}/logs.cpp | 19 +- {src-cpp => libs/Helpers/src/Helpers}/logs.h | 5 + libs/Helpers/template/BuildConfiguration.h.in | 19 ++ libs/Onboarding/CMakeLists.txt | 32 ++++ .../qml/Status/Onboarding/OnboardingView.qml | 30 ++++ libs/StatusGoQt/CMakeLists.txt | 31 ++++ libs/StatusGoQt/src/CMakeLists.txt | 14 ++ libs/StatusQ/CMakeLists.txt | 27 +++ .../qml/Status/Core/Theme/CMakeLists.txt | 28 +++ .../Status/Core/Theme/StatusDarkPalette.qml | 5 + .../qml/Status/Core/Theme/StatusDarkTheme.qml | 6 + .../Status/Core/Theme/StatusLightPalette.qml | 5 + .../Status/Core/Theme/StatusLightTheme.qml | 6 + .../qml/Status/Core/Theme/StatusPalette.qml | 4 + .../qml/Status/Core/Theme/StatusTheme.qml | 6 + libs/StatusQ/qml/Status/Core/Theme/Style.qml | 27 +++ libs/StatusQ/tests/CMakeLists.txt | 44 +++++ libs/StatusQ/tests/main.cpp | 26 +++ .../qml/StatusQ/TestHelpers/TestUtils.qml | 23 +++ libs/StatusQ/tests/readme.md | 24 +++ libs/StatusQ/tests/src/CMakeLists.txt | 6 + .../tests/src/TestHelpers/CMakeLists.txt | 8 + .../tests/src/TestHelpers/MonitorQtOutput.cpp | 68 ++++++++ .../tests/src/TestHelpers/MonitorQtOutput.h | 43 +++++ test/CMakeLists.txt | 0 {test-cpp => test/unit}/CMakeLists.txt | 0 {test-cpp => test/unit}/testDeps.cpp | 0 ui/imports/assets/CMakeLists.txt | 40 +++++ vendor/CMakeLists.txt | 1 + vendor/conan-configs/apple-arm64.ini | 11 ++ vendor/conan-configs/apple-x86_64.ini | 11 ++ vendor/status-go | 2 +- 67 files changed, 1408 insertions(+), 206 deletions(-) create mode 100644 app/CMakeLists.txt create mode 100644 app/README.md create mode 100644 app/qml/CMakeLists.txt create mode 100644 app/qml/Status/Application/CMakeLists.txt create mode 100644 app/qml/Status/Application/Decorators/SplashScreen.qml create mode 100644 app/qml/Status/Application/MainShortcuts.qml create mode 100644 app/qml/Status/Application/MainView/MainView.qml create mode 100644 app/qml/Status/Application/StatusContentView.qml create mode 100644 app/qml/Status/Application/StatusWindow.qml create mode 100644 app/qml/Status/Application/System/StatusTrayIcon.qml create mode 100644 app/qml/main.qml create mode 100644 app/res/CMakeLists.txt create mode 100644 app/res/app.qrc create mode 100644 app/res/qtquickcontrols2.conf create mode 100644 app/src/Application/ApplicationController.cpp create mode 100644 app/src/Application/ApplicationController.h create mode 100644 app/src/Application/CMakeLists.txt create mode 100644 app/src/CMakeLists.txt create mode 100644 app/src/main.cpp create mode 100644 cmake/platform_specific.cmake create mode 100644 cmake/platform_specific/macos.cmake create mode 100644 cmake/platform_specific/windows.cmake create mode 100644 libs/Assets/CMakeLists.txt create mode 100644 libs/Assets/qml/Status/Assets/Resources.qml create mode 100644 libs/CMakeLists.txt create mode 100644 libs/Core/CMakeLists.txt create mode 100644 libs/Core/res/CMakeLists.txt create mode 100644 libs/Core/src/CMakeLists.txt create mode 100644 libs/Core/src/Core/CMakeLists.txt create mode 100644 libs/Helpers/CMakeLists.txt create mode 100644 libs/Helpers/src/CMakeLists.txt create mode 100644 libs/Helpers/src/Helpers/CMakeLists.txt create mode 100644 libs/Helpers/src/Helpers/helpers.h rename {src-cpp => libs/Helpers/src/Helpers}/logs.cpp (70%) rename {src-cpp => libs/Helpers/src/Helpers}/logs.h (63%) create mode 100644 libs/Helpers/template/BuildConfiguration.h.in create mode 100644 libs/Onboarding/CMakeLists.txt create mode 100644 libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml create mode 100644 libs/StatusGoQt/CMakeLists.txt create mode 100644 libs/StatusGoQt/src/CMakeLists.txt create mode 100644 libs/StatusQ/CMakeLists.txt create mode 100644 libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt create mode 100644 libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml create mode 100644 libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml create mode 100644 libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml create mode 100644 libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml create mode 100644 libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml create mode 100644 libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml create mode 100644 libs/StatusQ/qml/Status/Core/Theme/Style.qml create mode 100644 libs/StatusQ/tests/CMakeLists.txt create mode 100644 libs/StatusQ/tests/main.cpp create mode 100644 libs/StatusQ/tests/qml/StatusQ/TestHelpers/TestUtils.qml create mode 100644 libs/StatusQ/tests/readme.md create mode 100644 libs/StatusQ/tests/src/CMakeLists.txt create mode 100644 libs/StatusQ/tests/src/TestHelpers/CMakeLists.txt create mode 100644 libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp create mode 100644 libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h create mode 100644 test/CMakeLists.txt rename {test-cpp => test/unit}/CMakeLists.txt (100%) rename {test-cpp => test/unit}/testDeps.cpp (100%) create mode 100644 ui/imports/assets/CMakeLists.txt create mode 100644 vendor/CMakeLists.txt create mode 100644 vendor/conan-configs/apple-arm64.ini create mode 100644 vendor/conan-configs/apple-x86_64.ini diff --git a/CMakeLists.txt b/CMakeLists.txt index c45373559e..0359bcfae4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,148 +1,34 @@ -cmake_minimum_required(VERSION 3.18) +# Provide general project configuration setup +# +cmake_minimum_required(VERSION 3.21) + +set(STATUS_QT_VERSION 6.3) +set(STATUS_VERSION 0.6.0) project(status-desktop - VERSION 0.1.0 + VERSION ${STATUS_VERSION} LANGUAGES CXX) -if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) - message( - FATAL_ERROR - "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there." - ) -endif() +set(PROJECT_ORGANIZATION_DOMAIN "status.im") +set(PROJECT_ORGANIZATION_NAME "Status") +set(PROJECT_APPLICATION_NAME "Status Desktop") -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) -endif() - -message(STATUS "Started CMake for ${PROJECT_NAME} v${PROJECT_VERSION}...\n") - -include(ExternalProject) - -# QtCreator supports the following variables for Android, which are identical to qmake Android variables. -# Check https://doc.qt.io/qt/deployment-android.html for more information. -# They need to be set before the find_package(...) calls below. - -#if(ANDROID) -# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") -# if (ANDROID_ABI STREQUAL "armeabi-v7a") -# set(ANDROID_EXTRA_LIBS -# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so -# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) -# endif() -#endif() - -find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick Widgets Concurrent REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick Widgets Concurrent REQUIRED) - -set(PROJECT_SOURCES - src-cpp/main.cpp - src-cpp/constants.cpp - src-cpp/logs.cpp - resources.rcc -) - -if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) - qt_add_executable(status-desktop - ${PROJECT_SOURCES} - ) -else() - if(ANDROID) - add_library(status-desktop SHARED - ${PROJECT_SOURCES} - ) - else() - add_executable(status-desktop - ${PROJECT_SOURCES} - ) - endif() -endif() - - -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vendor/status-go bin/status-go) - -# The following are dependencies that do not include CMakeList.txt files -# Create a PR in those projects so we can include them just like it was -# done with status-go -include(cmake/QRCodeGen.cmake) -include(cmake/Keycard.cmake) - -# Submodiles -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src-cpp/dotherside) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src-cpp/app) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src-cpp/app_service) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src-cpp/backend) - -target_include_directories(status-desktop PUBLIC include) - - -target_compile_definitions(status-desktop - PRIVATE $<$,$>:QT_QML_DEBUG>) - -target_link_libraries(status-desktop - PRIVATE - Qt${QT_VERSION_MAJOR}::Core - Qt${QT_VERSION_MAJOR}::Quick - Qt${QT_VERSION_MAJOR}::Widgets - DOtherSide - statusgo_shared # <- Link status-go with this target (remove `_shared` for static linking) - qrcodegen - keycard - app_service - app - ) - - -add_custom_target(rcc ALL DEPENDS resources.rcc) -add_custom_command( - OUTPUT resources.rcc - COMMENT "Building resources.rcc" - COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_SOURCE_DIR}/resources.rcc - COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_SOURCE_DIR}/ui/resources.qrc - COMMAND go run - ${CMAKE_CURRENT_SOURCE_DIR}/ui/generate-rcc.go - -source=${CMAKE_CURRENT_SOURCE_DIR}/ui - -output=${CMAKE_CURRENT_SOURCE_DIR}/ui/resources.qrc - COMMAND rcc - --binary - $<$:--no-compress> - ${CMAKE_CURRENT_SOURCE_DIR}/ui/resources.qrc - ${CMAKE_CURRENT_SOURCE_DIR}/resources/resources.qrc - -o ${CMAKE_CURRENT_SOURCE_DIR}/resources.rcc - VERBATIM - USES_TERMINAL -) - - -# run -add_custom_target(run - COMMENT "Execute desktop" - DEPENDS status-desktop - COMMAND ./status-desktop - VERBATIM - USES_TERMINAL -) - - -# run debug -add_custom_target(run-debug - COMMENT "Execute desktop with debugger on port 1234" - DEPENDS status-desktop - COMMAND ./status-desktop -qmljsdebugger=port:1234 - VERBATIM - USES_TERMINAL -) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) include(CTest) -if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) - add_subdirectory(test-cpp) +enable_testing() + +if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64" AND APPLE) + set(STATUSGO_FORCE_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) endif() + +# status-desktop application +add_subdirectory(vendor) +add_subdirectory(libs) +add_subdirectory(app) +add_subdirectory(test) +# TODO: temporary not to duplicate resources until we switch to c++ app then it can be refactored +add_subdirectory(ui/imports/assets) diff --git a/README.md b/README.md index a9bdb613b7..ad9e66824d 100644 --- a/README.md +++ b/README.md @@ -5,69 +5,3 @@ Desktop client for the [Status Network](https://statusnetwork.com/) built with [ ![https://github.com/status-im/nim-status-client/blob/master/screenshot.png](https://github.com/status-im/nim-status-client/blob/master/screenshot.png) Dev Docs: [https://hackmd.io/@status-desktop/B1naRjxh_/https%3A%2F%2Fhackmd.io%2F%40status-desktop%2FB1eOaf-nd](https://hackmd.io/@status-desktop/B1naRjxh_/https%3A%2F%2Fhackmd.io%2F%40status-desktop%2FB1eOaf-nd) - - - - - -# CPP App - -### Setup `Linux`: -1. conancenter -Execute `conan remote list`. It should return this line among the results. -``` -conancenter: https://center.conan.io [Verify SSL: True] -``` -If it doesnt, consider upgrading conan with `pip install conan --upgrade` and then executing. `conan remote add -i 0 conancenter https://center.conan.io` . See [conan's documentation](https://docs.conan.io/en/latest/uploading_packages/remotes.html#conancenter) for more info. - - -2. conan libstdc++11 -This applies to linux: the default conan profile does not work, since GCC uses the new C++ ABI since version 5.1 and conan, for compatibility purposes uses the old C++ ABI. -Execute this to update the profile: -``` -conan profile update settings.compiler.libcxx=libstdc++11 default -``` - -3. Install dependencies: - -``` -cd build -conan install .. -s build_type=Release --build=missing -``` - -### Setup `OS X`: - -1. Create `conan` profile `~/.conan/profiles/clang`: -``` -[settings] -compiler=apple-clang -compiler.version=12.0 -compiler.libcxx=libc++ -arch=x86_64 -os=Macos -build_type=Release - -[env] -CC=/usr/bin/clang -CXX=/usr/bin/clang++ -``` - -2. Install dependecies: - -``` -cd build -conan install .. --profile=clang --build=missing -``` - -### Buid & test & run: -``` -conan build .. -ctest -VV -C Release -./status-desktop -``` - -Instead of `conan build ..` CMake may be used: -``` -cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -cmake --build . --config Release -``` diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000000..4cee61abfe --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,66 @@ +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +set(CMAKE_AUTORCC On) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick REQUIRED) +qt6_standard_project_setup() + +qt6_add_executable(${PROJECT_NAME} "") + +# TODO: Fix temporarly workaround until we make qt6_target_qml_sources work +# Adds qml files as /Status/Application/qml/.../ +qt6_add_qml_module(${PROJECT_NAME} + URI Status.Application + VERSION 1.0 + QML_FILES + qml/main.qml + qml/Status/Application/StatusWindow.qml + qml/Status/Application/StatusContentView.qml + qml/Status/Application/MainShortcuts.qml + + qml/Status/Application/MainView/MainView.qml + + qml/Status/Application/System/StatusTrayIcon.qml + + qml/Status/Application/Decorators/SplashScreen.qml + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Application +) + +# Compile time definitions required by the project +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_PROJECT_NAME=${PROJECT_NAME}) +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_PROJECT_ORGANIZATION_DOMAIN=${PROJECT_ORGANIZATION_DOMAIN}) +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_PROJECT_ORGANIZATION_NAME=${PROJECT_ORGANIZATION_NAME}) +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_PROJECT_APPLICATION_NAME=${PROJECT_APPLICATION_NAME}) + +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_BINARY_DIR=${CMAKE_BINARY_DIR}) +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_SOURCE_DIR=${CMAKE_SOURCE_DIR}) + +add_subdirectory(qml) +add_subdirectory(src) +add_subdirectory(res) + +include(${CMAKE_SOURCE_DIR}/cmake/platform_specific.cmake) +string(TOLOWER ${PROJECT_ORGANIZATION_NAME} URL_ORGANIZATION_NAME) +configure_app_os_specific(${PROJECT_NAME} ${URL_ORGANIZATION_NAME} ${PROJECT_ORGANIZATION_DOMAIN} ${PROJECT_VERSION_MAJOR} ${PROJECT_VERSION_MINOR} ${PROJECT_VERSION_PATCH}) + +target_compile_definitions(${PROJECT_NAME} + PRIVATE + $<$,$>:QT_QML_DEBUG> +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + + # TODO: Use Status:: namespace + #Core + Helpers + Onboarding + Assets +) + +# QtCreator needs this +set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/qml;${QML_IMPORT_PATH} CACHE STRING "For QtCreator" FORCE) +list(REMOVE_DUPLICATES QML_IMPORT_PATH) + diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000000..4b3a0ff353 --- /dev/null +++ b/app/README.md @@ -0,0 +1,59 @@ +# CPP App + +## Setup dependencies + +### 1. conancenter + +Execute `conan remote list`. It should return this line among the results: + +```bash +conancenter: https://center.conan.io [Verify SSL: True] +``` + +If it doesn't, consider upgrading conan with `pip install conan --upgrade` and then executing. `conan remote add -i 0 conancenter https://center.conan.io`. See [conan's documentation](https://docs.conan.io/en/latest/uploading_packages/remotes.html#conancenter) for more info. + +### 2. conan libstdc++11 + +This applies to linux: the default conan profile does not work, since GCC uses the new C++ ABI since version 5.1 and conan, for compatibility purposes uses the old C++ ABI. +Execute this to update the profile: + +```bash +conan profile update settings.compiler.libcxx=libstdc++11 default +``` + +### 2. Install dependencies + +```bash +conan install . --profile= -s build_type=Release --build=missing -if=build/conan +``` + +Platform specific conan profile + +- Macos: + - Intel: `vendor/conan-configs/apple-arm64.ini` + - Apple silicon: `vendor/conan-configs/apple-x86_64.ini` +- Windows: TODO +- Linux: TODO + +## Buid, test & run + +Platform specific Qt prefix path + +- Macos: `$HOME/Qt/6.3.0/macos` +- Windows: TODO +- Linux: TODO + +### Build with conan + +```bash +CMAKE_PREFIX_PATH= conan build . -if=build/conan -bf=build +ctest -VV -C Release +./status-desktop +``` + +### Build with cmake + +```bash +cmake -B build -S . -DCMAKE_PREFIX_PATH= -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/conan/conan_toolchain.cmake +cmake --build build --config Release +``` diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt new file mode 100644 index 0000000000..5427c466c2 --- /dev/null +++ b/app/qml/CMakeLists.txt @@ -0,0 +1,15 @@ +# Note that the automatic plugin generation is only possible if the module does not do anything besides registering the types. +# If it needs to do something more advanced like registering an image provider in initializeEngine, you still need to manually write the plugin. qt6_add_qml_module has support for this with NO_GENERATE_PLUGIN_SOURCE. + +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + +add_subdirectory(Status/Application) + +# Qt 6.3 fails calling qt6_target_qml_sources +#qt6_target_qml_sources(${PROJECT_NAME} +# QML_FILES +# main.qml +#) diff --git a/app/qml/Status/Application/CMakeLists.txt b/app/qml/Status/Application/CMakeLists.txt new file mode 100644 index 0000000000..72161748f1 --- /dev/null +++ b/app/qml/Status/Application/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + +# Qt 6.3 fails calling qt6_target_qml_sources +#qt6_target_qml_sources(${PROJECT_NAME} +# QML_FILES +# StatusWindow.qml +# StatusContentView.qml +# TODO +#) diff --git a/app/qml/Status/Application/Decorators/SplashScreen.qml b/app/qml/Status/Application/Decorators/SplashScreen.qml new file mode 100644 index 0000000000..269208c6b5 --- /dev/null +++ b/app/qml/Status/Application/Decorators/SplashScreen.qml @@ -0,0 +1,37 @@ +import QtQuick + +import Status.Assets +import Status.Core.Theme + +Item { + id: root + + signal animationFinished() + function show() { + splashLogo.playing = true + } + + implicitWidth: splashLogo.implicitWidth + implicitHeight: splashLogo.implicitHeight + + visible: (opacity > 0.0001) + + // TODO: consider bringing POC attempt to use lottie animations + AnimatedImage { + id: splashLogo + anchors.centerIn: parent + scale: 0.5 + source: Resources.gif("status_splash_" + Style.theme.name) + + readonly property real frameToStartAnimation: frameCount/2 + readonly property real animationRange: (frameCount - frameToStartAnimation) + + onCurrentFrameChanged: { + if(currentFrame > frameToStartAnimation) + root.opacity = 1 - (currentFrame - frameToStartAnimation)/animationRange + if(currentFrame === (frameCount - 1)) + root.animationFinished() + } + playing: false + } +} diff --git a/app/qml/Status/Application/MainShortcuts.qml b/app/qml/Status/Application/MainShortcuts.qml new file mode 100644 index 0000000000..a1c17ce3da --- /dev/null +++ b/app/qml/Status/Application/MainShortcuts.qml @@ -0,0 +1,39 @@ +import QtQuick + +/*! + */ +Item { + required property Window window; + property alias enableHideWindow: hideWindowShortcut.enabled + + Shortcut { + sequence: StandardKey.FullScreen + onActivated: { + if (visibility === Window.FullScreen) + window.showNormal() + else + window.showFullScreen() + } + } + + Shortcut { + sequence: "Ctrl+M" + onActivated: { + if (visibility === Window.Minimized) + window.showNormal() + else + window.showMinimized() + } + } + + Shortcut { + id: hideWindowShortcut + sequences: [StandardKey.Close] + onActivated: window.visible = false; + } + + Shortcut { + sequence: StandardKey.Quit + onActivated: Qt.quit() + } +} diff --git a/app/qml/Status/Application/MainView/MainView.qml b/app/qml/Status/Application/MainView/MainView.qml new file mode 100644 index 0000000000..f4b2cde6e9 --- /dev/null +++ b/app/qml/Status/Application/MainView/MainView.qml @@ -0,0 +1,35 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +/// Responsible for setup of user workflows after onboarding +Item { + id: root + + /// Emited when everything is loaded and UX ready + signal ready() + + Component.onCompleted: root.ready() + + implicitWidth: mainLayout.implicitWidth + implicitHeight: mainLayout.implicitHeight + + ColumnLayout { + id: mainLayout + + anchors.fill: parent + + RowLayout {} + Label { + Layout.alignment: Qt.AlignHCenter + text: "TODO MainView" + } + Button { + text: "Quit" + Layout.alignment: Qt.AlignHCenter + onClicked: Qt.quit() + } + + RowLayout {} + } +} diff --git a/app/qml/Status/Application/StatusContentView.qml b/app/qml/Status/Application/StatusContentView.qml new file mode 100644 index 0000000000..a596d8c8d0 --- /dev/null +++ b/app/qml/Status/Application/StatusContentView.qml @@ -0,0 +1,66 @@ +import QtQml +import QtQuick +import QtQuick.Controls + +import Status.Application +import Status.Onboarding + +/// Has entry responsibility for the main workflows +Item { + id: root + + implicitWidth: d.isViewLoaded ? d.loadedView.implicitWidth : 800 + implicitHeight: d.isViewLoaded ? d.loadedView.implicitHeight : 600 + + QtObject { + id: d + + readonly property bool isViewLoaded: contentLoader.status === Loader.Ready + readonly property Item loadedView: isViewLoaded ? contentLoader.item : null + } + + Component { + id: onboardingViewComponent + + OnboardingView { + onUserLoggedIn: { + splashScreenPopup.open() + contentLoader.sourceComponent = mainViewComponent + } + } + } + + Component { + id: mainViewComponent + + MainView { + onReady: splashScreenPopup.close() + } + } + + Popup { + id: splashScreenPopup + + onAboutToShow: splashScreenLoader.active = true + onClosed: splashScreenLoader.active = false + anchors.centerIn: Overlay.overlay + + Loader { + id: splashScreenLoader + active: false + sourceComponent: SplashScreen { + id: splasScreen + onAnimationFinished: splashScreenPopup.close() + } + onStatusChanged: if(status === Loader.Ready) item.show() + } + background: Item {} + } + + Loader { + id: contentLoader + + anchors.fill: parent + sourceComponent: onboardingViewComponent + } +} diff --git a/app/qml/Status/Application/StatusWindow.qml b/app/qml/Status/Application/StatusWindow.qml new file mode 100644 index 0000000000..45149ee589 --- /dev/null +++ b/app/qml/Status/Application/StatusWindow.qml @@ -0,0 +1,59 @@ +import QtQuick +import QtQuick.Layouts + +import Qt.labs.settings + +import Status.Application + +/** Administrative scope + */ +Window { + id: root + + minimumWidth: 900 + minimumHeight: 600 + + Component.onCompleted: { + width: mainLayout.implicitWidth + height: mainLayout.implicitHeight + } + + visible: true + title: qsTr(Qt.application.name) + + flags: Qt.FramelessWindowHint + + ColumnLayout { + id: mainLayout + + anchors.fill: parent + + // TODO: nav-bar? +// StatusAppNavBar { +// } + + StatusContentView { + Layout.fillWidth: true + Layout.fillHeight: true + } + } + + ApplicationController { + id: appController + } + + Settings { + property alias x: root.x + property alias y: root.y + property alias width: root.width + property alias height: root.height + + // TODO: set this in non-deployment to the development "Status" folder + //fileName: `${appController.userSettings.directory}/appController.userSettings.fileName` + } + + MainShortcuts { + window: root + enableHideWindow: true // TODO: Only if browser selected + } +} diff --git a/app/qml/Status/Application/System/StatusTrayIcon.qml b/app/qml/Status/Application/System/StatusTrayIcon.qml new file mode 100644 index 0000000000..f45bd0b69e --- /dev/null +++ b/app/qml/Status/Application/System/StatusTrayIcon.qml @@ -0,0 +1,43 @@ +import QtQuick +import QtQuick.Controls + +import Qt.labs.platform + +import Status.Assets + +SystemTrayIcon { + id: root + + property bool production: true + + signal showApplication() + + visible: true + icon.source: { + if (production) + return Qt.platform.os === "osx" ? Resources.svg("status-logo-icon") : Resources.png("status-logo") + else + return Resources.svg("status-logo-dark") + } + icon.mask: false + + menu: Menu { + MenuItem { + text: qsTr("Open Status") + onTriggered: root.showApplication() + } + + MenuSeparator { + } + + MenuItem { + text: qsTr("Quit") + onTriggered: Qt.quit() + } + } + + onActivated: function (reason) { + if (reason !== SystemTrayIcon.Context && Qt.platform.os !== "osx") + root.showApplication() + } +} diff --git a/app/qml/main.qml b/app/qml/main.qml new file mode 100644 index 0000000000..746a23adc5 --- /dev/null +++ b/app/qml/main.qml @@ -0,0 +1,18 @@ +import QtQuick + +import Status.Application + +/** + QML entry point with minimal responsibilities + */ +StatusWindow { + id: root + + StatusTrayIcon { + onShowApplication: { + root.show() + root.raise() + root.requestActivate() + } + } +} diff --git a/app/res/CMakeLists.txt b/app/res/CMakeLists.txt new file mode 100644 index 0000000000..9f524c7b9d --- /dev/null +++ b/app/res/CMakeLists.txt @@ -0,0 +1,15 @@ +# TODO workaround until Qt6 API is clarified +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/app.qrc + + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + +# TODO find out why it isn't working +# +#qt6_target_qml_sources(${PROJECT_NAME} +# RESOURCES +# qtquickcontrols2.conf +# PREFIX "" +#) diff --git a/app/res/app.qrc b/app/res/app.qrc new file mode 100644 index 0000000000..4fbf17b7bb --- /dev/null +++ b/app/res/app.qrc @@ -0,0 +1,5 @@ + + + qtquickcontrols2.conf + + diff --git a/app/res/qtquickcontrols2.conf b/app/res/qtquickcontrols2.conf new file mode 100644 index 0000000000..8c6dd807e3 --- /dev/null +++ b/app/res/qtquickcontrols2.conf @@ -0,0 +1,2 @@ +[Controls] +Style=Universal diff --git a/app/src/Application/ApplicationController.cpp b/app/src/Application/ApplicationController.cpp new file mode 100644 index 0000000000..4cf3bd047d --- /dev/null +++ b/app/src/Application/ApplicationController.cpp @@ -0,0 +1,7 @@ +#include "ApplicationController.h" + +ApplicationController::ApplicationController(QObject *parent) + : QObject{parent} +{ + +} diff --git a/app/src/Application/ApplicationController.h b/app/src/Application/ApplicationController.h new file mode 100644 index 0000000000..91c65cdef5 --- /dev/null +++ b/app/src/Application/ApplicationController.h @@ -0,0 +1,19 @@ +#pragma once + + +#include +#include + +/** + * @brief Responsible for providing general information and utility components + */ +class ApplicationController : public QObject +{ + Q_OBJECT + QML_ELEMENT +public: + explicit ApplicationController(QObject *parent = nullptr); + +signals: + +}; diff --git a/app/src/Application/CMakeLists.txt b/app/src/Application/CMakeLists.txt new file mode 100644 index 0000000000..ac832e0c18 --- /dev/null +++ b/app/src/Application/CMakeLists.txt @@ -0,0 +1,13 @@ +# Required by QML_ELEMENT +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/ApplicationController.h + ${CMAKE_CURRENT_SOURCE_DIR}/ApplicationController.cpp + + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) diff --git a/app/src/CMakeLists.txt b/app/src/CMakeLists.txt new file mode 100644 index 0000000000..948224da11 --- /dev/null +++ b/app/src/CMakeLists.txt @@ -0,0 +1,13 @@ +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + +add_subdirectory(Application) diff --git a/app/src/main.cpp b/app/src/main.cpp new file mode 100644 index 0000000000..53ec7bf312 --- /dev/null +++ b/app/src/main.cpp @@ -0,0 +1,61 @@ +#include +#include + +#include +#include + +#include +#include + +#include +#include + +using namespace Status; + +void setApplicationInformation(QGuiApplication& app); + +int main(int argc, char *argv[]) +{ + //qInstallMessageHandler(Helpers::logFormatter); + + QGuiApplication app(argc, argv); + + setApplicationInformation(app); + + QTranslator translator; + const QStringList uiLanguages = QLocale::system().uiLanguages(); + for (const QString &locale : uiLanguages) { + const QString baseName = STRINGIFY(BUILD_PROJECT_NAME) + QLocale(locale).name(); + if (translator.load(":/i18n/" + baseName)) { + app.installTranslator(&translator); + break; + } + } + + QQmlApplicationEngine engine; + + const QUrl url(u"qrc:/Status/Application/qml/main.qml"_qs); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, + &app, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} + +void setApplicationInformation(QGuiApplication& app) { +#if !defined BUILD_PROJECT_ORGANIZATION_NAME + static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_NAME") +#endif + app.setOrganizationName(STRINGIFY(BUILD_PROJECT_ORGANIZATION_NAME)); +#if !defined BUILD_PROJECT_ORGANIZATION_DOMAIN + static_assert(false, "Compile-time define missing: BUILD_PROJECT_ORGANIZATION_DOMAIN") +#endif + app.setOrganizationDomain(STRINGIFY(BUILD_PROJECT_ORGANIZATION_DOMAIN)); +#if !defined BUILD_PROJECT_APPLICATION_NAME + static_assert(false, "Compile-time define missing: BUILD_PROJECT_APPLICATION_NAME") +#endif + app.setApplicationName(STRINGIFY(BUILD_PROJECT_APPLICATION_NAME)); +} diff --git a/cmake/platform_specific.cmake b/cmake/platform_specific.cmake new file mode 100644 index 0000000000..b4dd4e3ee4 --- /dev/null +++ b/cmake/platform_specific.cmake @@ -0,0 +1,5 @@ +if(WIN32) + include(${CMAKE_CURRENT_LIST_DIR}/platform_specific/windows.cmake) +elseif(APPLE) + include(${CMAKE_CURRENT_LIST_DIR}/platform_specific/macos.cmake) +endif() \ No newline at end of file diff --git a/cmake/platform_specific/macos.cmake b/cmake/platform_specific/macos.cmake new file mode 100644 index 0000000000..42d12e01c2 --- /dev/null +++ b/cmake/platform_specific/macos.cmake @@ -0,0 +1,11 @@ +function(configure_app_os_specific TARGET_ARG URL_ORGANIZATION_NAME DOMAIN_ARG VERSION_MAJOR VERSION_MINOR VERSION_PATCH) + + set_target_properties(${TARGET_ARG} PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER ${URL_ORGANIZATION_NAME}.${DOMAIN_ARG} + MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MINOR}.${VERSION_PATCH} + # TODO: This breaks debugging QML imports + #MACOSX_BUNDLE TRUE + ) + +endfunction() \ No newline at end of file diff --git a/cmake/platform_specific/windows.cmake b/cmake/platform_specific/windows.cmake new file mode 100644 index 0000000000..86884c8592 --- /dev/null +++ b/cmake/platform_specific/windows.cmake @@ -0,0 +1,7 @@ +function(configure_app_os_specific) + +set_target_properties(${PROJECT_NAME} PROPERTIES + WIN32_EXECUTABLE TRUE +) + +endfunction() \ No newline at end of file diff --git a/libs/Assets/CMakeLists.txt b/libs/Assets/CMakeLists.txt new file mode 100644 index 0000000000..178dbab01d --- /dev/null +++ b/libs/Assets/CMakeLists.txt @@ -0,0 +1,39 @@ +# Global not theme dependent assets +# TODO: refactor it when switching to C++ code into Assets resource library linked or embed with the app +# +cmake_minimum_required(VERSION 3.21) + +project(Assets + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Qml REQUIRED) +qt6_standard_project_setup() + +set_source_files_properties(qml/Status/Assets/Resources.qml PROPERTIES + QT_QML_SINGLETON_TYPE TRUE +) + +qt6_add_qml_module(${PROJECT_NAME} + URI Status.Assets + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + qml/Status/Assets/Resources.qml + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Assets/ +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Qml + + # TODO: refactor when moved to C++ code + UiAssets +) + +# QtCreator needs this +set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/qml;${QML_IMPORT_PATH} CACHE STRING "For QtCreator" FORCE) +list(REMOVE_DUPLICATES QML_IMPORT_PATH) diff --git a/libs/Assets/qml/Status/Assets/Resources.qml b/libs/Assets/qml/Status/Assets/Resources.qml new file mode 100644 index 0000000000..547b11d8cf --- /dev/null +++ b/libs/Assets/qml/Status/Assets/Resources.qml @@ -0,0 +1,17 @@ +pragma Singleton + +import QtQml + +QtObject { + readonly property string assetPath: "qrc:/Status/UiAssets" + + function svg(name) { + return assetPath + "/icons/" + name + ".svg"; + } + function lottie(name) { + return assetPath + "/lottie/" + name + ".json"; + } + function gif(name) { + return assetPath + "/gif/" + name + ".gif"; + } +} diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt new file mode 100644 index 0000000000..3ea3bc0c90 --- /dev/null +++ b/libs/CMakeLists.txt @@ -0,0 +1,6 @@ +add_subdirectory(Helpers) +# TODO: enable after adding content +#add_subdirectory(Core) +add_subdirectory(StatusQ) +add_subdirectory(Onboarding) +add_subdirectory(Assets) diff --git a/libs/Core/CMakeLists.txt b/libs/Core/CMakeLists.txt new file mode 100644 index 0000000000..5d193bfd3a --- /dev/null +++ b/libs/Core/CMakeLists.txt @@ -0,0 +1,32 @@ +# Base library. Expect most of the module libraries to depend on it +# +cmake_minimum_required(VERSION 3.21) + +project(Core + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED) +qt6_standard_project_setup() + +qt6_add_qml_module(${PROJECT_NAME} + URI Status.Core + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + qml/Status/Core/DevTest.qml + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Core +) + +add_subdirectory(qml/Status/Core) +add_subdirectory(src) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml +) diff --git a/libs/Core/res/CMakeLists.txt b/libs/Core/res/CMakeLists.txt new file mode 100644 index 0000000000..06a32a1b4f --- /dev/null +++ b/libs/Core/res/CMakeLists.txt @@ -0,0 +1,4 @@ +qt6_add_resources(${PROJECT_NAME} imageresources + PREFIX "/images" + FILES logo.png splashscreen.png +) \ No newline at end of file diff --git a/libs/Core/src/CMakeLists.txt b/libs/Core/src/CMakeLists.txt new file mode 100644 index 0000000000..a9fa39f4e0 --- /dev/null +++ b/libs/Core/src/CMakeLists.txt @@ -0,0 +1,14 @@ +# Internally we use includes directly +# External clients have to explicitly use the module name +add_subdirectory(Core) + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Core + # TODO: Workaround to QML_ELEMENT Qt6 + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/Core + + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/libs/Core/src/Core/CMakeLists.txt b/libs/Core/src/Core/CMakeLists.txt new file mode 100644 index 0000000000..124b911e08 --- /dev/null +++ b/libs/Core/src/Core/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${PROJECT_NAME} + PRIVATE + + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) diff --git a/libs/Helpers/CMakeLists.txt b/libs/Helpers/CMakeLists.txt new file mode 100644 index 0000000000..93384c1082 --- /dev/null +++ b/libs/Helpers/CMakeLists.txt @@ -0,0 +1,57 @@ +# Light helpers library expected to be used by all other libraries +# +cmake_minimum_required(VERSION 3.21) + +project(Helpers + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED) +qt6_standard_project_setup() + +add_library(${PROJECT_NAME} SHARED "") + +# Setup configuration type (Debug/Release) +# Inspired by https://programmingrecluse.wordpress.com/2020/02/04/detect-debug-build-with-cmake/ +if(CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES Debug Release) +elseif(NOT CMAKE_BUILD_TYPE) + message("Missing Build Type! Run cmake with:\n-DCMAKE_BUILD_TYPE=Debug|Release") +endif() + +# Use by linker only +set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug) + +# Setup BUILD_DEBUG and BUILD_REALEASE if single configuration builds +if(CMAKE_BUILD_TYPE) + string(TOUPPER "${CMAKE_BUILD_TYPE}" _upper_build_type) + set(BUILD_${_upper_build_type} true) +endif() + +set(BUILD_GENERATED_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/template/BuildConfiguration.h.in" + "${BUILD_GENERATED_DIRECTORY}/Helpers/BuildConfiguration.h" + @ONLY) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${BUILD_GENERATED_DIRECTORY} + PRIVATE + ${BUILD_GENERATED_DIRECTORY}/Helpers +) + +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/template/BuildConfiguration.h.in +) + +add_subdirectory(src) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml +) diff --git a/libs/Helpers/src/CMakeLists.txt b/libs/Helpers/src/CMakeLists.txt new file mode 100644 index 0000000000..0ef4e7d5b1 --- /dev/null +++ b/libs/Helpers/src/CMakeLists.txt @@ -0,0 +1,8 @@ +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Helpers +) + +add_subdirectory(Helpers) \ No newline at end of file diff --git a/libs/Helpers/src/Helpers/CMakeLists.txt b/libs/Helpers/src/Helpers/CMakeLists.txt new file mode 100644 index 0000000000..e0e4f12665 --- /dev/null +++ b/libs/Helpers/src/Helpers/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/helpers.h + ${CMAKE_CURRENT_SOURCE_DIR}/logs.h + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/logs.cpp +) diff --git a/libs/Helpers/src/Helpers/helpers.h b/libs/Helpers/src/Helpers/helpers.h new file mode 100644 index 0000000000..e3978f93f4 --- /dev/null +++ b/libs/Helpers/src/Helpers/helpers.h @@ -0,0 +1,19 @@ +#include + +namespace Status::Helpers { + +constexpr bool isDebugBuild() +{ + #if defined BUILD_DEBUG + return true; + #else + return false; + #endif +} + +} + +#if !defined STRINGIFY + #define STRINGIFY(X) STRIFY(X) + #define STRIFY(X) #X +#endif diff --git a/src-cpp/logs.cpp b/libs/Helpers/src/Helpers/logs.cpp similarity index 70% rename from src-cpp/logs.cpp rename to libs/Helpers/src/Helpers/logs.cpp index 2804feab62..a4dbff7dd7 100644 --- a/src-cpp/logs.cpp +++ b/libs/Helpers/src/Helpers/logs.cpp @@ -1,9 +1,23 @@ +#include "helpers.h" + #include #include #include +#include + +#include + +namespace Status::Helpers { + void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg) { + // TODO: Refactor it into development-tools app + //if(isDebugBuild()) { + std::cout << msg.toLocal8Bit().data() << std::endl; + return; + //} + QByteArray localMsg = msg.toLocal8Bit(); const char* file = context.file ? context.file : ""; QByteArray function = @@ -22,5 +36,8 @@ void logFormatter(QtMsgType type, const QMessageLogContext& context, const QStri case QtCriticalMsg: log = "\033[0;91mCRT \033[0m%s \033[1;91m%s \033[0;33mfile=\033[94m%s:%u %s\n"; break; case QtFatalMsg: log = "\033[0;31m!!! \033[0m%s \033[1m%s \033[0;33mfile=\033[94m%s:%u %s\n"; break; } - fprintf(stderr, log, timestamp.constData(), localMsg.constData(), file, context.line, function.constData()); + fprintf(type == QtCriticalMsg || type == QtFatalMsg ? stderr : stdout, + log, timestamp.constData(), localMsg.constData(), file, context.line, function.constData()); } + +} // namespace diff --git a/src-cpp/logs.h b/libs/Helpers/src/Helpers/logs.h similarity index 63% rename from src-cpp/logs.h rename to libs/Helpers/src/Helpers/logs.h index c200da52cb..8462595f3d 100644 --- a/src-cpp/logs.h +++ b/libs/Helpers/src/Helpers/logs.h @@ -4,4 +4,9 @@ #include #include +namespace Status::Helpers { + +/// Formats with colloring output if not a development build void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg); + +} diff --git a/libs/Helpers/template/BuildConfiguration.h.in b/libs/Helpers/template/BuildConfiguration.h.in new file mode 100644 index 0000000000..9fa0f80dca --- /dev/null +++ b/libs/Helpers/template/BuildConfiguration.h.in @@ -0,0 +1,19 @@ +// Cross platform and environment build definition +#if defined(_MSC_VER) + // The microsoft compiler sets _DEBUG appropriately when targeting a debug build. + #if _DEBUG + #define BUILD_DEBUG 1 + #else + #define BUILD_RELEASE 1 + #endif +#elif defined(__apple_build_version__) + // Xcode might set DEBUG when targeting debug, maybe. + #if DEBUG + #define BUILD_DEBUG 1 + #else + #define BUILD_RELEASE 1 + #endif +#else + #cmakedefine BUILD_DEBUG 1 + #cmakedefine BUILD_RELEASE 1 +#endif diff --git a/libs/Onboarding/CMakeLists.txt b/libs/Onboarding/CMakeLists.txt new file mode 100644 index 0000000000..76abc1355d --- /dev/null +++ b/libs/Onboarding/CMakeLists.txt @@ -0,0 +1,32 @@ +# Base library. Expect most of the module libraries to depend on it +# +cmake_minimum_required(VERSION 3.21) + +project(Onboarding + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED) +qt6_standard_project_setup() + +qt6_add_qml_module(${PROJECT_NAME} + URI Status.Onboarding + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + qml/Status/Onboarding/OnboardingView.qml + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Onboarding/ +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml +) + +# QtCreator needs this +set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/qml;${QML_IMPORT_PATH} CACHE STRING "For QtCreator" FORCE) +list(REMOVE_DUPLICATES QML_IMPORT_PATH) diff --git a/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml b/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml new file mode 100644 index 0000000000..ada5ff2195 --- /dev/null +++ b/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml @@ -0,0 +1,30 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +Item { + id: root + + signal userLoggedIn() + + implicitWidth: mainLayout.implicitWidth + implicitHeight: mainLayout.implicitHeight + + ColumnLayout { + id: mainLayout + + anchors.fill: parent + + RowLayout {} + Label { + Layout.alignment: Qt.AlignHCenter + text: "TODO OnboardingWorkflow" + } + Button { + text: "Done" + Layout.alignment: Qt.AlignHCenter + onClicked: root.userLoggedIn() + } + RowLayout {} + } +} diff --git a/libs/StatusGoQt/CMakeLists.txt b/libs/StatusGoQt/CMakeLists.txt new file mode 100644 index 0000000000..71bef4259a --- /dev/null +++ b/libs/StatusGoQt/CMakeLists.txt @@ -0,0 +1,31 @@ +# Light helpers library expected to be used by all other libraries +# +cmake_minimum_required(VERSION 3.21) + +project(StatusGoQt + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Core REQUIRED) +qt6_standard_project_setup() + +add_library(${PROJECT_NAME} SHARED "") + +# Use by linker only +set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug) + +add_subdirectory(src) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Core + + statusgo_shared +) + +# Copy status-go lib close to the executable +# Temporary workaround; TODO: see a better alternative that doesn't depend on target order (dedicated dependencies dir?) +get_target_property(STATUSGO_LIBRARY_PATH statusgo_shared IMPORTED_LOCATION) +configure_file(${STATUSGO_LIBRARY_PATH} ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) diff --git a/libs/StatusGoQt/src/CMakeLists.txt b/libs/StatusGoQt/src/CMakeLists.txt new file mode 100644 index 0000000000..7e7b61d0b6 --- /dev/null +++ b/libs/StatusGoQt/src/CMakeLists.txt @@ -0,0 +1,14 @@ +# Internally we use includes directly +# External clients have to explicitly use the module name +add_subdirectory(StatusGo) + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/StatusGo + # TODO: Workaround to QML_ELEMENT Qt6 + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/StatusGo + + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/libs/StatusQ/CMakeLists.txt b/libs/StatusQ/CMakeLists.txt new file mode 100644 index 0000000000..c2f16e18be --- /dev/null +++ b/libs/StatusQ/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.21) + +project(StatusQ + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED) +qt6_standard_project_setup() + +qt6_add_qml_module(${PROJECT_NAME} + URI Status + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status +) + +add_subdirectory(qml/Status/Core/Theme) +add_subdirectory(tests) + +# QtCreator needs this +set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/qml;${QML_IMPORT_PATH} CACHE STRING "For QtCreator" FORCE) +list(REMOVE_DUPLICATES QML_IMPORT_PATH) diff --git a/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt b/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt new file mode 100644 index 0000000000..bb7a9c070e --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt @@ -0,0 +1,28 @@ +# Theme dependent components and assets +project(StatusQ_Core_Theme) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED) +qt6_standard_project_setup() + +set_source_files_properties(Style.qml PROPERTIES + QT_QML_SINGLETON_TYPE TRUE +) + +qt6_add_qml_module(${PROJECT_NAME} + URI Status.Core.Theme + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + StatusDarkPalette.qml + StatusDarkTheme.qml + StatusLightPalette.qml + StatusLightTheme.qml + StatusPalette.qml + StatusTheme.qml + Style.qml + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Core/Theme +) diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml new file mode 100644 index 0000000000..dd6a2a91fc --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml @@ -0,0 +1,5 @@ +import QtQuick + +StatusPalette { + +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml new file mode 100644 index 0000000000..721ae0550d --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml @@ -0,0 +1,6 @@ +import QtQuick + +StatusTheme { + readonly property string name: "dark" + readonly property StatusPalette palette: StatusDarkPalette {} +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml new file mode 100644 index 0000000000..dd6a2a91fc --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml @@ -0,0 +1,5 @@ +import QtQuick + +StatusPalette { + +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml new file mode 100644 index 0000000000..aab571d096 --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml @@ -0,0 +1,6 @@ +import QtQuick + +StatusTheme { + readonly property string name: "light" + readonly property StatusPalette palette: StatusLightPalette {} +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml new file mode 100644 index 0000000000..7ae86fd625 --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml @@ -0,0 +1,4 @@ +import QtQuick + +QtObject { +} \ No newline at end of file diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml new file mode 100644 index 0000000000..cec71f490a --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + required property string name + required property StatusPalette palette +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/Style.qml b/libs/StatusQ/qml/Status/Core/Theme/Style.qml new file mode 100644 index 0000000000..8249cf5e44 --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/Style.qml @@ -0,0 +1,27 @@ +pragma Singleton + +import QtQuick +//import QtQuick.Controls.Universal + +QtObject { + property StatusTheme theme: lightTheme + property StatusPalette palette: theme.palette + readonly property StatusTheme lightTheme: StatusLightTheme {} + readonly property StatusTheme darkTheme: StatusDarkTheme {} + + property var changeTheme: function (palette, isCurrentSystemThemeDark) { + switch (theme) { + case Universal.Light: + theme = lightTheme; + break; + case Universal.Dark: + theme = darkTheme; + break; + case Universal.System: + current = isCurrentSystemThemeDark? darkTheme : lightTheme; + break; + default: + console.warning('Unknown theme. Valid themes are "light" and "dark"') + } + } +} diff --git a/libs/StatusQ/tests/CMakeLists.txt b/libs/StatusQ/tests/CMakeLists.txt new file mode 100644 index 0000000000..eb685812c6 --- /dev/null +++ b/libs/StatusQ/tests/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.5) + +project(TestStatusQ LANGUAGES CXX) + +enable_testing() + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml QuickTest REQUIRED) +qt6_standard_project_setup() + +qt6_add_qml_module(${PROJECT_NAME} + URI StatusQ.TestHelpers + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/TestHelpers +) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# no need to copy around qml test files for shadow builds - just set the respective define +add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") + +add_test(NAME ${PROJECT_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME} -input "${CMAKE_CURRENT_SOURCE_DIR}") +add_custom_target("Run_${PROJECT_NAME}" COMMAND ${CMAKE_CTEST_COMMAND} --test-dir "${CMAKE_CURRENT_BINARY_DIR}") +add_dependencies("Run_${PROJECT_NAME}" ${PROJECT_NAME}) + +# TODO: move this to a test helpers library +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(src) + +target_link_libraries(${PROJECT_NAME} PRIVATE + Qt6::QuickTest + Qt6::Qml + Qt6::Quick +) diff --git a/libs/StatusQ/tests/main.cpp b/libs/StatusQ/tests/main.cpp new file mode 100644 index 0000000000..924f9a2603 --- /dev/null +++ b/libs/StatusQ/tests/main.cpp @@ -0,0 +1,26 @@ +#include +#include + +#include "TestHelpers/MonitorQtOutput.h" + +class TestSetup : public QObject +{ + Q_OBJECT + +public: + TestSetup() {} + +public slots: + void qmlEngineAvailable(QQmlEngine *engine) + { + // TODO: Workaround until we make StatusQ a CMake library + engine->addImportPath("../src/"); + engine->addImportPath("./qml/"); + // TODO: Alternative to not yet supported QML_ELEMENT + qmlRegisterType("StatusQ.TestHelpers", 0, 1, "MonitorQtOutput"); + } +}; + +QUICK_TEST_MAIN_WITH_SETUP(TestControls, TestSetup) + +#include "main.moc" diff --git a/libs/StatusQ/tests/qml/StatusQ/TestHelpers/TestUtils.qml b/libs/StatusQ/tests/qml/StatusQ/TestHelpers/TestUtils.qml new file mode 100644 index 0000000000..0fa796d26c --- /dev/null +++ b/libs/StatusQ/tests/qml/StatusQ/TestHelpers/TestUtils.qml @@ -0,0 +1,23 @@ +pragma Singleton + +import QtQml +import QtTest + +QtObject { + + //> Simulate key and wait for side effects + function pressKeyAndWait(test, item, key) { + test.keyClick(key) + + ensureRendered(test, item) + } + + function ensureRendered(test, item) { + test.verify(test.waitForRendering(item, 1000)) + } + + function expectRendering(test, item) { + test.verify(test.isPolishScheduled(item)) + test.verify(test.waitForRendering(item, 1000)) + } +} diff --git a/libs/StatusQ/tests/readme.md b/libs/StatusQ/tests/readme.md new file mode 100644 index 0000000000..facf2497af --- /dev/null +++ b/libs/StatusQ/tests/readme.md @@ -0,0 +1,24 @@ +# Readme + +## Developer instructions + +CMake + +```sh +cd ./tests/ +cmake -B ./build/ -S . +cmake --build ./build/ +ctest --test-dir ./build/ +``` + +QtCreator + +- Open the `./tests/CMakeLists.txt` +- Choose a QT kit to run the tests +- Set `%{sourceDir}/tests` as Working Directory for the TestStatusQ target +- In the *Test Results* panel choose Run All Tests or just run the *TestStatusQ* target + +## TODO + +- [ ] TestHelpers library +- [ ] Consolidate and integrate with https://github.com/status-im/desktop-ui-tests diff --git a/libs/StatusQ/tests/src/CMakeLists.txt b/libs/StatusQ/tests/src/CMakeLists.txt new file mode 100644 index 0000000000..3220944cf5 --- /dev/null +++ b/libs/StatusQ/tests/src/CMakeLists.txt @@ -0,0 +1,6 @@ +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(TestHelpers) \ No newline at end of file diff --git a/libs/StatusQ/tests/src/TestHelpers/CMakeLists.txt b/libs/StatusQ/tests/src/TestHelpers/CMakeLists.txt new file mode 100644 index 0000000000..2728db39a9 --- /dev/null +++ b/libs/StatusQ/tests/src/TestHelpers/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.h + ${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.cpp + + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + diff --git a/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp b/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp new file mode 100644 index 0000000000..1c6aeefb85 --- /dev/null +++ b/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp @@ -0,0 +1,68 @@ +#include "MonitorQtOutput.h" + +#include +#include + +std::weak_ptr MonitorQtOutput::m_qtMessageOutputForSharing; +std::mutex MonitorQtOutput::m_mutex; +QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr; + + +MonitorQtOutput::MonitorQtOutput() +{ + // Ensure only one instance registers a handler + // Warning: don't call QT's logger functions inside the critical section + std::unique_lock localLock(m_mutex); + auto globalMsgOut = m_qtMessageOutputForSharing.lock(); + auto prev = qInstallMessageHandler(qtMessageOutput); + if(prev != qtMessageOutput) + m_previousHandler = prev; + if(!globalMsgOut) { + m_thisMessageOutput = std::make_shared(); + m_qtMessageOutputForSharing = m_thisMessageOutput; + } + else { + m_thisMessageOutput = globalMsgOut; + m_start = m_thisMessageOutput->length(); + } +} + +MonitorQtOutput::~MonitorQtOutput() +{ + std::unique_lock localLock(m_mutex); + if(m_thisMessageOutput.use_count() == 1) { + // Last instance, deregister the handler + qInstallMessageHandler(0); + m_thisMessageOutput.reset(); + } +} + +void +MonitorQtOutput::qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + std::unique_lock localLock(m_mutex); + auto globalMsgOut = m_qtMessageOutputForSharing.lock(); + assert(globalMsgOut != nullptr); + globalMsgOut->append(msg + '\n'); + // Also reproduce the default output + m_previousHandler(type, context, msg); +} + +QString +MonitorQtOutput::qtOuput() +{ + std::unique_lock localLock(m_mutex); + assert(m_thisMessageOutput->length() >= m_start); + return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start); +} + +void +MonitorQtOutput::restartCapturing() +{ + std::unique_lock localLock(m_mutex); + // Ensure the messageHandler is installed. Foun to be reset at test initializaiton + auto prev = qInstallMessageHandler(qtMessageOutput); + if(prev != qtMessageOutput) + m_previousHandler = prev; + m_start = m_thisMessageOutput->length(); +} diff --git a/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h b/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h new file mode 100644 index 0000000000..657ed79b96 --- /dev/null +++ b/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include +#include + +/// +/// \brief Monitor output for tests and declaratively control message handler availability +/// +/// The captured buffer is global and each instance has a reference to it and a start pointer +/// from its creation or last clear call +/// The first instance installs a QT message handler @see Qt::qInstallMessageHandler then +/// All other instances share the global buffer until the last instance goes out of scope and deregisters +/// from Qt's global message handler and destroyes the buffer +/// +/// \todo Check that QML doesn't keep instance between test runs +/// +class MonitorQtOutput : public QQuickItem +{ + Q_OBJECT +public: + MonitorQtOutput(); + ~MonitorQtOutput(); + + /// Return captured output from the global buffer. That is from the instantiation or last `clear()` was called + Q_INVOKABLE QString qtOuput(); + /// Reset buffer start after the last line. qtOutput won't return anything until new output is captured + Q_INVOKABLE void restartCapturing(); + +signals: + +private: + static void qtMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); + static QtMessageHandler m_previousHandler; + + // Use it to keep track of qInstallMessageHandler call + static std::weak_ptr m_qtMessageOutputForSharing; + static std::mutex m_mutex; + std::shared_ptr m_thisMessageOutput; + int m_start = 0; +}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test-cpp/CMakeLists.txt b/test/unit/CMakeLists.txt similarity index 100% rename from test-cpp/CMakeLists.txt rename to test/unit/CMakeLists.txt diff --git a/test-cpp/testDeps.cpp b/test/unit/testDeps.cpp similarity index 100% rename from test-cpp/testDeps.cpp rename to test/unit/testDeps.cpp diff --git a/ui/imports/assets/CMakeLists.txt b/ui/imports/assets/CMakeLists.txt new file mode 100644 index 0000000000..3a28b57390 --- /dev/null +++ b/ui/imports/assets/CMakeLists.txt @@ -0,0 +1,40 @@ +# Temporary library not to duplicate resources +# TODO: refactor it when switching to C++ code into Assets resource library linked or embed with the app +# +cmake_minimum_required(VERSION 3.21) + +project(UiAssets + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Qml REQUIRED) +qt6_standard_project_setup() + +qt6_add_qml_module(${PROJECT_NAME} + URI Status.UiAssets + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + RESOURCES + gif/status_splash_dark.gif + gif/status_splash_light.gif + + icons/status-logo-icon.svg + icons/status-logo-dark.svg + + png/traffic_lights/close.png + png/traffic_lights/close_pressed.png + png/traffic_lights/maximize.png + png/traffic_lights/maximize_pressed.png + png/traffic_lights/minimise.png + png/traffic_lights/minimise_pressed.png + png/status-logo.png + + RESOURCE_PREFIX "" +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Qml +) diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt new file mode 100644 index 0000000000..3614da9037 --- /dev/null +++ b/vendor/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/status-go) \ No newline at end of file diff --git a/vendor/conan-configs/apple-arm64.ini b/vendor/conan-configs/apple-arm64.ini new file mode 100644 index 0000000000..fcbdfff051 --- /dev/null +++ b/vendor/conan-configs/apple-arm64.ini @@ -0,0 +1,11 @@ +[settings] +compiler=apple-clang +compiler.version=13.1 +compiler.libcxx=libc++ +arch=armv8 +os=Macos +build_type=Release + +[env] +CC=/usr/bin/clang +CXX=/usr/bin/clang++ \ No newline at end of file diff --git a/vendor/conan-configs/apple-x86_64.ini b/vendor/conan-configs/apple-x86_64.ini new file mode 100644 index 0000000000..373c6ee1d4 --- /dev/null +++ b/vendor/conan-configs/apple-x86_64.ini @@ -0,0 +1,11 @@ +[settings] +compiler=apple-clang +compiler.version=13.1 +compiler.libcxx=libc++ +arch=x86_64 +os=Macos +build_type=Release + +[env] +CC=/usr/bin/clang +CXX=/usr/bin/clang++ \ No newline at end of file diff --git a/vendor/status-go b/vendor/status-go index 05073a9640..23d745fe0a 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 05073a96407ca40313663f7423195ce767c6d9c5 +Subproject commit 23d745fe0a61501b847af9c54479d5fa763a51d0