HLabeledTextField → extensible HLabeledItem
This commit is contained in:
parent
fdaf7089ab
commit
e676473f82
@ -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).
|
||||
|
8
TODO.md
8
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
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user