From 11581306e4d3edaf6d7c0054a63c3d71283cc2c6 Mon Sep 17 00:00:00 2001 From: Mohsen Date: Sat, 17 Aug 2024 16:38:03 +0330 Subject: [PATCH] impl simple search bar. --- src/core/qfieldcloudprojectsmodel.cpp | 28 ++++++++--- src/core/qfieldcloudprojectsmodel.h | 3 ++ src/qml/QFieldCloudScreen.qml | 68 +++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/src/core/qfieldcloudprojectsmodel.cpp b/src/core/qfieldcloudprojectsmodel.cpp index 15e7041e33..a15572a35f 100644 --- a/src/core/qfieldcloudprojectsmodel.cpp +++ b/src/core/qfieldcloudprojectsmodel.cpp @@ -2453,22 +2453,38 @@ bool QFieldCloudProjectsFilterModel::showLocalOnly() const bool QFieldCloudProjectsFilterModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const { - if ( mShowLocalOnly && mSourceModel->data( mSourceModel->index( source_row, 0, source_parent ), QFieldCloudProjectsModel::LocalPathRole ).toString().isEmpty() ) + auto currentRowIndex = mSourceModel->index( source_row, 0, source_parent ); + if ( mShowLocalOnly && mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::LocalPathRole ).toString().isEmpty() ) { return false; } - bool ok = false; + bool matchesProjectType = false; switch ( mFilter ) { case PrivateProjects: // the list will include public "community" projects that are present locally so they can appear in the "My projects" list - ok = mSourceModel->data( mSourceModel->index( source_row, 0, source_parent ), QFieldCloudProjectsModel::UserRoleOriginRole ).toString() != QStringLiteral( "public" ) - || !mSourceModel->data( mSourceModel->index( source_row, 0, source_parent ), QFieldCloudProjectsModel::LocalPathRole ).toString().isEmpty(); + matchesProjectType = mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::UserRoleOriginRole ).toString() != QStringLiteral( "public" ) + || !mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::LocalPathRole ).toString().isEmpty(); break; case PublicProjects: - ok = mSourceModel->data( mSourceModel->index( source_row, 0, source_parent ), QFieldCloudProjectsModel::UserRoleOriginRole ).toString() == QStringLiteral( "public" ); + matchesProjectType = mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::UserRoleOriginRole ).toString() == QStringLiteral( "public" ); break; } - return ok; + + QString Name = mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::NameRole ).toString(); + QString Description = mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::DescriptionRole ).toString(); + QString Owner = mSourceModel->data( currentRowIndex, QFieldCloudProjectsModel::OwnerRole ).toString(); + + bool matchesTextFilter = mTextFilter.isEmpty() || Name.contains( mTextFilter, Qt::CaseInsensitive ) || Description.contains( mTextFilter, Qt::CaseInsensitive ) || Owner.contains( mTextFilter, Qt::CaseInsensitive ); + + return matchesProjectType && matchesTextFilter; +} + +void QFieldCloudProjectsFilterModel::setTextFilter( const QString &newTextFilter ) +{ + if ( mTextFilter == newTextFilter ) + return; + mTextFilter = newTextFilter; + invalidateFilter(); } diff --git a/src/core/qfieldcloudprojectsmodel.h b/src/core/qfieldcloudprojectsmodel.h index de3148c496..382f0e68a4 100644 --- a/src/core/qfieldcloudprojectsmodel.h +++ b/src/core/qfieldcloudprojectsmodel.h @@ -553,6 +553,8 @@ class QFieldCloudProjectsFilterModel : public QSortFilterProxyModel */ void setShowLocalOnly( bool showLocalOnly ); + Q_INVOKABLE void setTextFilter( const QString &newTextFilter ); + signals: void projectsModelChanged(); @@ -566,6 +568,7 @@ class QFieldCloudProjectsFilterModel : public QSortFilterProxyModel QFieldCloudProjectsModel *mSourceModel = nullptr; ProjectsFilter mFilter = PrivateProjects; bool mShowLocalOnly = false; + QString mTextFilter; }; Q_DECLARE_METATYPE( QFieldCloudProjectsFilterModel::ProjectsFilter ) diff --git a/src/qml/QFieldCloudScreen.qml b/src/qml/QFieldCloudScreen.qml index dadf676696..c9023605ec 100644 --- a/src/qml/QFieldCloudScreen.qml +++ b/src/qml/QFieldCloudScreen.qml @@ -192,6 +192,71 @@ Page { property bool overshootRefresh: false property bool refreshing: false + headerPositioning: ListView.OverlayHeader + + header: Rectangle { + width: table.width + height: 41 + color: Theme.mainBackgroundColor + z: 20 + + Rectangle { + width: table.width + height: 40 + radius: 6 + border.width: 1 + color: Theme.mainBackgroundColor + border.color: searchBar.activeFocus ? Theme.mainColor : "transparent" + + QfToolButton { + id: searchButton + width: 40 + height: 40 + anchors.left: parent.left + bgcolor: "transparent" + iconSource: Theme.getThemeIcon("ic_baseline_search_black") + iconColor: Theme.mainTextColor + onClicked: { + table.model.setTextFilter(searchBar.text); + } + } + + QfToolButton { + id: clearButton + anchors.right: parent.right + width: 40 + height: 40 + iconSource: Theme.getThemeIcon('ic_close_black_24dp') + iconColor: Theme.mainTextColor + bgcolor: "transparent" + visible: searchBar.text !== "" + onClicked: { + searchBar.text = ''; + table.model.setTextFilter(''); + } + } + + TextField { + id: searchBar + padding: 7 + anchors.left: searchButton.right + anchors.right: clearButton.left + anchors.rightMargin: 4 + height: 40 + leftPadding: padding + 4 + selectByMouse: true + placeholderText: (!searchBar.activeFocus && text === "" && displayText === "") ? qsTr("Search for project") : "" + background: Item { + } + Keys.onEnterPressed: { + table.model.setTextFilter(text); + } + Keys.onReturnPressed: { + table.model.setTextFilter(text); + } + } + } + } model: QFieldCloudProjectsFilterModel { projectsModel: cloudProjectsModel @@ -420,6 +485,7 @@ Page { MouseArea { property Item pressedItem + propagateComposedEvents: true anchors.fill: parent onClicked: mouse => { var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); @@ -433,6 +499,7 @@ Page { cloudProjectsModel.projectPackageAndDownload(item.projectId); } } + mouse.accepted = false; } onPressed: mouse => { var item = table.itemAt(table.contentX + mouse.x, table.contentY + mouse.y); @@ -440,6 +507,7 @@ Page { pressedItem = item; pressedItem.isPressed = true; } + mouse.accepted = false; } onCanceled: { if (pressedItem) {