Manual Explore Rooms

This is an update to searching the public room list. Currently if you can't find the room you're looking for you can type a full alias of room ID into the search bar and a view/join button appears. This is hard to discover and technically broken since it was turned into a generic component for finding rooms (it kinda works but doesn't fit now as it's focussed on the joining rooms not adding new ones to spaces). It is also not very discoverable if you don't know it's there.

This patch patch updates the workflow to be truly generic and hopefully more discoverable. Instead of using the search bar if no results are found a button asking if someone wants to manually enter a room ID or alias appears. This launches a dialog where the user can type in an alias or ID and it has some basic checking to make sure the string looks as expected.

The new functionality also generically works for joining rooms and adding children to spaces.
This commit is contained in:
James Graham
2023-10-11 15:53:21 +00:00
parent 0730f15e2b
commit a9c2428498
4 changed files with 158 additions and 37 deletions

View File

@@ -152,6 +152,7 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/RoomPage.qml
qml/RoomWindow.qml
qml/JoinRoomPage.qml
qml/ManualRoomDialog.qml
qml/ExplorerDelegate.qml
qml/InviteUserPage.qml
qml/StartChatPage.qml

View File

@@ -26,7 +26,7 @@ RowLayout {
if (isJoined) {
RoomManager.enterRoom(root.connection.room(roomId))
} else {
Controller.joinRoom(roomId)
Controller.joinRoom(roomId.length > 0 ? roomId : alias)
}
})
}

View File

@@ -52,32 +52,9 @@ Kirigami.ScrollablePage {
contentItem: RowLayout {
Kirigami.SearchField {
id: identifierField
property bool isRoomAlias: text.match(/#(.+):(.+)/g)
property NeoChatRoom room: isRoomAlias ? connection.roomByAlias(text) : null
property bool isJoined: room != null
Layout.fillWidth: true
placeholderText: i18n("Find a room...")
}
QQC2.Button {
id: joinButton
visible: identifierField.isRoomAlias
text: identifierField.isJoined ? i18n("View") : i18n("Join")
highlighted: true
onClicked: {
if (!identifierField.isJoined) {
Controller.joinRoom(identifierField.text);
// When joining the room, the room will be opened
}
applicationWindow().pageStack.layers.pop();
}
}
QQC2.ComboBox {
id: serverField
@@ -252,19 +229,26 @@ Kirigami.ScrollablePage {
}
}
footer: RowLayout {
width: parent.width
header: Delegates.RoundedItemDelegate {
Layout.fillWidth: true
onClicked: _private.openManualRoomDialog()
QQC2.ProgressBar {
visible: publicRoomsListView.model.loading && publicRoomsListView.count !== 0
indeterminate: true
padding: Kirigami.Units.largeSpacing * 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.topMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
}
text: i18n("Enter a room address")
icon.name: "compass"
icon.width: Kirigami.Units.gridUnit * 2
icon.height: Kirigami.Units.gridUnit * 2
}
footer: QQC2.ProgressBar {
width: parent.width
visible: publicRoomsListView.count !== 0 && publicRoomsListView.model.loading
indeterminate: true
padding: Kirigami.Units.largeSpacing * 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.topMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: Kirigami.Units.largeSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
}
Kirigami.LoadingPlaceholder {
@@ -275,7 +259,24 @@ Kirigami.ScrollablePage {
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
visible: !publicRoomsListView.model.loading && publicRoomsListView.count === 0
text: i18nc("@info:label", "No rooms found")
text: 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.roomSelected.connect((roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined) => {
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.closeDialog();
});
dialog.open();
}
}
}

View File

@@ -0,0 +1,119 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.neochat
Kirigami.Dialog {
id: root
/**
* @brief The connection for the current user.
*/
required property NeoChatConnection connection
/**
* @brief Signal emitted when a valid room id or alias is entered.
*/
signal roomSelected(string roomId,
string displayName,
url avatarUrl,
string alias,
string topic,
int memberCount,
bool isJoined)
title: i18nc("@title", "Room ID or Alias")
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
standardButtons: Kirigami.Dialog.Cancel
customFooterActions: [
Kirigami.Action {
enabled: roomIdAliasText.isValidText
text: i18n("OK")
icon.name: "dialog-ok"
onTriggered: {
// We don't necessarily have all the info so fill out the best we can.
let roomId = roomIdAliasText.isAlias() ? "" : roomIdAliasText.text;
let displayName = "";
let avatarUrl = "";
let alias = roomIdAliasText.isAlias() ? roomIdAliasText.text : "";
let topic = "";
let memberCount = -1;
let isJoined = false;
if (roomIdAliasText.room) {
roomId = roomIdAliasText.room.id;
displayName = roomIdAliasText.room.displayName;
avatarUrl = roomIdAliasText.room.avatarUrl.toString().length > 0 ? connection.makeMediaUrl(roomIdAliasText.room.avatarUrl) : ""
alias = roomIdAliasText.room.canonicalAlias;
topic = roomIdAliasText.room.topic;
memberCount = roomIdAliasText.room.joinedCount;
isJoined = true;
}
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.close();
}
}
]
contentItem: ColumnLayout {
spacing: 0
FormCard.FormTextFieldDelegate {
id: roomIdAliasText
property bool isValidText: text.match(/(#|!)(.+):(.+)/g)
property bool correctStart: text.startsWith("#") || text.startsWith("!")
property NeoChatRoom room: {
if (!acceptableInput) {
return null;
}
if (isAlias()) {
return root.connection.roomByAlias(text);
} else {
return root.connection.room(text);
}
}
label: i18n("Room ID or Alias:")
statusMessage: {
if (text.length > 0 && !correctStart) {
return i18n("Must start with # for an alias or ! for an ID");
}
if (timer.running) {
return "";
}
if (text.length > 0 && !isValidText) {
return i18n("The input is not a valid room ID or alias");
}
return correctStart ? "" : i18n("Must start with # for an alias or ! for an ID");
}
status: text.length > 0 ? Kirigami.MessageType.Error : Kirigami.MessageType.Information
onTextEdited: timer.restart()
function isAlias() {
return roomIdAliasText.text.startsWith("#");
}
Timer {
id: timer
interval: 1000
}
}
}
onVisibleChanged: {
roomIdAliasText.forceActiveFocus()
timer.restart()
}
}