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.
This commit is contained in:
Joshua Goins
2026-01-23 15:44:47 -05:00
parent 593ad27e8c
commit 9d2a427619
4 changed files with 44 additions and 8 deletions

View File

@@ -51,8 +51,16 @@ SearchPage {
signal roomSelected(string roomId, string displayName, url avatarUrl, string alias, string topic, int memberCount, bool isJoined) 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") 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" customPlaceholderIcon: "data-warning"
enableSearch: publicRoomListModel.errorText.length === 0
Component.onCompleted: focusSearch() Component.onCompleted: focusSearch()
@@ -63,6 +71,7 @@ SearchPage {
display: QQC2.Button.IconOnly display: QQC2.Button.IconOnly
checkable: true checkable: true
text: i18nc("@action:button", "Only show spaces") text: i18nc("@action:button", "Only show spaces")
enabled: root.enableSearch
QQC2.ToolTip.visible: hovered QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text 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 activeFocusOnTab: false // We handle moving to this item via up/down arrows, otherwise the tab order is wacky
text: i18n("Enter a Room Manually") text: i18n("Enter a Room Manually")
visible: publicRoomListModel.redirectedText.length === 0 visible: root.customPlaceholderText.length === 0
icon.name: "compass" icon.name: "compass"
icon.width: Kirigami.Units.gridUnit * 2 icon.width: Kirigami.Units.gridUnit * 2
icon.height: Kirigami.Units.gridUnit * 2 icon.height: Kirigami.Units.gridUnit * 2

View File

@@ -80,6 +80,11 @@ Kirigami.ScrollablePage {
*/ */
property bool showSearchButton: true 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. * @brief Message to be shown in a custom placeholder.
* The custom placeholder will be shown if the text is not empty * The custom placeholder will be shown if the text is not empty
@@ -139,6 +144,7 @@ Kirigami.ScrollablePage {
Kirigami.SearchField { Kirigami.SearchField {
id: searchField id: searchField
focus: true focus: true
enabled: root.enableSearch
Layout.fillWidth: true Layout.fillWidth: true
Keys.onEnterPressed: searchButton.clicked() Keys.onEnterPressed: searchButton.clicked()
Keys.onReturnPressed: searchButton.clicked() Keys.onReturnPressed: searchButton.clicked()
@@ -158,6 +164,7 @@ Kirigami.ScrollablePage {
display: QQC2.Button.IconOnly display: QQC2.Button.IconOnly
visible: root.showSearchButton visible: root.showSearchButton
text: i18nc("@action:button", "Search") text: i18nc("@action:button", "Search")
enabled: root.enableSearch
onClicked: { onClicked: {
if (typeof root.model.search === 'function') { if (typeof root.model.search === 'function') {
@@ -173,7 +180,6 @@ Kirigami.ScrollablePage {
Timer { Timer {
id: searchTimer id: searchTimer
interval: 500 interval: 500
running: true
onTriggered: if (typeof root.model.search === 'function') { onTriggered: if (typeof root.model.search === 'function') {
root.model.search(); root.model.search();
} }
@@ -193,7 +199,7 @@ Kirigami.ScrollablePage {
id: noSearchMessage id: noSearchMessage
icon.name: "search" icon.name: "search"
anchors.centerIn: parent 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 helpfulAction: root.noSearchHelpfulAction
} }
@@ -208,13 +214,13 @@ Kirigami.ScrollablePage {
Kirigami.PlaceholderMessage { Kirigami.PlaceholderMessage {
id: customPlaceholder id: customPlaceholder
anchors.centerIn: parent 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 icon.name: root.customPlaceholderIcon
} }
Kirigami.LoadingPlaceholder { Kirigami.LoadingPlaceholder {
anchors.centerIn: parent 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: { Keys.onUpPressed: {

View File

@@ -172,6 +172,8 @@ void PublicRoomListModel::next(int limit)
} }
m_redirectedText.clear(); m_redirectedText.clear();
Q_EMIT redirectedChanged(); Q_EMIT redirectedChanged();
m_errorText.clear();
Q_EMIT errorTextChanged();
if (job) { if (job) {
qCDebug(PublicRoomList) << "Other job running, ignore"; 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); this->beginInsertRows({}, rooms.count(), rooms.count() + job->chunk().count() - 1);
rooms.append(job->chunk()); rooms.append(job->chunk());
this->endInsertRows(); 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(); m_redirectedText = job->jsonData()[u"error"_s].toString();
Q_EMIT redirectedChanged(); Q_EMIT redirectedChanged();
} else {
m_errorText = job->jsonData()[u"error"_s].toString();
Q_EMIT errorTextChanged();
} }
this->job = nullptr; this->job = nullptr;
@@ -329,4 +334,9 @@ QString PublicRoomListModel::redirectedText() const
return m_redirectedText; return m_redirectedText;
} }
QString PublicRoomListModel::errorText() const
{
return m_errorText;
}
#include "moc_publicroomlistmodel.cpp" #include "moc_publicroomlistmodel.cpp"

View File

@@ -53,10 +53,17 @@ class PublicRoomListModel : public QAbstractListModel
Q_PROPERTY(bool searching READ searching NOTIFY searchingChanged) 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) 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: public:
/** /**
* @brief Defines the model roles. * @brief Defines the model roles.
@@ -120,6 +127,8 @@ public:
QString redirectedText() const; QString redirectedText() const;
QString errorText() const;
private: private:
QPointer<NeoChatConnection> m_connection = nullptr; QPointer<NeoChatConnection> m_connection = nullptr;
QString m_server; QString m_server;
@@ -143,6 +152,7 @@ private:
Quotient::QueryPublicRoomsJob *job = nullptr; Quotient::QueryPublicRoomsJob *job = nullptr;
QString m_redirectedText; QString m_redirectedText;
QString m_errorText;
Q_SIGNALS: Q_SIGNALS:
void connectionChanged(); void connectionChanged();
@@ -151,4 +161,5 @@ Q_SIGNALS:
void showOnlySpacesChanged(); void showOnlySpacesChanged();
void searchingChanged(); void searchingChanged();
void redirectedChanged(); void redirectedChanged();
void errorTextChanged();
}; };