From 9b89e08294c19f2cbb865700451bbf540aa290e8 Mon Sep 17 00:00:00 2001 From: Patryk Osmaczko Date: Tue, 19 Jul 2022 12:29:18 +0200 Subject: [PATCH] feat: add filtering&sorting example closes: status-im/status-desktop#6510 closes: status-im/status-desktop#6512 --- CMakeLists.txt | 7 +- sandbox/CMakeLists.txt | 5 +- sandbox/demoapp/data/Models.qml | 13 ++- sandbox/examples/FilteringSorting.qml | 154 ++++++++++++++++++++++++++ sandbox/main.cpp | 4 + sandbox/main.qml | 61 +++++++++- sandbox/qml.qrc | 1 + sandbox/sandboxapp.cpp | 4 +- 8 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 sandbox/examples/FilteringSorting.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 35e990ab..ad521d99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,11 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# add_subdirectory(src) +# https://doc.qt.io/qtcreator/creator-qml-modules-with-plugins.html#importing-qml-modules +set(QML_IMPORT_PATH + ${CMAKE_SOURCE_DIR}/src;${QML_IMPORT_PATH} + CACHE STRING "") + +add_subdirectory(vendor/SortFilterProxyModel) add_subdirectory(sandbox) add_subdirectory(tests) diff --git a/sandbox/CMakeLists.txt b/sandbox/CMakeLists.txt index efe18fc6..ead6a2bd 100644 --- a/sandbox/CMakeLists.txt +++ b/sandbox/CMakeLists.txt @@ -28,5 +28,6 @@ endif() target_compile_definitions(${PROJECT_NAME} PRIVATE SRC_DIR="${CMAKE_CURRENT_LIST_DIR}") -target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick - Qt5::QuickControls2) +target_link_libraries( + ${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick Qt5::QuickControls2 + SortFilterProxyModel) diff --git a/sandbox/demoapp/data/Models.qml b/sandbox/demoapp/data/Models.qml index 403dfb10..91daff0e 100644 --- a/sandbox/demoapp/data/Models.qml +++ b/sandbox/demoapp/data/Models.qml @@ -913,8 +913,19 @@ CExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2I notificationsCount: 0 } ListElement { - sectionId: "demoApp" + sectionId: "examples" sectionType: 101 + name: "Examples" + active: false + image: "" + icon: "show" + color: "" + hasNotification: false + notificationsCount: 0 + } + ListElement { + sectionId: "demoApp" + sectionType: 102 name: "Demo Application" active: false image: "" diff --git a/sandbox/examples/FilteringSorting.qml b/sandbox/examples/FilteringSorting.qml new file mode 100644 index 00000000..44c6e793 --- /dev/null +++ b/sandbox/examples/FilteringSorting.qml @@ -0,0 +1,154 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core.Utils 0.1 + +import SortFilterProxyModel 0.2 + +ColumnLayout { + id: root + + RowLayout { + Layout.fillWidth: true + + StatusIconTextButton { + id: sortBtn + + property int sortOrder: -1 + statusIcon: { + if (sortOrder == Qt.AscendingOrder) return "chevron-down" + if (sortOrder == Qt.DescendingOrder) return "chevron-up" + return "remove" + } + + onClicked: { + var st = sortOrder + 1 + sortOrder = st > 1 ? -1 : st + } + } + + StatusInput { + id: searchInput + + Layout.fillWidth: true + input.icon.name: "search" + input.placeholderText: "nickname.." + } + + StatusIconTabButton { + id: contactBtn + + icon.name: "tiny/tiny-contact" + identicon.icon.color: Theme.palette.primaryColor1 + onClicked: highlighted = !highlighted + } + + StatusIconTabButton { + id: verifiedBtn + + icon.name: "tiny/tiny-checkmark" + identicon.icon.color: Theme.palette.primaryColor1 + onClicked: highlighted = !highlighted + } + } + + ListView { + Layout.fillWidth: true + implicitHeight: contentItem.childrenRect.height + spacing: 4 + + model: SortFilterProxyModel { + sourceModel: d.users + sorters: StringSorter { + enabled: sortBtn.sortOrder !== -1 + roleName: "nick" + sortOrder: sortBtn.sortOrder + } + filters: [ + ExpressionFilter { + expression: model.nick.startsWith(searchInput.text) + }, + AllOf { + enabled: contactBtn.highlighted || verifiedBtn.highlighted + ValueFilter { + enabled: contactBtn.highlighted + roleName: "isContact" + value: true + } + ValueFilter { + enabled: verifiedBtn.highlighted + roleName: "isVerified" + value: true + } + } + ] + } + + delegate: StatusMemberListItem { + width: parent.width + userName: model.name + nickName: model.nick + isVerified: model.isVerified + isContact: model.isContact + } + } + + QtObject { + id: d + + readonly property ListModel users: ListModel { + ListElement { + name: "Richard" + nick: "Ricky" + isVerified: true + isContact: true + } + ListElement { + name: "Susan" + nick: "Sue" + isVerified: false + isContact: false + } + ListElement { + name: "Edward" + nick: "Ed" + isVerified: true + isContact: false + } + ListElement { + name: "Toomas" + nick: "Tommy" + isVerified: false + isContact: false + } + ListElement { + name: "Elizabeth" + nick: "Bess" + isVerified: true + isContact: true + } + ListElement { + name: "Thomas" + nick: "Tom" + isVerified: false + isContact: true + } + ListElement { + name: "Fernando" + nick: "Alonso" + isVerified: false + isContact: true + } + ListElement { + name: "Alexander" + nick: "Alex" + isVerified: true + isContact: false + } + } + } +} diff --git a/sandbox/main.cpp b/sandbox/main.cpp index c59b39dd..e71c3599 100644 --- a/sandbox/main.cpp +++ b/sandbox/main.cpp @@ -4,6 +4,8 @@ #include "sandboxapp.h" +#include + int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) @@ -12,6 +14,8 @@ int main(int argc, char *argv[]) SandboxApp app(argc, argv); + qqsfpm::registerTypes(); + qputenv("QT_QUICK_CONTROLS_HOVER_ENABLED", QByteArrayLiteral("1")); app.setOrganizationName("Status"); diff --git a/sandbox/main.qml b/sandbox/main.qml index 52c10226..8c1da543 100644 --- a/sandbox/main.qml +++ b/sandbox/main.qml @@ -4,6 +4,7 @@ import QtQuick.Controls 2.14 import QtGraphicalEffects 1.13 import QtQuick.Layouts 1.14 import Qt.labs.settings 1.0 +import QtQml.Models 2.14 import Sandbox 0.1 @@ -14,6 +15,8 @@ import StatusQ.Components 0.1 import StatusQ.Layout 0.1 import StatusQ.Platform 0.1 +import SortFilterProxyModel 0.2 + import "demoapp/data" 1.0 StatusWindow { @@ -44,7 +47,8 @@ StatusWindow { readonly property int nodeManagement: 4 readonly property int profileSettings: 5 readonly property int apiDocumentation: 100 - readonly property int demoApp: 101 + readonly property int examples: 101 + readonly property int demoApp: 102 } function setActiveItem(sectionId) { @@ -87,13 +91,16 @@ StatusWindow { if(model.sectionType === appSectionType.apiDocumentation) { stackView.push(libraryDocumentationCmp) - rootWindow.setActiveItem(sectionId) + } + else if(model.sectionType === appSectionType.examples) + { + stackView.push(examplesCmp) } else if(model.sectionType === appSectionType.demoApp) { stackView.push(demoAppCmp) - rootWindow.setActiveItem(model.sectionId) } + rootWindow.setActiveItem(model.sectionId) } } } @@ -400,6 +407,53 @@ StatusWindow { } } + Component { + id: examplesCmp + + StatusAppTwoPanelLayout { + id: examplesView + + function example(name) { + examplesLoader.source = Qt.resolvedUrl("./examples/" + name + ".qml") + storeSettings.selectedExample = examplesLoader.source + } + + readonly property string defaultExampleSource: example("FilteringSorting") + + leftPanel: StatusScrollView { + id: examplesLeftPanel + + anchors.fill: parent + anchors.topMargin: 48 + + ColumnLayout { + width: examplesLeftPanel.availableWidth + spacing: 0 + + StatusNavigationListItem { + Layout.fillWidth: true + title: "FilteringSorting" + selected: examplesLoader.source.toString().includes(title) + onClicked: examplesView.example(title) + } + } + } + + rightPanel: StatusScrollView { + id: examplesRightPanel + anchors.fill: parent + anchors.margins: 64 + anchors.topMargin: anchors.margins + 32 + + Loader { + id: examplesLoader + width: examplesRightPanel.availableWidth + source: storeSettings.selectedExample !== "" ? storeSettings.selectedExample : examplesView.defaultExampleSource + } + } + } + } + Component { id: demoAppCmp @@ -494,6 +548,7 @@ StatusWindow { Settings { id: storeSettings property string selected: "" + property string selectedExample: "" property bool lightTheme: true property bool fillPage: false } diff --git a/sandbox/qml.qrc b/sandbox/qml.qrc index b14b180f..50d103ac 100644 --- a/sandbox/qml.qrc +++ b/sandbox/qml.qrc @@ -75,5 +75,6 @@ DemoApp.qml main.qml ThemeSwitch.qml + examples/FilteringSorting.qml diff --git a/sandbox/sandboxapp.cpp b/sandbox/sandboxapp.cpp index 246c7f6e..7278fa1a 100644 --- a/sandbox/sandboxapp.cpp +++ b/sandbox/sandboxapp.cpp @@ -20,7 +20,7 @@ void SandboxApp::startEngine() qmlRegisterType("Sandbox", 0, 1, "Spellchecker"); #ifdef QT_DEBUG - const QUrl url = QUrl::fromLocalFile(SRC_DIR + QString{"/main.qml"}); + const QUrl url = QUrl::fromLocalFile(SRC_DIR + QStringLiteral("/main.qml")); #else const QUrl url(QStringLiteral("qrc:/main.qml")); #endif @@ -29,7 +29,7 @@ void SandboxApp::startEngine() #ifdef QT_DEBUG - m_engine.addImportPath(SRC_DIR + QString{"/../src"}); + m_engine.addImportPath(SRC_DIR + QStringLiteral("/../src")); #else m_engine.addImportPath(QStringLiteral(":/")); #endif