Files
neochat/src/qml/ExploreRoomsPage.qml
Joshua Goins 364eda6400 Fix keyboard navigation on search pages
Some of our search pages (such as the room and user search) has a list
header item. Due to how this works, it's not actually a part of the
list view keyboard navigation and a whole separate item. So in the tab
order, it comes *after* the list view which makes no sense. And it's
part of the list view, so users must expect it to be selectable with the
up and down arrows like other items.

This simple change makes it so it behaves as expected. The first actual
list item is selected by default, but it's possible to navigate to the
list header item via the up arrow key and then return to the list view
using the down arrow. The list header item is also removed from the tab
order and the whole page is much nicer to use now.
2024-06-08 15:44:38 +00:00

130 lines
4.0 KiB
QML

// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
// SPDX-License-Identifier: GPL-3.0-only
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import Qt.labs.qmlmodels
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.neochat
/**
* @brief Component for finding rooms for the public list.
*
* This component is based on a SearchPage, adding the functionality to select or
* enter a server in the header, as well as the ability to manually type a room in
* if the public room search cannot find it.
*
* @sa SearchPage
*/
SearchPage {
id: root
/**
* @brief The connection for the current local user.
*/
required property NeoChatConnection connection
/**
* @brief Whether results should only includes spaces.
*/
property bool showOnlySpaces: spacesOnlyButton.checked
onShowOnlySpacesChanged: updateSearch()
/**
* @brief Whetherthe button to toggle the showOnlySpaces state should be shown.
*/
property bool showOnlySpacesButton: true
/**
* @brief Signal emitted when a room is selected.
*
* The signal contains all the room's info so that it can be acted
* upon as required, e.g. joining or entering the room or adding the room as
* the child of a space.
*/
signal roomSelected(string roomId, string displayName, url avatarUrl, string alias, string topic, int memberCount, bool isJoined)
title: i18nc("@action:title", "Explore Rooms")
Component.onCompleted: focusSearch()
headerTrailing: RowLayout {
QQC2.Button {
id: spacesOnlyButton
icon.name: "globe"
display: QQC2.Button.IconOnly
checkable: true
text: i18nc("@action:button", "Only show spaces")
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
}
ServerComboBox {
id: serverComboBox
connection: root.connection
}
}
model: PublicRoomListModel {
id: publicRoomListModel
connection: root.connection
server: serverComboBox.server
showOnlySpaces: root.showOnlySpaces
}
modelDelegate: ExplorerDelegate {
onRoomSelected: (roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.closeDialog();
}
}
listHeaderDelegate: Delegates.RoundedItemDelegate {
onClicked: _private.openManualRoomDialog()
activeFocusOnTab: false // We handle moving to this item via up/down arrows, otherwise the tab order is wacky
text: i18n("Enter a room address")
icon.name: "compass"
icon.width: Kirigami.Units.gridUnit * 2
icon.height: Kirigami.Units.gridUnit * 2
}
listFooterDelegate: QQC2.ProgressBar {
width: ListView.view.width
leftInset: Kirigami.Units.largeSpacing
rightInset: Kirigami.Units.largeSpacing
visible: root.count !== 0 && publicRoomListModel.searching
indeterminate: true
}
searchFieldPlaceholder: i18n("Find a room…")
noResultPlaceholderMessage: i18nc("@info:label", "No public rooms found")
Component {
id: manualRoomDialog
ManualRoomDialog {}
}
QtObject {
id: _private
function openManualRoomDialog() {
let dialog = manualRoomDialog.createObject(applicationWindow().overlay, {
connection: root.connection
});
dialog.parent = root.Window.window.overlay;
dialog.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.closeDialog();
});
dialog.open();
}
}
}