diff --git a/CMakeLists.txt b/CMakeLists.txt index 0359bcfae4..2fb1531b13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,3 +32,4 @@ 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) +add_subdirectory(ui/fonts) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 2a54b1f16e..1acc38b152 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -12,17 +12,26 @@ qt6_add_executable(${PROJECT_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/Decorators/SplashScreen.qml qml/Status/Application/MainView/MainView.qml + qml/Status/Application/MainView/StatusApplicationSections.qml + + qml/Status/Application/MainView/StatusApplicationSections/Wallet/WalletNavBarSection.qml + + qml/Status/Application/Settings/ApplicationSettings.qml qml/Status/Application/System/StatusTrayIcon.qml - qml/Status/Application/Decorators/SplashScreen.qml + qml/Status/Application/Workflows/CloseApplicationHandler.qml + + qml/Status/Application/StatusContentView.qml + qml/Status/Application/MainShortcuts.qml + qml/Status/Application/StatusWindow.qml + OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Application ) @@ -37,6 +46,7 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_BINARY_DIR=${CMAKE_BINA target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_SOURCE_DIR=${CMAKE_SOURCE_DIR}) add_subdirectory(qml) +add_subdirectory(qml/Status/Application/Navigation) add_subdirectory(src) add_subdirectory(res) @@ -53,11 +63,14 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Quick + StatusQ_Application_Navigation + # TODO: Use Status:: namespace #Core Helpers Onboarding Assets + StatusQ ) # QtCreator needs this diff --git a/app/qml/Status/Application/MainView/MainView.qml b/app/qml/Status/Application/MainView/MainView.qml index f4b2cde6e9..566ad412ab 100644 --- a/app/qml/Status/Application/MainView/MainView.qml +++ b/app/qml/Status/Application/MainView/MainView.qml @@ -2,11 +2,20 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls +import Status.Application + +import Status.Containers +import Status.Controls + +import Status.Application.Navigation + /// Responsible for setup of user workflows after onboarding Item { id: root - /// Emited when everything is loaded and UX ready + required property ApplicationController appController + + /// Emitted when everything is loaded and UX ready signal ready() Component.onCompleted: root.ready() @@ -14,22 +23,40 @@ Item { implicitWidth: mainLayout.implicitWidth implicitHeight: mainLayout.implicitHeight - ColumnLayout { + RowLayout { id: mainLayout anchors.fill: parent - RowLayout {} - Label { - Layout.alignment: Qt.AlignHCenter - text: "TODO MainView" - } - Button { - text: "Quit" - Layout.alignment: Qt.AlignHCenter - onClicked: Qt.quit() + StatusNavigationBar { + id: navBar + + Layout.fillHeight: true + + sections: appSections.sectionsList } - RowLayout {} + ColumnLayout { + // Not visible all the time + StatusBanner { + Layout.fillWidth: true + + //statusText: // TODO: appController.bannerController.text + //type: // TODO: appController.bannerController.type + visible: false // TODO: appController.bannerController.visible + } + Loader { + id: mainLoader + + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } + + StatusApplicationSections { + id: appSections + // Chat ... + // Wallet ... } } diff --git a/app/qml/Status/Application/MainView/StatusApplicationSections.qml b/app/qml/Status/Application/MainView/StatusApplicationSections.qml new file mode 100644 index 0000000000..1f59c38fa2 --- /dev/null +++ b/app/qml/Status/Application/MainView/StatusApplicationSections.qml @@ -0,0 +1,25 @@ +import QtQml + +import Status.Controls.Navigation + +QtObject { + readonly property var sectionsList: [wallet, settings] + readonly property ApplicationSection wallet: ApplicationSection { + navButton: WalletButtonComponent + content: WalletContentComponent + + component WalletButtonComponent: NavigationBarButton { + } + component WalletContentComponent: ApplicationContentView { + } + } + readonly property ApplicationSection settings: ApplicationSection { + navButton: SettingsButtonComponent + content: SettingsContentComponent + + component SettingsButtonComponent: NavigationBarButton { + } + component SettingsContentComponent: ApplicationContentView { + } + } +} diff --git a/app/qml/Status/Application/MainView/StatusApplicationSections/Wallet/WalletNavBarSection.qml b/app/qml/Status/Application/MainView/StatusApplicationSections/Wallet/WalletNavBarSection.qml new file mode 100644 index 0000000000..19788aa828 --- /dev/null +++ b/app/qml/Status/Application/MainView/StatusApplicationSections/Wallet/WalletNavBarSection.qml @@ -0,0 +1,20 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import Status.Application.Navigation +import Status.Controls.Navigation + +NavigationBarSection { + id: root + + implicitHeight: walletButton.implicitHeight + + StatusNavigationButton { + id: walletButton + + anchors.fill: parent + + // TODO: icon, tooltip ... + } +} diff --git a/app/qml/Status/Application/Navigation/CMakeLists.txt b/app/qml/Status/Application/Navigation/CMakeLists.txt new file mode 100644 index 0000000000..3070cf775c --- /dev/null +++ b/app/qml/Status/Application/Navigation/CMakeLists.txt @@ -0,0 +1,25 @@ +# Controls specialized on user workflows +project(StatusQ_Application_Navigation) + +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.Application.Navigation + VERSION 1.0 + + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + StatusNavigationBar.qml + StatusNavigationButton.qml + + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Application/Navigation +) diff --git a/app/qml/Status/Application/Navigation/StatusNavigationBar.qml b/app/qml/Status/Application/Navigation/StatusNavigationBar.qml new file mode 100644 index 0000000000..b734613961 --- /dev/null +++ b/app/qml/Status/Application/Navigation/StatusNavigationBar.qml @@ -0,0 +1,29 @@ +import QtQml +import QtQuick +import QtQuick.Layouts + +import Status.Controls.Navigation + +NavigationBar { + implicitHeight: mainLayout.implicitHeight + + required property var sections + + ColumnLayout { + id: mainLayout + + MacTrafficLights { + Layout.margins: 13 + } + + Repeater { + model: sections + + Loader { + Layout.fillWidth: true + + sourceComponent: modelData.navButton + } + } + } +} diff --git a/app/qml/Status/Application/Navigation/StatusNavigationButton.qml b/app/qml/Status/Application/Navigation/StatusNavigationButton.qml new file mode 100644 index 0000000000..9a8aef20bf --- /dev/null +++ b/app/qml/Status/Application/Navigation/StatusNavigationButton.qml @@ -0,0 +1,6 @@ +import QtQml + +import Status.Controls.Navigation + +NavigationBarButton { +} diff --git a/app/qml/Status/Application/Settings/ApplicationSettings.qml b/app/qml/Status/Application/Settings/ApplicationSettings.qml new file mode 100644 index 0000000000..e5cac15c7e --- /dev/null +++ b/app/qml/Status/Application/Settings/ApplicationSettings.qml @@ -0,0 +1,8 @@ +import QtQml +import QtQuick + +import Qt.labs.settings + +Settings { + property bool quitOnClose: false +} diff --git a/app/qml/Status/Application/StatusContentView.qml b/app/qml/Status/Application/StatusContentView.qml index a596d8c8d0..f6ae1fd653 100644 --- a/app/qml/Status/Application/StatusContentView.qml +++ b/app/qml/Status/Application/StatusContentView.qml @@ -5,10 +5,16 @@ import QtQuick.Controls import Status.Application import Status.Onboarding -/// Has entry responsibility for the main workflows +import Status.Controls.Navigation + +/*! Has entry responsibility for the main workflows + */ Item { id: root + required property ApplicationState appState + required property ApplicationController appController + implicitWidth: d.isViewLoaded ? d.loadedView.implicitWidth : 800 implicitHeight: d.isViewLoaded ? d.loadedView.implicitHeight : 600 @@ -35,6 +41,7 @@ Item { MainView { onReady: splashScreenPopup.close() + appController: root.appController } } diff --git a/app/qml/Status/Application/StatusWindow.qml b/app/qml/Status/Application/StatusWindow.qml index 45149ee589..d233b19c5d 100644 --- a/app/qml/Status/Application/StatusWindow.qml +++ b/app/qml/Status/Application/StatusWindow.qml @@ -5,7 +5,12 @@ import Qt.labs.settings import Status.Application -/** Administrative scope +import Status.Controls.Navigation +import Status.Core.Theme + +import "Workflows" + +/*! Administrative scope */ Window { id: root @@ -14,35 +19,73 @@ Window { minimumHeight: 600 Component.onCompleted: { - width: mainLayout.implicitWidth - height: mainLayout.implicitHeight + width: contentView.implicitWidth + height: contentView.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 - } - } + color: "transparent" ApplicationController { id: appController } - Settings { + Rectangle { + id: windowBackground + anchors.fill: parent + radius: Style.geometry.appCornersRadius + color: Theme.palette.appBackgroundColor + + StatusContentView { + id: contentView + + anchors.fill: parent + + appState: appState + appController: appController + } + } + + // Title gestures handler + MouseArea { + id: dragArea + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + height: Style.geometry.titleBarHeight + // lower than contentView to not steal events from user controls + z: contentView.z - 1 + + onDoubleClicked: root.visibility === Window.Maximized ? Window.window.showNormal() : Window.window.showMaximized() + + property point prevMousePoint + onPressed: (mouse) => prevMousePoint = Qt.point(mouse.x, mouse.y) + onMouseXChanged: root.x += mouseX - prevMousePoint.x + onMouseYChanged: root.y += mouseY - prevMousePoint.y + } + + ApplicationState { + id: appState + } + + onClosing: function(close) { + close.accepted = closeHandler.canApplicationClose() + } + + CloseApplicationHandler { + id: closeHandler + + quitOnClose: appSettings.quitOnClose + + onHideApplication: root.visible = false + } + + ApplicationSettings { + id: appSettings + property alias x: root.x property alias y: root.y property alias width: root.width diff --git a/app/qml/Status/Application/Workflows/CloseApplicationHandler.qml b/app/qml/Status/Application/Workflows/CloseApplicationHandler.qml new file mode 100644 index 0000000000..ac63f9b572 --- /dev/null +++ b/app/qml/Status/Application/Workflows/CloseApplicationHandler.qml @@ -0,0 +1,18 @@ +import QtQml + +QtObject { + id: root + + required property bool quitOnClose + + signal hideApplication() + + function canApplicationClose() { + if(root.quitOnClose) { + root.hideApplication() + return false + } + + return true + } +} diff --git a/libs/Assets/CMakeLists.txt b/libs/Assets/CMakeLists.txt index 440196fac3..e8baff919d 100644 --- a/libs/Assets/CMakeLists.txt +++ b/libs/Assets/CMakeLists.txt @@ -19,9 +19,11 @@ set_source_files_properties(qml/Status/Assets/Resources.qml PROPERTIES 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/ ) @@ -31,6 +33,7 @@ target_link_libraries(${PROJECT_NAME} Qt6::Qml # TODO: refactor when moved to C++ code + FontAssets UiAssets ) diff --git a/libs/Assets/qml/Status/Assets/Resources.qml b/libs/Assets/qml/Status/Assets/Resources.qml index 547b11d8cf..9a3a6dd6ff 100644 --- a/libs/Assets/qml/Status/Assets/Resources.qml +++ b/libs/Assets/qml/Status/Assets/Resources.qml @@ -14,4 +14,7 @@ QtObject { function gif(name) { return assetPath + "/gif/" + name + ".gif"; } + function png(name) { + return assetPath + "/png/" + name + ".png"; + } } diff --git a/libs/Core/CMakeLists.txt b/libs/Core/CMakeLists.txt index 31952c08b9..3701871213 100644 --- a/libs/Core/CMakeLists.txt +++ b/libs/Core/CMakeLists.txt @@ -14,9 +14,11 @@ 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 diff --git a/libs/Onboarding/CMakeLists.txt b/libs/Onboarding/CMakeLists.txt index 9f1a67aef2..c8c459c660 100644 --- a/libs/Onboarding/CMakeLists.txt +++ b/libs/Onboarding/CMakeLists.txt @@ -14,9 +14,11 @@ 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/ ) diff --git a/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml b/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml index ada5ff2195..b17287fb25 100644 --- a/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml +++ b/libs/Onboarding/qml/Status/Onboarding/OnboardingView.qml @@ -2,6 +2,9 @@ import QtQuick import QtQuick.Layouts import QtQuick.Controls +import Status.Containers +import Status.Controls.Navigation + Item { id: root @@ -15,7 +18,11 @@ Item { anchors.fill: parent - RowLayout {} + MacTrafficLights { + Layout.margins: 13 + } + + LayoutSpacer {} Label { Layout.alignment: Qt.AlignHCenter text: "TODO OnboardingWorkflow" @@ -25,6 +32,6 @@ Item { Layout.alignment: Qt.AlignHCenter onClicked: root.userLoggedIn() } - RowLayout {} + LayoutSpacer {} } } diff --git a/libs/StatusQ/CMakeLists.txt b/libs/StatusQ/CMakeLists.txt index 82d6e70fb7..314ed02cdb 100644 --- a/libs/StatusQ/CMakeLists.txt +++ b/libs/StatusQ/CMakeLists.txt @@ -12,16 +12,31 @@ 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(qml/Status/Containers) +add_subdirectory(qml/Status/Controls) +add_subdirectory(qml/Status/Core) add_subdirectory(tests) +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml + + Assets + StatusQ_Containers + StatusQ_Controls + StatusQ_Core +) + # 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/Containers/CMakeLists.txt b/libs/StatusQ/qml/Status/Containers/CMakeLists.txt new file mode 100644 index 0000000000..b03f88ed77 --- /dev/null +++ b/libs/StatusQ/qml/Status/Containers/CMakeLists.txt @@ -0,0 +1,26 @@ +# Custom container and layouts +project(StatusQ_Containers) + +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.Containers + VERSION 1.0 + + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + LayoutSpacer.qml + + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Containers +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml +) diff --git a/libs/StatusQ/qml/Status/Containers/LayoutSpacer.qml b/libs/StatusQ/qml/Status/Containers/LayoutSpacer.qml new file mode 100644 index 0000000000..136725f86c --- /dev/null +++ b/libs/StatusQ/qml/Status/Containers/LayoutSpacer.qml @@ -0,0 +1,4 @@ +import QtQuick.Layouts + +GridLayout { +} diff --git a/libs/StatusQ/qml/Status/Controls/CMakeLists.txt b/libs/StatusQ/qml/Status/Controls/CMakeLists.txt new file mode 100644 index 0000000000..c58b91bdf5 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/CMakeLists.txt @@ -0,0 +1,30 @@ +# Custom controls +project(StatusQ_Controls) + +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.Controls + VERSION 1.0 + + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + StatusBanner.qml + + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Controls +) + +add_subdirectory(Navigation) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml + + StatusQ_Controls_Navigation +) diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationContentView.qml b/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationContentView.qml new file mode 100644 index 0000000000..f829e25d86 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationContentView.qml @@ -0,0 +1,7 @@ +import QtQuick + +/*! + Template for application section content + */ +Item { +} diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationSection.qml b/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationSection.qml new file mode 100644 index 0000000000..37c5dc9dd3 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationSection.qml @@ -0,0 +1,12 @@ +import QtQml + +/*! + An application section with button and content view + */ +QtObject { + required property NavigationBarButtonComponent navButton + required property ApplicationContentView content + + component NavigationBarButtonComponent: NavigationBarButton {} + component ApplicationContentViewComponent: ApplicationContentView {} +} diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationState.qml b/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationState.qml new file mode 100644 index 0000000000..6e345f6b24 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/ApplicationState.qml @@ -0,0 +1,7 @@ +import QtQml + +/*! + Keep general application related stated used by custom controls + */ +QtObject { +} diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/CMakeLists.txt b/libs/StatusQ/qml/Status/Controls/Navigation/CMakeLists.txt new file mode 100644 index 0000000000..dd5ed3c792 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/CMakeLists.txt @@ -0,0 +1,29 @@ +# Controls specialized on user workflows +project(StatusQ_Controls_Navigation) + +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.Controls.Navigation + VERSION 1.0 + + # TODO: temporary until we make qt_target_qml_sources work + QML_FILES + ApplicationContentView.qml + ApplicationSection.qml + ApplicationState.qml + MacTrafficLights.qml + NavigationBar.qml + NavigationBarButton.qml + + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Controls/Navigation +) diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/MacTrafficLights.qml b/libs/StatusQ/qml/Status/Controls/Navigation/MacTrafficLights.qml new file mode 100644 index 0000000000..f85377479b --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/MacTrafficLights.qml @@ -0,0 +1,125 @@ +import QtQuick +import QtQuick.Controls + +import Status.Core.Theme +import Status.Assets + +Item { + id: root + + property color inactiveColor: Style.isLightTheme ? "#10000000" : "#10FFFFFF" + property color inactiveBorderColor: inactiveColor + property bool showActive: true + + width: layout.implicitWidth + height: layout.implicitHeight + + Row { + id: layout + spacing: 8 + anchors.top: parent.top + anchors.left: parent.left + + TrafficLightButton { + colors: ButtonColors{ + pressed: "#B24F47" + active: Qt.lighter("#E9685C", 1.07) + inactive: root.inactiveColor + } + borderColors: ButtonColors { + pressed: "#943229" + active: "#D14C40" + inactive: root.inactiveBorderColor + } + imagePrefix: "close" + + onClicked: Window.window.close() + } + TrafficLightButton { + colors: ButtonColors{ + pressed: "#878E3B" + active: Qt.lighter("#EDB84C", 1.07) + inactive: root.inactiveColor + } + borderColors: ButtonColors { + pressed: "#986E29" + active: "#D79F3D" + inactive: root.inactiveBorderColor + } + imagePrefix: "minimise" + imageScale: 0.64 + imageVCenterOffset: 0.5 + + onClicked: Window.window.showMinimized() + } + TrafficLightButton { + colors: ButtonColors{ + pressed: "#48943f" + active: Qt.lighter("#62C454", 1.06) + inactive: root.inactiveColor + } + borderColors: ButtonColors { + pressed: "#357225" + active: "#53A73E" + inactive: root.inactiveBorderColor + } + imagePrefix: "maximize" + + onClicked: Window.visibility === Window.FullScreen ? Window.window.showNormal() : Window.window.showFullScreen() + } + } + + + component ButtonColors: QtObject { + required property color pressed + required property color active + required property color inactive + } + + component TrafficLightButton: AbstractButton { + id: button + + required property ButtonColors colors + required property ButtonColors borderColors + required property string imagePrefix + property real imageScale: 0.52 + property real imageVCenterOffset: 0 + + implicitWidth: 12 + implicitHeight: 12 + hoverEnabled: true + padding: 0 + + contentItem: Image { + anchors.centerIn: parent + visible: allMouseArea.containsMouse + source: Resources.png(`traffic_lights/${imagePrefix}${button.pressed ? "_pressed" : ""}`) + anchors.verticalCenterOffset: button.imageVCenterOffset + scale: button.imageScale + fillMode: Image.PreserveAspectFit + antialiasing: true + } + + background: Rectangle { + radius: width / 2 + opacity: enabled ? 1 : 0.3 + + color: button.down ? colors.pressed + : Window.active ? colors.active + : colors.inactive + border.color: button.down ? borderColors.pressed + : Window.active ? borderColors.active + : borderColors.inactive + border.width: Style.isLightTheme ? 0.5 : 0 + } + + z: allMouseArea.z + 1 + } + + MouseArea { + id: allMouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } +} diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBar.qml b/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBar.qml new file mode 100644 index 0000000000..4ce0c94843 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBar.qml @@ -0,0 +1,11 @@ +import QtQuick +import QtQuick.Layouts + +/*! + Template for side NavigationBar + + The width is given, the rest of the controls have to adapt to the width + */ +Item { + implicitWidth: 78 +} diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBarButton.qml b/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBarButton.qml new file mode 100644 index 0000000000..371a250dfd --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBarButton.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +/*! + Template for a NavigationBar square button + */ +Item { + height: width +} diff --git a/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBarSection.qml b/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBarSection.qml new file mode 100644 index 0000000000..0827159594 --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/Navigation/NavigationBarSection.qml @@ -0,0 +1,7 @@ +import QtQuick + +/*! + Template for a Navigation Bar section + */ +Item { +} diff --git a/libs/StatusQ/qml/Status/Controls/StatusBanner.qml b/libs/StatusQ/qml/Status/Controls/StatusBanner.qml new file mode 100644 index 0000000000..6c2d01f9dc --- /dev/null +++ b/libs/StatusQ/qml/Status/Controls/StatusBanner.qml @@ -0,0 +1,138 @@ +import QtQuick + +import Status.Core +import Status.Core.Theme + +/*! + \qmltype StatusBanner + \inherits Column + \inqmlmodule StatusQ.Controls + \since StatusQ.Controls 0.1 + \brief It displays a banner with a custom text, size and type. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-column.html}{Column}. + + The \c StatusBanner displays a banner with a custom text, size and type (Info, Danger, Success or Warning). + + Example of how the control looks like: + \image status_banner.png + + Example of how to use it: + + \qml + StatusBanner { + width: parent.width + visible: popup.userIsBlocked + type: StatusBanner.Type.Danger + statusText: qsTr("Blocked") + } + \endqml + + For a list of components available see StatusQ. +*/ +Column { + id: statusBanner + + /*! + \qmlproperty string StatusBanner::statusText + This property holds the text the banner will display. + */ + property string statusText + /*! + \qmlproperty string StatusBanner::type + This property holds type of banner. Possible values are: + \qml + enum Type { + Info, // 0 + Danger, // 1 + Success, // 2 + Warning // 3 + } + \endqml + */ + property int type: StatusBanner.Type.Info + /*! + \qmlproperty string StatusBanner::textPixels + This property holds the pixels size of the text inside the banner. + */ + property int textPixels: 15 + /*! + \qmlproperty string StatusBanner::statusBannerHeight + This property holds the height of the banner rectangle. + */ + property int statusBannerHeight: 38 + + // "private" properties + QtObject { + id: d + property color backgroundColor + property color bordersColor + property color fontColor + } + + // TODO: move it to C++ + enum Type { + Info, // 0 + Danger, // 1 + Success, // 2 + Warning // 3 + } + + // Component definition + Rectangle { + id: topDiv + color: d.bordersColor + height: 1 + width: parent.width + } + + Rectangle { + id: box + width: parent.width + height: statusBanner.statusBannerHeight + color: d.backgroundColor + + StatusBaseText { + id: statusTxt + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pixelSize: statusBanner.textPixels + text: statusBanner.statusText + color: d.fontColor + } + } + + Rectangle { + id: bottomDiv + color: d.bordersColor + height: 1 + width: parent.width + } + + // Behavior + states: [ + State { + when: statusBanner.type === StatusBanner.Type.Info + PropertyChanges { target: d; backgroundColor: Theme.palette.primaryColor3} + PropertyChanges { target: d; bordersColor: Theme.palette.primaryColor2} + PropertyChanges { target: d; fontColor: Theme.palette.primaryColor1} + }, + State { + when: statusBanner.type === StatusBanner.Type.Danger + PropertyChanges { target: d; backgroundColor: Theme.palette.dangerColor3} + PropertyChanges { target: d; bordersColor: Theme.palette.dangerColor2} + PropertyChanges { target: d; fontColor: Theme.palette.dangerColor1} + }, + State { + when: statusBanner.type === StatusBanner.Type.Success + PropertyChanges { target: d; backgroundColor: Theme.palette.successColor2} + PropertyChanges { target: d; bordersColor: Theme.palette.successColor2} + PropertyChanges { target: d; fontColor: Theme.palette.successColor1} + }, + State { + when: statusBanner.type === StatusBanner.Type.Warning + PropertyChanges { target: d; backgroundColor: Theme.palette.pinColor3} + PropertyChanges { target: d; bordersColor: Theme.palette.pinColor2} + PropertyChanges { target: d; fontColor: Theme.palette.pinColor1} + } + ] +} diff --git a/libs/StatusQ/qml/Status/Core/CMakeLists.txt b/libs/StatusQ/qml/Status/Core/CMakeLists.txt new file mode 100644 index 0000000000..f0dbd18282 --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/CMakeLists.txt @@ -0,0 +1,30 @@ +# QML generic elements used by the other components +project(StatusQ_Core) + +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 + StatusBaseText.qml + + # Required to suppress "qmllint may not work" warning + OUTPUT_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Core +) + +add_subdirectory(Theme) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Quick + Qt6::Qml + + StatusQ_Core_Theme +) diff --git a/libs/StatusQ/qml/Status/Core/StatusBaseText.qml b/libs/StatusQ/qml/Status/Core/StatusBaseText.qml new file mode 100644 index 0000000000..bc128ebfac --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/StatusBaseText.qml @@ -0,0 +1,31 @@ +import QtQuick + +import Status.Core.Theme + +/*! + \qmltype StatusBaseText + \inherits Text + \inqmlmodule StatusQ.Core + \since StatusQ.Core + \brief Displays multiple lines of text. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-text.html}{Text}. + + The \c StatusBaseText item displays text. + For example: + + \qml + StatusBaseText { + width: 240 + text: qsTr("Hello World!") + font.pixelSize: 24 + color: Theme.pallete.directColor1 + } + \endqml + + \image status_base_text.png + + For a list of components available see StatusQ. +*/ + +Text { + font.family: Theme.baseFont.name +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt b/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt index bb7a9c070e..91fddd4d54 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt +++ b/libs/StatusQ/qml/Status/Core/Theme/CMakeLists.txt @@ -6,22 +6,34 @@ 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 +set_source_files_properties( + StatusColors.qml + Style.qml + Theme.qml + Utils.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 + StatusColors.qml StatusDarkPalette.qml StatusDarkTheme.qml + StatusLayouting.qml StatusLightPalette.qml StatusLightTheme.qml StatusPalette.qml StatusTheme.qml Style.qml + Theme.qml + Utils.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/StatusColors.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusColors.qml new file mode 100644 index 0000000000..664db44fbf --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusColors.qml @@ -0,0 +1,68 @@ +pragma Singleton + +import QtQml +import QtQuick + +/*! + Define the base color values + */ +QtObject { + readonly property color black: '#000000' + readonly property color white: '#FFFFFF' + + readonly property color blue: '#4360DF' + readonly property color blue2: '#2946C4' + readonly property color blue3: '#88B0FF' + readonly property color blue4: '#869EFF' + readonly property color blue5: '#AAC6FF' + readonly property color blue6: '#ECEFFC' + + readonly property color brown: '#8B3131' + readonly property color brown2: '#9B832F' + readonly property color brown3: '#AD4343' + + readonly property color cyan: '#51D0F0' + + readonly property color graphite: '#212121' + readonly property color graphite2: '#252525' + readonly property color graphite3: '#2C2C2C' + readonly property color graphite4: '#373737' + readonly property color graphite5: '#909090' + + readonly property color green: '#4EBC60' + readonly property color green2: '#7CDA00' + readonly property color green3: '#60C370' + readonly property color green4: '#93DB33' + readonly property color green5: '#9EA85D' + readonly property color green6: '#AFB551' + + readonly property color grey: '#F0F2F5' + readonly property color grey2: '#F6F8FA' + readonly property color grey3: '#E9EDF1' + readonly property color grey4: '#EEF2F5' + readonly property color grey5: '#939BA1' + + readonly property color moss: '#26A69A' + readonly property color moss2: '#10A88E' + + readonly property color orange: '#FE8F59' + readonly property color orange2: '#FF9F0F' + readonly property color orange3: '#FFA67B' + readonly property color orange4: '#FE8F59' + + readonly property color purple: '#887AF9' + + readonly property color red: '#FF2D55' + readonly property color red2: '#FA6565' + readonly property color red3: '#FF5C7B' + + readonly property color turquoise: '#0DA4C9' + readonly property color turquoise2: '#07BCE9' + readonly property color turquoise3: '#7BE5FF' + readonly property color turquoise4: '#0DA4C9' + + readonly property color violet: '#D37EF4' + + readonly property color yellow: '#FFCA0F' + readonly property color yellow2: '#EAD27B' +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml index dd6a2a91fc..e46f437e93 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkPalette.qml @@ -1,5 +1,23 @@ import QtQuick StatusPalette { + baseColor3: StatusColors.graphite3 + appBackgroundColor: baseColor3 + + dangerColor1: StatusColors.red3 + dangerColor2: Utils.addAlphaTo(StatusColors.red3, 0.3) + dangerColor3: Utils.addAlphaTo(StatusColors.red3, 0.2) + + successColor1: StatusColors.green3 + successColor2: Utils.addAlphaTo(StatusColors.green3, 0.2) + + mentionColor1: StatusColors.turquoise3 + mentionColor2: Utils.addAlphaTo(StatusColors.turquoise4, 0.3) + mentionColor3: Utils.addAlphaTo(StatusColors.turquoise4, 0.2) + mentionColor4: Utils.addAlphaTo(StatusColors.turquoise4, 0.1) + + pinColor1: StatusColors.orange3 + pinColor2: Utils.addAlphaTo(StatusColors.orange4, 0.2) + pinColor3: Utils.addAlphaTo(StatusColors.orange4, 0.1) } diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml index 721ae0550d..15cb72760d 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusDarkTheme.qml @@ -1,6 +1,6 @@ import QtQuick StatusTheme { - readonly property string name: "dark" - readonly property StatusPalette palette: StatusDarkPalette {} + name: "dark" + palette: StatusDarkPalette {} } diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusLayouting.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusLayouting.qml new file mode 100644 index 0000000000..d520fa988f --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusLayouting.qml @@ -0,0 +1,8 @@ +import QtQml + +QtObject { + readonly property int titleBarHeight: 25 + readonly property real appCornersRadius: 5 + + +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml index dd6a2a91fc..1f74b988b4 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusLightPalette.qml @@ -1,5 +1,27 @@ import QtQuick StatusPalette { + baseColor3: StatusColors.grey3 + appBackgroundColor: "white" + + primaryColor1: StatusColors.blue + primaryColor2: Utils.addAlphaTo(StatusColors.blue, 0.2) + primaryColor3: Utils.addAlphaTo(StatusColors.blue, 0.1) + + dangerColor1: StatusColors.red + dangerColor2: Utils.addAlphaTo(StatusColors.red, 0.2) + dangerColor3: Utils.addAlphaTo(StatusColors.red, 0.1) + + successColor1: StatusColors.green + successColor2: Utils.addAlphaTo(StatusColors.green, 0.1) + + mentionColor1: StatusColors.turquoise + mentionColor2: Utils.addAlphaTo(StatusColors.turquoise2, 0.3) + mentionColor3: Utils.addAlphaTo(StatusColors.turquoise2, 0.2) + mentionColor4: Utils.addAlphaTo(StatusColors.turquoise2, 0.1) + + pinColor1: StatusColors.orange + pinColor2: Utils.addAlphaTo(StatusColors.orange2, 0.2) + pinColor3: Utils.addAlphaTo(StatusColors.orange2, 0.1) } diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml index aab571d096..005acce162 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusLightTheme.qml @@ -1,6 +1,7 @@ import QtQuick StatusTheme { - readonly property string name: "light" - readonly property StatusPalette palette: StatusLightPalette {} + name: "light" + + palette: StatusLightPalette {} } diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml index 7ae86fd625..1b76241f20 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusPalette.qml @@ -1,4 +1,32 @@ import QtQuick +/*! + Base interface for the palette requirements of presentation layer + */ QtObject { -} \ No newline at end of file + // Generic colors defined by the design style + required property color baseColor3 + + // Application base colors + required property color appBackgroundColor + + required property color primaryColor1 + required property color primaryColor2 + required property color primaryColor3 + + required property color dangerColor1 + required property color dangerColor2 + required property color dangerColor3 + + required property color successColor1 + required property color successColor2 + + required property color mentionColor1 + required property color mentionColor2 + required property color mentionColor3 + required property color mentionColor4 + + required property color pinColor1 + required property color pinColor2 + required property color pinColor3 +} diff --git a/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml b/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml index cec71f490a..57a06ed1bb 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/StatusTheme.qml @@ -1,5 +1,8 @@ import QtQuick +/*! + Base interface for the look and feel requirements of the presentation layer + */ 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 index 8249cf5e44..7eb86e60a3 100644 --- a/libs/StatusQ/qml/Status/Core/Theme/Style.qml +++ b/libs/StatusQ/qml/Status/Core/Theme/Style.qml @@ -1,27 +1,17 @@ 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 {} +/*! + The main entry point into presentation layer customization + */ +Item { + readonly property StatusPalette palette: Theme.palette + readonly property StatusTheme theme: Theme.current - 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"') - } + readonly property alias geometry: geometryObject + + StatusLayouting { + id: geometryObject } } diff --git a/libs/StatusQ/qml/Status/Core/Theme/Theme.qml b/libs/StatusQ/qml/Status/Core/Theme/Theme.qml new file mode 100644 index 0000000000..d3afc8c36e --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/Theme.qml @@ -0,0 +1,37 @@ +pragma Singleton + +import QtQuick + +import QtQuick.Controls.Universal 2.12 + +/*! + Convenience type for easy access to StatusTheme + */ +QtObject { + property StatusTheme current: lightTheme + property bool isLightTheme: current === lightTheme + readonly property StatusTheme lightTheme: StatusLightTheme {} + readonly property StatusTheme darkTheme: StatusDarkTheme {} + + property QtObject baseFont: FontLoader { + source: "qrc:/Status/FontsAssets/Inter/Inter-Regular.otf" + } + + property StatusPalette palette: current.palette + + property var changeTheme: function (universalTheme, isCurrentSystemThemeDark) { + switch (universalTheme) { + case Universal.Light: + current = lightTheme; + break; + case Universal.Dark: + current = 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/qml/Status/Core/Theme/Utils.qml b/libs/StatusQ/qml/Status/Core/Theme/Utils.qml new file mode 100644 index 0000000000..c502aaf3e4 --- /dev/null +++ b/libs/StatusQ/qml/Status/Core/Theme/Utils.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import QtQuick 2.0 + +/*! + Helper functions for colors and sizes transformations + + \note Consider moving some heavy used functions to C++ for type optimizations. + \note Consider that Qt6 transpile QML files in C++ which are then optimized by compiler; + however, types like \c QVariant is providing limited options compared to native types + */ +QtObject { + function addAlphaTo(baseColor, alpha) { + return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, alpha) + } +} diff --git a/libs/StatusQ/tests/CMakeLists.txt b/libs/StatusQ/tests/CMakeLists.txt index eb685812c6..bb86bedc0e 100644 --- a/libs/StatusQ/tests/CMakeLists.txt +++ b/libs/StatusQ/tests/CMakeLists.txt @@ -35,10 +35,12 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) -add_subdirectory(src) +add_subdirectory(TestHelpers) target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::QuickTest Qt6::Qml Qt6::Quick + + Status::TestHelpers ) diff --git a/libs/StatusQ/tests/TestHelpers/CMakeLists.txt b/libs/StatusQ/tests/TestHelpers/CMakeLists.txt new file mode 100644 index 0000000000..c54ed205df --- /dev/null +++ b/libs/StatusQ/tests/TestHelpers/CMakeLists.txt @@ -0,0 +1,47 @@ +# Base library. Expect most of the module libraries to depend on it +# +cmake_minimum_required(VERSION 3.21) + +project(TestHelpers + VERSION 0.1.0 + LANGUAGES CXX) + +set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS true) + +find_package(GTest REQUIRED) + +find_package(Qt6 ${STATUS_QT_VERSION} COMPONENTS Quick Qml REQUIRED) +qt6_standard_project_setup() + +qt6_add_qml_module(${PROJECT_NAME} + URI Status.TestHelpers + VERSION 1.0 +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_sources(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.h + ${CMAKE_CURRENT_SOURCE_DIR}/IOTestHelpers.h + + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/MonitorQtOutput.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/IOTestHelpers.cpp + + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt +) + +target_link_libraries(${PROJECT_NAME} + PUBLIC + Qt6::Quick + Qt6::Qml + + PRIVATE + GTest::gtest_main +) + +add_library(Status::TestHelpers ALIAS TestHelpers) diff --git a/libs/StatusQ/tests/TestHelpers/IOTestHelpers.cpp b/libs/StatusQ/tests/TestHelpers/IOTestHelpers.cpp new file mode 100644 index 0000000000..bc1ef26bc2 --- /dev/null +++ b/libs/StatusQ/tests/TestHelpers/IOTestHelpers.cpp @@ -0,0 +1,36 @@ +#include "IOTestHelpers.h" + +#include + +namespace fs = std::filesystem; + +namespace Status::Testing { + +fs::path createTestFolder(const std::string& testName) +{ + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::ostringstream timeOss; + timeOss << std::put_time(&tm, "%d-%m-%Y_%H-%M-%S"); + auto tmpPath = fs::path(testing::TempDir())/(testName + "-" + timeOss.str()); + fs::create_directories(tmpPath); + return tmpPath; +} + +AutoCleanTempTestDir::AutoCleanTempTestDir(const std::string &testName) + : m_testFolder(createTestFolder(testName)) +{ +} + +AutoCleanTempTestDir::~AutoCleanTempTestDir() +{ + fs::remove_all(m_testFolder); +} + +const std::filesystem::path& AutoCleanTempTestDir::testFolder() +{ + return m_testFolder; +} + + +} diff --git a/libs/StatusQ/tests/TestHelpers/IOTestHelpers.h b/libs/StatusQ/tests/TestHelpers/IOTestHelpers.h new file mode 100644 index 0000000000..e7ba656ae1 --- /dev/null +++ b/libs/StatusQ/tests/TestHelpers/IOTestHelpers.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include + +namespace Status::Testing { + +class AutoCleanTempTestDir { +public: + /// Creates a temporary folder to be used in tests. The folder content's will + /// be removed when out of scope + explicit AutoCleanTempTestDir(const std::string& testName); + ~AutoCleanTempTestDir(); + + const std::filesystem::path& testFolder(); + +private: + const std::filesystem::path m_testFolder; +}; + +} diff --git a/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp b/libs/StatusQ/tests/TestHelpers/MonitorQtOutput.cpp similarity index 98% rename from libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp rename to libs/StatusQ/tests/TestHelpers/MonitorQtOutput.cpp index 1c6aeefb85..4045ad77fe 100644 --- a/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.cpp +++ b/libs/StatusQ/tests/TestHelpers/MonitorQtOutput.cpp @@ -3,6 +3,8 @@ #include #include +namespace Status::Testing { + std::weak_ptr MonitorQtOutput::m_qtMessageOutputForSharing; std::mutex MonitorQtOutput::m_mutex; QtMessageHandler MonitorQtOutput::m_previousHandler = nullptr; @@ -66,3 +68,5 @@ MonitorQtOutput::restartCapturing() m_previousHandler = prev; m_start = m_thisMessageOutput->length(); } + +} diff --git a/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h b/libs/StatusQ/tests/TestHelpers/MonitorQtOutput.h similarity index 97% rename from libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h rename to libs/StatusQ/tests/TestHelpers/MonitorQtOutput.h index 657ed79b96..e9b0180db5 100644 --- a/libs/StatusQ/tests/src/TestHelpers/MonitorQtOutput.h +++ b/libs/StatusQ/tests/TestHelpers/MonitorQtOutput.h @@ -6,6 +6,8 @@ #include #include +namespace Status::Testing { + /// /// \brief Monitor output for tests and declaratively control message handler availability /// @@ -41,3 +43,5 @@ private: std::shared_ptr m_thisMessageOutput; int m_start = 0; }; + +} diff --git a/libs/StatusQ/tests/src/CMakeLists.txt b/libs/StatusQ/tests/src/CMakeLists.txt deleted file mode 100644 index 3220944cf5..0000000000 --- a/libs/StatusQ/tests/src/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 2728db39a9..0000000000 --- a/libs/StatusQ/tests/src/TestHelpers/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -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/ui/fonts/CMakeLists.txt b/ui/fonts/CMakeLists.txt new file mode 100644 index 0000000000..dc13cad117 --- /dev/null +++ b/ui/fonts/CMakeLists.txt @@ -0,0 +1,28 @@ +# 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(FontAssets + 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.FontsAssets + VERSION 1.0 + # TODO: temporary until we make qt_target_qml_sources work + RESOURCES + Inter/Inter-Regular.otf + + RESOURCE_PREFIX "" +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + Qt6::Qml +)