HLabeledTextField → extensible HLabeledItem

This commit is contained in:
miruka 2020-06-02 20:14:55 -04:00
parent fdaf7089ab
commit e676473f82
11 changed files with 158 additions and 102 deletions

View File

@ -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).

View File

@ -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

View File

@ -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
}

View File

@ -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,14 +209,25 @@ HGridLayout {
"To ignore the alias when typing, prepend it with a space."
)
Component.onCompleted: field.text = currentAlias
Layout.fillWidth: true
Layout.maximumWidth: 480
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()
}
}
}
HRowLayout {
Layout.alignment: Qt.AlignBottom

View File

@ -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 {

View File

@ -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 {

View File

@ -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,7 +52,7 @@ HBox {
},
cancel: button => {
userField.field.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 {

View File

@ -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,7 +51,7 @@ HBox {
},
cancel: button => {
roomField.field.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 {

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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
}
}
}