From 9d2a427619d35bd9a2a5c6facde1db4a6e42611d Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Fri, 23 Jan 2026 15:44:47 -0500 Subject: [PATCH] Improve the search pages, especially in error and searching states Someone hit a nasty bug while attempting to find a KDE room on the kde.org server, the error wouldn't come up normally and the dialog would be blank. That's because that specific placeholder message doesn't appear until you type something into the search field, which is weird. There is a few other oddities with SearchPage that I squashed, including showing the loading placeholder in more appropiate situations. --- src/libneochat/qml/ExploreRoomsPage.qml | 13 +++++++++++-- src/libneochat/qml/SearchPage.qml | 14 ++++++++++---- src/rooms/models/publicroomlistmodel.cpp | 12 +++++++++++- src/rooms/models/publicroomlistmodel.h | 13 ++++++++++++- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/libneochat/qml/ExploreRoomsPage.qml b/src/libneochat/qml/ExploreRoomsPage.qml index cca7fa2df..a4e53b3f6 100644 --- a/src/libneochat/qml/ExploreRoomsPage.qml +++ b/src/libneochat/qml/ExploreRoomsPage.qml @@ -51,8 +51,16 @@ SearchPage { signal roomSelected(string roomId, string displayName, url avatarUrl, string alias, string topic, int memberCount, bool isJoined) title: i18nc("@action:title Explore public rooms and spaces", "Explore") - customPlaceholderText: publicRoomListModel.redirectedText + customPlaceholderText: { + if (publicRoomListModel.redirectedText.length > 0) + return publicRoomListModel.redirectedText; + if (publicRoomListModel.errorText.length > 0) + return publicRoomListModel.errorText; + + return ""; + } customPlaceholderIcon: "data-warning" + enableSearch: publicRoomListModel.errorText.length === 0 Component.onCompleted: focusSearch() @@ -63,6 +71,7 @@ SearchPage { display: QQC2.Button.IconOnly checkable: true text: i18nc("@action:button", "Only show spaces") + enabled: root.enableSearch QQC2.ToolTip.visible: hovered QQC2.ToolTip.text: text @@ -96,7 +105,7 @@ SearchPage { activeFocusOnTab: false // We handle moving to this item via up/down arrows, otherwise the tab order is wacky text: i18n("Enter a Room Manually") - visible: publicRoomListModel.redirectedText.length === 0 + visible: root.customPlaceholderText.length === 0 icon.name: "compass" icon.width: Kirigami.Units.gridUnit * 2 icon.height: Kirigami.Units.gridUnit * 2 diff --git a/src/libneochat/qml/SearchPage.qml b/src/libneochat/qml/SearchPage.qml index 7a895abca..da01a7740 100644 --- a/src/libneochat/qml/SearchPage.qml +++ b/src/libneochat/qml/SearchPage.qml @@ -80,6 +80,11 @@ Kirigami.ScrollablePage { */ property bool showSearchButton: true + /** + * @brief Enable the search controls like the text field and button. + */ + property bool enableSearch: true + /** * @brief Message to be shown in a custom placeholder. * The custom placeholder will be shown if the text is not empty @@ -139,6 +144,7 @@ Kirigami.ScrollablePage { Kirigami.SearchField { id: searchField focus: true + enabled: root.enableSearch Layout.fillWidth: true Keys.onEnterPressed: searchButton.clicked() Keys.onReturnPressed: searchButton.clicked() @@ -158,6 +164,7 @@ Kirigami.ScrollablePage { display: QQC2.Button.IconOnly visible: root.showSearchButton text: i18nc("@action:button", "Search") + enabled: root.enableSearch onClicked: { if (typeof root.model.search === 'function') { @@ -173,7 +180,6 @@ Kirigami.ScrollablePage { Timer { id: searchTimer interval: 500 - running: true onTriggered: if (typeof root.model.search === 'function') { root.model.search(); } @@ -193,7 +199,7 @@ Kirigami.ScrollablePage { id: noSearchMessage icon.name: "search" anchors.centerIn: parent - visible: searchField.text.length === 0 && listView.count === 0 && customPlaceholder.text.length === 0 + visible: searchField.text.length === 0 && listView.count === 0 && !root.model.searching && customPlaceholder.text.length === 0 helpfulAction: root.noSearchHelpfulAction } @@ -208,13 +214,13 @@ Kirigami.ScrollablePage { Kirigami.PlaceholderMessage { id: customPlaceholder anchors.centerIn: parent - visible: searchField.text.length > 0 && listView.count === 0 && !root.model.searching && text.length > 0 + visible: listView.count === 0 && !root.model.searching && text.length > 0 icon.name: root.customPlaceholderIcon } Kirigami.LoadingPlaceholder { anchors.centerIn: parent - visible: searchField.text.length > 0 && listView.count === 0 && (root.model.searching || searchTimer.running) && customPlaceholder.text.length === 0 + visible: listView.count === 0 && (root.model.searching || searchTimer.running) } Keys.onUpPressed: { diff --git a/src/rooms/models/publicroomlistmodel.cpp b/src/rooms/models/publicroomlistmodel.cpp index 6bc828e52..e3b3d698b 100644 --- a/src/rooms/models/publicroomlistmodel.cpp +++ b/src/rooms/models/publicroomlistmodel.cpp @@ -172,6 +172,8 @@ void PublicRoomListModel::next(int limit) } m_redirectedText.clear(); Q_EMIT redirectedChanged(); + m_errorText.clear(); + Q_EMIT errorTextChanged(); if (job) { qCDebug(PublicRoomList) << "Other job running, ignore"; @@ -200,9 +202,12 @@ void PublicRoomListModel::next(int limit) this->beginInsertRows({}, rooms.count(), rooms.count() + job->chunk().count() - 1); rooms.append(job->chunk()); this->endInsertRows(); - } else if (job->error() == BaseJob::ContentAccessError) { + } else if (job->error() == BaseJob::ContentAccessError && !m_searchText.isEmpty()) { m_redirectedText = job->jsonData()[u"error"_s].toString(); Q_EMIT redirectedChanged(); + } else { + m_errorText = job->jsonData()[u"error"_s].toString(); + Q_EMIT errorTextChanged(); } this->job = nullptr; @@ -329,4 +334,9 @@ QString PublicRoomListModel::redirectedText() const return m_redirectedText; } +QString PublicRoomListModel::errorText() const +{ + return m_errorText; +} + #include "moc_publicroomlistmodel.cpp" diff --git a/src/rooms/models/publicroomlistmodel.h b/src/rooms/models/publicroomlistmodel.h index 2c2cecdeb..7d2cdc4f1 100644 --- a/src/rooms/models/publicroomlistmodel.h +++ b/src/rooms/models/publicroomlistmodel.h @@ -53,10 +53,17 @@ class PublicRoomListModel : public QAbstractListModel Q_PROPERTY(bool searching READ searching NOTIFY searchingChanged) /** - * @brief The text returned by the server after redirection + * @brief The text returned by the server after redirection (after performing a search) */ Q_PROPERTY(QString redirectedText READ redirectedText NOTIFY redirectedChanged) + /** + * @brief The error while trying to list the rooms (not after searching, which is covered by redirectedText) + * + * This is useful when a server completely shut off room search, or any kind of network error. + */ + Q_PROPERTY(QString errorText READ errorText NOTIFY errorTextChanged) + public: /** * @brief Defines the model roles. @@ -120,6 +127,8 @@ public: QString redirectedText() const; + QString errorText() const; + private: QPointer m_connection = nullptr; QString m_server; @@ -143,6 +152,7 @@ private: Quotient::QueryPublicRoomsJob *job = nullptr; QString m_redirectedText; + QString m_errorText; Q_SIGNALS: void connectionChanged(); @@ -151,4 +161,5 @@ Q_SIGNALS: void showOnlySpacesChanged(); void searchingChanged(); void redirectedChanged(); + void errorTextChanged(); };