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
This commit is contained in:
parent
49b592daa3
commit
1e8c851283
162
CMakeLists.txt
162
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
|
project(status-desktop
|
||||||
VERSION 0.1.0
|
VERSION ${STATUS_VERSION}
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
|
|
||||||
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
set(PROJECT_ORGANIZATION_DOMAIN "status.im")
|
||||||
message(
|
set(PROJECT_ORGANIZATION_NAME "Status")
|
||||||
FATAL_ERROR
|
set(PROJECT_APPLICATION_NAME "Status Desktop")
|
||||||
"In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there."
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
|
||||||
set(CMAKE_AUTORCC ON)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
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 $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>: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
|
|
||||||
$<$<CONFIG:Debug>:--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
|
|
||||||
)
|
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
|
enable_testing()
|
||||||
add_subdirectory(test-cpp)
|
|
||||||
|
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64" AND APPLE)
|
||||||
|
set(STATUSGO_FORCE_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR})
|
||||||
endif()
|
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)
|
||||||
|
|
66
README.md
66
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)
|
![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)
|
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
|
|
||||||
```
|
|
||||||
|
|
|
@ -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/.../<file name>
|
||||||
|
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
|
||||||
|
$<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>: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)
|
||||||
|
|
|
@ -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=<Platform specific conan 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=<Qt 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=<Qt prefix path> -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build/conan/conan_toolchain.cmake
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
|
@ -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
|
||||||
|
#)
|
|
@ -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
|
||||||
|
#)
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 ""
|
||||||
|
#)
|
|
@ -0,0 +1,5 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>qtquickcontrols2.conf</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1,2 @@
|
||||||
|
[Controls]
|
||||||
|
Style=Universal
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "ApplicationController.h"
|
||||||
|
|
||||||
|
ApplicationController::ApplicationController(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QtQml/qqmlregistration.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Responsible for providing general information and utility components
|
||||||
|
*/
|
||||||
|
class ApplicationController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
public:
|
||||||
|
explicit ApplicationController(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
};
|
|
@ -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
|
||||||
|
)
|
|
@ -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)
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QTranslator>
|
||||||
|
|
||||||
|
#include <Helpers/helpers.h>
|
||||||
|
#include <Helpers/logs.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
|
@ -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()
|
|
@ -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()
|
|
@ -0,0 +1,7 @@
|
||||||
|
function(configure_app_os_specific)
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
|
WIN32_EXECUTABLE TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction()
|
|
@ -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)
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
add_subdirectory(Helpers)
|
||||||
|
# TODO: enable after adding content
|
||||||
|
#add_subdirectory(Core)
|
||||||
|
add_subdirectory(StatusQ)
|
||||||
|
add_subdirectory(Onboarding)
|
||||||
|
add_subdirectory(Assets)
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,4 @@
|
||||||
|
qt6_add_resources(${PROJECT_NAME} imageresources
|
||||||
|
PREFIX "/images"
|
||||||
|
FILES logo.png splashscreen.png
|
||||||
|
)
|
|
@ -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}
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
target_sources(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/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
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Helpers
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(Helpers)
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include <Helpers/BuildConfiguration.h>
|
||||||
|
|
||||||
|
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
|
|
@ -1,9 +1,23 @@
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <Helpers/BuildConfiguration.h>
|
||||||
|
|
||||||
|
namespace Status::Helpers {
|
||||||
|
|
||||||
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
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();
|
QByteArray localMsg = msg.toLocal8Bit();
|
||||||
const char* file = context.file ? context.file : "";
|
const char* file = context.file ? context.file : "";
|
||||||
QByteArray function =
|
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 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;
|
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
|
|
@ -4,4 +4,9 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
namespace Status::Helpers {
|
||||||
|
|
||||||
|
/// Formats with colloring output if not a development build
|
||||||
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
void logFormatter(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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 {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
|
@ -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}
|
||||||
|
)
|
|
@ -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)
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
StatusPalette {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
StatusTheme {
|
||||||
|
readonly property string name: "dark"
|
||||||
|
readonly property StatusPalette palette: StatusDarkPalette {}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
StatusPalette {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
StatusTheme {
|
||||||
|
readonly property string name: "light"
|
||||||
|
readonly property StatusPalette palette: StatusLightPalette {}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
required property string name
|
||||||
|
required property StatusPalette palette
|
||||||
|
}
|
|
@ -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"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include <QtQuickTest/quicktest.h>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#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<MonitorQtOutput>("StatusQ.TestHelpers", 0, 1, "MonitorQtOutput");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QUICK_TEST_MAIN_WITH_SETUP(TestControls, TestSetup)
|
||||||
|
|
||||||
|
#include "main.moc"
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(TestHelpers)
|
|
@ -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
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include "MonitorQtOutput.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
std::weak_ptr<QString> 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<std::mutex> 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<QString>();
|
||||||
|
m_qtMessageOutputForSharing = m_thisMessageOutput;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_thisMessageOutput = globalMsgOut;
|
||||||
|
m_start = m_thisMessageOutput->length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MonitorQtOutput::~MonitorQtOutput()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> localLock(m_mutex);
|
||||||
|
assert(m_thisMessageOutput->length() >= m_start);
|
||||||
|
return m_thisMessageOutput->right(m_thisMessageOutput->length() - m_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MonitorQtOutput::restartCapturing()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> 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();
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QQuickItem>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \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<QString> m_qtMessageOutputForSharing;
|
||||||
|
static std::mutex m_mutex;
|
||||||
|
std::shared_ptr<QString> m_thisMessageOutput;
|
||||||
|
int m_start = 0;
|
||||||
|
};
|
|
@ -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
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/status-go)
|
|
@ -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++
|
|
@ -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++
|
|
@ -1 +1 @@
|
||||||
Subproject commit 05073a96407ca40313663f7423195ce767c6d9c5
|
Subproject commit 23d745fe0a61501b847af9c54479d5fa763a51d0
|
Loading…
Reference in New Issue