diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e34e2da..fe21addb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ and this project adheres to - Removed delay when multiple rooms are removed/hidden from the list. This should provide a smoother experience when filtering rooms or collapsing - accounts. + accounts, and prevent the account duplication bug. If you encounter issues with these operations like the room list becoming invisible, make sure first that your Qt installation is up-to-date (latest x.y.Z version, e.g. 5.14.2). diff --git a/TODO.md b/TODO.md index 2d9f00d9..7ee19027 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,12 @@ # TODO +- fix cursor over field +- update room highlight when creating new room +- unknownerror matrixnotfound when creatign directchat +- keyerror when forgetting room while loading members +- account order, and verify not adding to config fiel works +- Refetch profile after manual profile change, don't wait for a room event + ## Refactoring - Rewrite account settings using `HTabbedContainer` @@ -155,7 +162,6 @@ ## Backend - Saving the room settings -- Refetch profile after manual profile change, don't wait for a room event - Better config file format diff --git a/src/gui/Base/HLabeledTextField.qml b/src/gui/Base/HLabeledItem.qml similarity index 76% rename from src/gui/Base/HLabeledTextField.qml rename to src/gui/Base/HLabeledItem.qml index 30b39477..1bde44a9 100644 --- a/src/gui/Base/HLabeledTextField.qml +++ b/src/gui/Base/HLabeledItem.qml @@ -7,10 +7,12 @@ HColumnLayout { spacing: theme.spacing / 2 - property alias label: label - property alias errorLabel: errorLabel - property alias field: field - property alias toolTip: toolTip + default property alias insideData: itemHolder.data + + readonly property Item item: itemHolder.visibleChildren[0] + readonly property alias label: label + readonly property alias errorLabel: errorLabel + readonly property alias toolTip: toolTip HRowLayout { @@ -49,9 +51,10 @@ HColumnLayout { } } - HTextField { - id: field - radius: 2 + Item { + id: itemHolder + // implicitWidth: childrenRect.width + implicitHeight: childrenRect.height Layout.fillWidth: true } diff --git a/src/gui/Pages/AccountSettings/Profile.qml b/src/gui/Pages/AccountSettings/Profile.qml index bbd71820..23ee0a27 100644 --- a/src/gui/Pages/AccountSettings/Profile.qml +++ b/src/gui/Pages/AccountSettings/Profile.qml @@ -12,7 +12,7 @@ HGridLayout { saveButton.nameChangeRunning = true py.callClientCoro( - userId, "set_displayname", [nameField.field.text], () => { + userId, "set_displayname", [nameField.item.text], () => { saveButton.nameChangeRunning = false accountSettings.headerName = Qt.binding(() => accountInfo.display_name) @@ -21,7 +21,7 @@ HGridLayout { } if (aliasField.changed) { - window.settings.writeAliases[userId] = aliasField.field.text + window.settings.writeAliases[userId] = aliasField.item.text window.settingsChanged() } @@ -41,8 +41,8 @@ HGridLayout { } function cancelChanges() { - nameField.field.text = accountInfo.display_name - aliasField.field.text = aliasField.currentAlias + nameField.item.text = accountInfo.display_name + aliasField.item.text = aliasField.currentAlias fileDialog.selectedFile = "" fileDialog.file = "" @@ -53,14 +53,14 @@ HGridLayout { flow: pageLoader.isWide ? GridLayout.LeftToRight : GridLayout.TopToBottom rowSpacing: currentSpacing - Component.onCompleted: nameField.field.forceActiveFocus() + Component.onCompleted: nameField.item.forceActiveFocus() HUserAvatar { property bool changed: Boolean(sourceOverride) id: avatar userId: accountSettings.userId - displayName: nameField.field.text + displayName: nameField.item.text mxc: accountInfo.avatar_url toolTipMxc: "" sourceOverride: fileDialog.selectedFile || fileDialog.file @@ -155,36 +155,38 @@ HGridLayout { Layout.fillWidth: true } - HLabeledTextField { - property bool changed: field.text !== accountInfo.display_name - - readonly property string fText: field.text - onFTextChanged: accountSettings.headerName = field.text + HLabeledItem { + property bool changed: item.text !== accountInfo.display_name id: nameField label.text: qsTr("Display name:") - field.maximumLength: 255 - field.onAccepted: applyChanges() - - Component.onCompleted: field.text = accountInfo.display_name - - Keys.onEscapePressed: cancelChanges() Layout.fillWidth: true Layout.maximumWidth: 480 + + HTextField { + width: parent.width + maximumLength: 255 + + onAccepted: applyChanges() + onTextChanged: accountSettings.headerName = text + Component.onCompleted: text = accountInfo.display_name + + Keys.onEscapePressed: cancelChanges() + } } - HLabeledTextField { + HLabeledItem { property string currentAlias: aliases[userId] || "" - property bool changed: field.text !== currentAlias + property bool changed: item.text !== currentAlias readonly property var aliases: window.settings.writeAliases readonly property string alreadyTakenBy: { - if (! field.text) return "" + if (! item.text) return "" for (const [id, idAlias] of Object.entries(aliases)) - if (id !== userId && idAlias === field.text) return id + if (id !== userId && idAlias === item.text) return id return "" } @@ -199,14 +201,6 @@ HGridLayout { qsTr("Taken by %1").arg(alreadyTakenBy) : "" - field.error: alreadyTakenBy !== "" - field.onAccepted: applyChanges() - field.placeholderText: qsTr("e.g. %1").arg(( - nameField.field.text || - accountInfo.display_name || - userId.substring(1) - )[0]) - toolTip.text: qsTr( "From any chat, start a message with specified alias " + "followed by a space to type and send as this " + @@ -215,12 +209,23 @@ HGridLayout { "To ignore the alias when typing, prepend it with a space." ) - Component.onCompleted: field.text = currentAlias - Layout.fillWidth: true Layout.maximumWidth: 480 - Keys.onEscapePressed: cancelChanges() + HTextField { + width: parent.width + error: aliasField.alreadyTakenBy !== "" + onAccepted: applyChanges() + placeholderText: qsTr("e.g. %1").arg(( + nameField.item.text || + accountInfo.display_name || + userId.substring(1) + )[0]) + + Component.onCompleted: text = aliasField.currentAlias + + Keys.onEscapePressed: cancelChanges() + } } } diff --git a/src/gui/Pages/AddAccount/SignIn.qml b/src/gui/Pages/AddAccount/SignIn.qml index a6d6bf27..98b187ed 100644 --- a/src/gui/Pages/AddAccount/SignIn.qml +++ b/src/gui/Pages/AddAccount/SignIn.qml @@ -8,7 +8,7 @@ HBox { id: signInBox clickButtonOnEnter: "apply" - onFocusChanged: idField.field.forceActiveFocus() + onFocusChanged: idField.item.forceActiveFocus() buttonModel: [ { @@ -31,8 +31,8 @@ HBox { errorMessage.text = "" const args = [ - idField.field.text.trim(), passwordField.field.text, - undefined, serverField.field.text.trim(), + idField.item.text.trim(), passwordField.item.text, + undefined, serverField.item.text.trim(), ] loginFuture = py.callCoro("login_client", args, userId => { @@ -86,8 +86,8 @@ HBox { property string signInWith: "username" readonly property bool canSignIn: - serverField.field.text.trim() && idField.field.text.trim() && - passwordField.field.text && ! serverField.field.error + serverField.item.text.trim() && idField.item.text.trim() && + passwordField.item.text && ! serverField.item.error Timer { @@ -128,7 +128,7 @@ HBox { } } - HLabeledTextField { + HLabeledItem { id: idField label.text: qsTr( signInWith === "email" ? "Email:" : @@ -137,27 +137,30 @@ HBox { ) Layout.fillWidth: true + + HTextField { + width: parent.width + } } - HLabeledTextField { + HLabeledItem { id: passwordField label.text: qsTr("Password:") - field.echoMode: HTextField.Password Layout.fillWidth: true + + HTextField { + width: parent.width + echoMode: HTextField.Password + } } - HLabeledTextField { + HLabeledItem { id: serverField label.text: qsTr("Homeserver:") - field.text: "https://matrix.org" - field.error: ! /.+:\/\/.+/.test(cleanText) Layout.fillWidth: true - - readonly property string cleanText: field.text.toLowerCase().trim() - // 2019-11-11 https://www.hello-matrix.net/public_servers.php readonly property var knownServers: [ "https://matrix.org", @@ -177,7 +180,15 @@ HBox { ] readonly property bool knownServerChosen: - knownServers.includes(cleanText) + knownServers.includes(item.cleanText) + + HTextField { + width: parent.width + text: "https://matrix.org" + error: ! /.+:\/\/.+/.test(cleanText) + + readonly property string cleanText: text.toLowerCase().trim() + } } HCheckBox { diff --git a/src/gui/Pages/AddChat/CreateRoom.qml b/src/gui/Pages/AddChat/CreateRoom.qml index 2b9d1a86..cf4001a0 100644 --- a/src/gui/Pages/AddChat/CreateRoom.qml +++ b/src/gui/Pages/AddChat/CreateRoom.qml @@ -8,7 +8,7 @@ HBox { id: addChatBox clickButtonOnEnter: "apply" - onFocusChanged: nameField.field.forceActiveFocus() + onFocusChanged: nameField.item.forceActiveFocus() buttonModel: [ { name: "apply", text: qsTr("Create"), iconName: "room-create" }, @@ -21,8 +21,8 @@ HBox { errorMessage.text = "" const args = [ - nameField.field.text, - topicField.field.text, + nameField.item.text, + topicField.item.text, publicCheckBox.checked, encryptCheckBox.checked, ! blockOtherServersCheckBox.checked, @@ -40,8 +40,8 @@ HBox { }, cancel: button => { - nameField.field.text = "" - topicField.field.text = "" + nameField.item.text = "" + topicField.item.text = "" publicCheckBox.checked = false encryptCheckBox.checked = false blockOtherServersCheckBox.checked = false @@ -57,7 +57,7 @@ HBox { HRoomAvatar { id: avatar roomId: "" - displayName: nameField.field.text + displayName: nameField.item.text Layout.alignment: Qt.AlignCenter Layout.preferredWidth: 128 @@ -66,27 +66,35 @@ HBox { CurrentUserAvatar { anchors.fill: parent z: 10 - opacity: nameField.field.text ? 0 : 1 + opacity: nameField.item.text ? 0 : 1 visible: opacity > 0 Behavior on opacity { HNumberAnimation {} } } } - HLabeledTextField { + HLabeledItem { id: nameField label.text: qsTr("Name:") - field.maximumLength: 255 Layout.fillWidth: true + + HTextField { + width: parent.width + maximumLength: 255 + } } - HLabeledTextField { + HLabeledItem { id: topicField label.text: qsTr("Topic:") - field.placeholderText: qsTr("This room is about...") Layout.fillWidth: true + + HTextField { + width: parent.width + placeholderText: qsTr("This room is about...") + } } HCheckBox { diff --git a/src/gui/Pages/AddChat/DirectChat.qml b/src/gui/Pages/AddChat/DirectChat.qml index 11ee2e1d..078fe3cc 100644 --- a/src/gui/Pages/AddChat/DirectChat.qml +++ b/src/gui/Pages/AddChat/DirectChat.qml @@ -8,14 +8,14 @@ HBox { id: addChatBox clickButtonOnEnter: "apply" - onFocusChanged: userField.field.forceActiveFocus() + onFocusChanged: userField.item.forceActiveFocus() buttonModel: [ { name: "apply", text: qsTr("Start chat"), iconName: "start-direct-chat", - enabled: Boolean(userField.field.text.trim()) + enabled: Boolean(userField.item.text.trim()) }, { name: "cancel", text: qsTr("Cancel"), iconName: "cancel" }, ] @@ -25,7 +25,7 @@ HBox { button.loading = true errorMessage.text = "" - const args = [userField.field.text.trim(), encryptCheckBox.checked] + const args = [userField.item.text.trim(), encryptCheckBox.checked] py.callClientCoro(userId, "new_direct_chat", args, roomId => { button.loading = false @@ -52,8 +52,8 @@ HBox { }, cancel: button => { - userField.field.text = "" - errorMessage.text = "" + userField.item.text = "" + errorMessage.text = "" pageLoader.showPrevious() } }) @@ -68,13 +68,17 @@ HBox { Layout.preferredHeight: Layout.preferredWidth } - HLabeledTextField { + HLabeledItem { id: userField label.text: qsTr("Peer user ID:") - field.placeholderText: qsTr("@example:matrix.org") - field.error: Boolean(errorMessage.text) Layout.fillWidth: true + + HTextField { + width: parent.width + placeholderText: qsTr("@example:matrix.org") + error: Boolean(errorMessage.text) + } } EncryptCheckBox { diff --git a/src/gui/Pages/AddChat/JoinRoom.qml b/src/gui/Pages/AddChat/JoinRoom.qml index b6d5bab6..2abb29c0 100644 --- a/src/gui/Pages/AddChat/JoinRoom.qml +++ b/src/gui/Pages/AddChat/JoinRoom.qml @@ -8,14 +8,14 @@ HBox { id: addChatBox clickButtonOnEnter: "apply" - onFocusChanged: roomField.field.forceActiveFocus() + onFocusChanged: roomField.item.forceActiveFocus() buttonModel: [ { name: "apply", text: qsTr("Join"), iconName: "room-join", - enabled: Boolean(roomField.field.text.trim()), + enabled: Boolean(roomField.item.text.trim()), }, { name: "cancel", text: qsTr("Cancel"), iconName: "cancel" }, ] @@ -25,7 +25,7 @@ HBox { button.loading = true errorMessage.text = "" - const args = [roomField.field.text.trim()] + const args = [roomField.item.text.trim()] py.callClientCoro(userId, "room_join", args, roomId => { button.loading = false @@ -51,8 +51,8 @@ HBox { }, cancel: button => { - roomField.field.text = "" - errorMessage.text = "" + roomField.item.text = "" + errorMessage.text = "" pageLoader.showPrevious() } }) @@ -67,13 +67,17 @@ HBox { Layout.preferredHeight: Layout.preferredWidth } - HLabeledTextField { + HLabeledItem { id: roomField label.text: qsTr("Alias, URL or room ID:") - field.placeholderText: qsTr("#example:matrix.org") - field.error: Boolean(errorMessage.text) Layout.fillWidth: true + + HTextField { + width: parent.width + placeholderText: qsTr("#example:matrix.org") + error: Boolean(errorMessage.text) + } } HLabel { diff --git a/src/gui/Pages/Chat/RoomPane/SettingsView.qml b/src/gui/Pages/Chat/RoomPane/SettingsView.qml index 01a6c82e..c4b6cf57 100644 --- a/src/gui/Pages/Chat/RoomPane/SettingsView.qml +++ b/src/gui/Pages/Chat/RoomPane/SettingsView.qml @@ -37,8 +37,8 @@ HBox { saveFuture = null } - nameField.field.reset() - topicField.field.reset() + nameField.item.reset() + topicField.item.reset() encryptCheckBox.reset() requireInviteCheckbox.reset() forbidGuestsCheckBox.reset() @@ -49,11 +49,11 @@ HBox { property var saveFuture: null readonly property bool anyChange: - nameField.field.changed || topicField.field.changed || + nameField.item.changed || topicField.item.changed || encryptCheckBox.changed || requireInviteCheckbox.changed || forbidGuestsCheckBox.changed - readonly property Item keybindFocusItem: nameField.field + readonly property Item keybindFocusItem: nameField.item HRoomAvatar { @@ -69,26 +69,33 @@ HBox { Layout.alignment: Qt.AlignCenter } - HLabeledTextField { + HLabeledItem { id: nameField label.text: qsTr("Name:") - field.maximumLength: 255 - field.defaultText: chat.roomInfo.given_name - field.enabled: chat.roomInfo.can_set_name Layout.fillWidth: true - Component.onCompleted: field.forceActiveFocus() + HTextField { + width: parent.width + maximumLength: 255 + defaultText: chat.roomInfo.given_name + enabled: chat.roomInfo.can_set_name + Component.onCompleted: forceActiveFocus() + } } - HLabeledTextField { + HLabeledItem { id: topicField label.text: qsTr("Topic:") - field.placeholderText: qsTr("This room is about...") - field.defaultText: chat.roomInfo.plain_topic - field.enabled: chat.roomInfo.can_set_topic Layout.fillWidth: true + + HTextField { + width: parent.width + placeholderText: qsTr("This room is about...") + defaultText: chat.roomInfo.plain_topic + enabled: chat.roomInfo.can_set_topic + } } HCheckBox { diff --git a/src/gui/Popups/RedactPopup.qml b/src/gui/Popups/RedactPopup.qml index 9b6de03d..96090438 100644 --- a/src/gui/Popups/RedactPopup.qml +++ b/src/gui/Popups/RedactPopup.qml @@ -23,7 +23,7 @@ BoxPopup { okText: qsTr("Remove") // box.focusButton: "ok" - onOpened: reasonField.field.forceActiveFocus() + onOpened: reasonField.item.forceActiveFocus() onOk: { const idsForSender = {} // {senderId: [event.id, ...]} @@ -38,7 +38,7 @@ BoxPopup { py.callClientCoro( mainUI.accountIds.includes(senderId) ? senderId : preferUserId, "room_mass_redact", - [roomId, reasonField.field.text, ...eventClientIds] + [roomId, reasonField.item.text, ...eventClientIds] ) } @@ -51,10 +51,14 @@ BoxPopup { property bool isLast: false - HLabeledTextField { + HLabeledItem { id: reasonField label.text: qsTr("Optional reason:") Layout.fillWidth: true + + HTextField { + width: parent.width + } } } diff --git a/src/gui/Popups/RemoveMemberPopup.qml b/src/gui/Popups/RemoveMemberPopup.qml index 1297584a..c13ed83d 100644 --- a/src/gui/Popups/RemoveMemberPopup.qml +++ b/src/gui/Popups/RemoveMemberPopup.qml @@ -24,12 +24,12 @@ BoxPopup { qsTr("Ban") - onOpened: reasonField.field.forceActiveFocus() + onOpened: reasonField.item.forceActiveFocus() onOk: py.callClientCoro( userId, operation === RemoveMemberPopup.Operation.Ban ? "room_ban" : "room_kick", - [roomId, targetUserId, reasonField.field.text || null], + [roomId, targetUserId, reasonField.item.text || null], ) @@ -45,10 +45,14 @@ BoxPopup { utils.coloredNameHtml(targetDisplayName, targetUserId) - HLabeledTextField { + HLabeledItem { id: reasonField label.text: qsTr("Optional reason:") Layout.fillWidth: true + + HTextField { + width: parent.width + } } }