From 6e0931e31be59883037f0974694ba0d6d6485736 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 23 Aug 2025 16:55:05 -0400 Subject: [PATCH] Improve search experience somewhat So I noticed that searching for messages feels "buggy". I dove into the code and gave it a pretty nice refresh, I know you'll like it once you try it! Some of the issues I noticed and are now fixed: * The search doesn't clear immediately when you clear the text box, it's delayed like everything else. This also has the knock-on effect of starting random network requests. * If you now press the search button (either with a mouse, pen, etc. or by the keyboard) the search delay timer was still running. * The "nothing is here" placeholder message appears when the search timer is running, making you think no messages were found. These changes also help other places where SearchPage is used, not just message search. --- src/libneochat/qml/SearchPage.qml | 18 +++++++++++------- src/timeline/models/searchmodel.cpp | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/libneochat/qml/SearchPage.qml b/src/libneochat/qml/SearchPage.qml index 472e52725..7a895abca 100644 --- a/src/libneochat/qml/SearchPage.qml +++ b/src/libneochat/qml/SearchPage.qml @@ -112,7 +112,7 @@ Kirigami.ScrollablePage { * @brief Force the search to be updated if the model has a valid search function. */ function updateSearch() { - searchTimer.restart(); + root.model.search(); } header: QQC2.Control { @@ -142,10 +142,13 @@ Kirigami.ScrollablePage { Layout.fillWidth: true Keys.onEnterPressed: searchButton.clicked() Keys.onReturnPressed: searchButton.clicked() - onTextChanged: { - searchTimer.restart(); - if (root.model) { - root.model.searchText = text; + onTextChanged: root.model.searchText = text + onAccepted: { + // If the text is empty, call the search model immediately because it will early-return. + if (root.model.searchText.length === 0) { + root.model.search(); + } else { + searchTimer.restart(); } } } @@ -158,6 +161,7 @@ Kirigami.ScrollablePage { onClicked: { if (typeof root.model.search === 'function') { + searchTimer.stop(); root.model.search(); } } @@ -197,7 +201,7 @@ Kirigami.ScrollablePage { id: noResultMessage icon.name: "search" anchors.centerIn: parent - visible: searchField.text.length > 0 && listView.count === 0 && !root.model.searching && customPlaceholder.text.length === 0 + visible: searchField.text.length > 0 && listView.count === 0 && (!root.model.searching && !searchTimer.running) && customPlaceholder.text.length === 0 helpfulAction: root.noResultHelpfulAction } @@ -210,7 +214,7 @@ Kirigami.ScrollablePage { Kirigami.LoadingPlaceholder { anchors.centerIn: parent - visible: searchField.text.length > 0 && listView.count === 0 && root.model.searching && customPlaceholder.text.length === 0 + visible: searchField.text.length > 0 && listView.count === 0 && (root.model.searching || searchTimer.running) && customPlaceholder.text.length === 0 } Keys.onUpPressed: { diff --git a/src/timeline/models/searchmodel.cpp b/src/timeline/models/searchmodel.cpp index 47f0376c5..4cdbfd8f3 100644 --- a/src/timeline/models/searchmodel.cpp +++ b/src/timeline/models/searchmodel.cpp @@ -26,12 +26,24 @@ void SearchModel::setSearchText(const QString &searchText) void SearchModel::search() { Q_ASSERT(m_room); - setSearching(true); + if (m_job) { m_job->abandon(); m_job = nullptr; } + // early-return case: the user sets the text to nothing, and we simply clear the results + if (m_searchText.isEmpty()) { + clearEventObjects(); + + beginResetModel(); + m_result = std::nullopt; + endResetModel(); + return; + } + + setSearching(true); + RoomEventFilter filter; filter.unreadThreadNotifications = std::nullopt; filter.lazyLoadMembers = true; @@ -48,7 +60,6 @@ void SearchModel::search() .eventContext = SearchJob::IncludeEventContext{3, 3, true}, .includeState = false, .groupings = std::nullopt, - }; auto job = m_room->connection()->callApi(SearchJob::Categories{criteria});