diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d1876676b..8f14ec952 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/qml/ExploreComponent.qml b/src/qml/ExploreComponent.qml index 73f9c5d1e..06d340e1d 100644 --- a/src/qml/ExploreComponent.qml +++ b/src/qml/ExploreComponent.qml @@ -26,7 +26,7 @@ RowLayout { if (isJoined) { RoomManager.enterRoom(root.connection.room(roomId)) } else { - Controller.joinRoom(roomId) + Controller.joinRoom(roomId.length > 0 ? roomId : alias) } }) } diff --git a/src/qml/JoinRoomPage.qml b/src/qml/JoinRoomPage.qml index 205b21b3e..e85a07e27 100644 --- a/src/qml/JoinRoomPage.qml +++ b/src/qml/JoinRoomPage.qml @@ -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(); } } } diff --git a/src/qml/ManualRoomDialog.qml b/src/qml/ManualRoomDialog.qml new file mode 100644 index 000000000..765eb5144 --- /dev/null +++ b/src/qml/ManualRoomDialog.qml @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2023 James Graham +// 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() + } +}