diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a93cea8c6..86e3a86f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -304,6 +304,7 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN qml/SearchPage.qml qml/ServerComboBox.qml qml/UserSearchPage.qml + qml/ManualUserDialog.qml RESOURCES qml/confetti.png qml/glowdot.png diff --git a/src/qml/ManualUserDialog.qml b/src/qml/ManualUserDialog.qml new file mode 100644 index 000000000..9a5a85218 --- /dev/null +++ b/src/qml/ManualUserDialog.qml @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2024 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.formcard as FormCard + +import org.kde.neochat + +Kirigami.Dialog { + id: root + + /** + * @brief The connection for the current user. + */ + required property NeoChatConnection connection + + /** + * @brief Thrown when a user is selected. + */ + signal userSelected() + + title: i18nc("@title", "User ID") + + 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: userIdText.isValidText + text: i18n("OK") + icon.name: "dialog-ok" + onTriggered: { + root.connection.openOrCreateDirectChat(userIdText.text) + root.accept(); + } + } + ] + + contentItem: ColumnLayout { + spacing: 0 + FormCard.FormTextFieldDelegate { + id: userIdText + property bool isValidText: text.match(/@(.+):(.+)/g) + property bool correctStart: text.startsWith("@") + + label: i18n("User ID:") + statusMessage: { + if (text.length > 0 && !correctStart) { + return i18n("User IDs Must start with @"); + } + if (timer.running) { + return ""; + } + if (text.length > 0 && !isValidText) { + return i18n("The input is not a valid user ID"); + } + return correctStart ? "" : i18n("User IDs Must start with @"); + } + status: text.length > 0 ? Kirigami.MessageType.Error : Kirigami.MessageType.Information + + onTextEdited: timer.restart() + + Timer { + id: timer + interval: 1000 + } + } + } + + onVisibleChanged: { + userIdText.forceActiveFocus() + timer.restart() + } +} diff --git a/src/qml/UserSearchPage.qml b/src/qml/UserSearchPage.qml index 93affd3d4..19246d2d6 100644 --- a/src/qml/UserSearchPage.qml +++ b/src/qml/UserSearchPage.qml @@ -13,11 +13,11 @@ import org.kde.kirigamiaddons.labs.components as Components import org.kde.neochat /** - * @brief Component for finding rooms for the public list. + * @brief Component for finding users from 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. + * This component is based on a SearchPage and allows the user to enter a search + * term into the input field and then search the room for messages with text that + * matches the input. * * @sa SearchPage */ @@ -38,6 +38,15 @@ SearchPage { connection: root.connection } + listHeaderDelegate: Delegates.RoundedItemDelegate { + onClicked: _private.openManualUserDialog() + + text: i18n("Enter a user ID") + icon.name: "list-add-user" + icon.width: Kirigami.Units.gridUnit * 2 + icon.height: Kirigami.Units.gridUnit * 2 + } + modelDelegate: Delegates.RoundedItemDelegate { id: userDelegate required property string userId @@ -82,18 +91,15 @@ SearchPage { noResultPlaceholderMessage: i18nc("@info:label", "No matches found") Component { - id: manualRoomDialog - ManualRoomDialog {} + id: manualUserDialog + ManualUserDialog {} } 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(); - }); + function openManualUserDialog() { + let dialog = manualUserDialog.createObject(applicationWindow().overlay, {connection: root.connection}); + dialog.accepted.connect(() => {root.closeDialog();}); dialog.open(); } }