workaround for Qt bug on Password echo mode in textfields

This commit is contained in:
gaelle 2025-02-06 14:06:50 +01:00
parent 711feabcf0
commit de0728651e

View file

@ -2,122 +2,131 @@ import QtQuick
import QtQuick.Controls.Basic as Control import QtQuick.Controls.Basic as Control
import QtQuick.Layouts import QtQuick.Layouts
import Linphone import Linphone
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
Control.TextField { Control.TextField {
id: mainItem id: mainItem
property var customWidth property var customWidth
width: (customWidth ? customWidth - 1 : 360) * DefaultStyle.dp width: (customWidth ? customWidth - 1 : 360) * DefaultStyle.dp
height: 49 * DefaultStyle.dp height: 49 * DefaultStyle.dp
leftPadding: 15 * DefaultStyle.dp leftPadding: 15 * DefaultStyle.dp
rightPadding: eyeButton.visible ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin : 15 * DefaultStyle.dp rightPadding: eyeButton.visible
echoMode: (hidden && !eyeButton.checked) ? TextInput.Password : TextInput.Normal ? 5 * DefaultStyle.dp + eyeButton.width + eyeButton.rightMargin
verticalAlignment: TextInput.AlignVCenter : 15 * DefaultStyle.dp
color: isError ? DefaultStyle.danger_500main : DefaultStyle.main2_600 echoMode: (hidden && !eyeButton.checked) ? TextInput.Password : TextInput.Normal
placeholderTextColor: DefaultStyle.placeholders
font {
family: DefaultStyle.defaultFont
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
selectByMouse: true
activeFocusOnTab: true
KeyNavigation.right: eyeButton
text: initialText
property bool controlIsDown: false // Workaround for Windows slowness when first typing a password
property bool hidden: false // due to Qt not initializing the Password echo mode before the first letter is typed
property bool isError: false Component.onCompleted: {
property bool backgroundVisible: true text = "workaround"
property color backgroundColor: DefaultStyle.grey_100 resetText()
property color disabledBackgroundColor: DefaultStyle.grey_200 }
property color backgroundBorderColor: DefaultStyle.grey_200
property string initialText
property int pixelSize: 14 * DefaultStyle.dp
property int weight: 400 * DefaultStyle.dp
// fill propertyName and propertyOwner to check text validity verticalAlignment: TextInput.AlignVCenter
property string propertyName color: isError ? DefaultStyle.danger_500main : DefaultStyle.main2_600
property var propertyOwner placeholderTextColor: DefaultStyle.placeholders
property var propertyOwnerGui font {
property var initialReading: true family: DefaultStyle.defaultFont
property var isValid: function(text) { pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
selectByMouse: true
activeFocusOnTab: true
KeyNavigation.right: eyeButton
text: initialText
property bool controlIsDown: false
property bool hidden: false
property bool isError: false
property bool backgroundVisible: true
property color backgroundColor: DefaultStyle.grey_100
property color disabledBackgroundColor: DefaultStyle.grey_200
property color backgroundBorderColor: DefaultStyle.grey_200
property string initialText
property int pixelSize: 14 * DefaultStyle.dp
property int weight: 400 * DefaultStyle.dp
// fill propertyName and propertyOwner to check text validity
property string propertyName
property var propertyOwner
property var propertyOwnerGui
property var initialReading: true
property var isValid: function (text) {
return true return true
} }
property bool toValidate: false property bool toValidate: false
property int idleTimeOut: 200 property int idleTimeOut: 200
property bool empty: propertyOwnerGui ? mainItem.propertyOwnerGui.core != undefined && mainItem.propertyOwnerGui.core[mainItem.propertyName]?.length == 0 property bool empty: propertyOwnerGui
: mainItem.propertyOwner != undefined && mainItem.propertyOwner[mainItem.propertyName]?.length == 0 ? mainItem.propertyOwnerGui.core != undefined && mainItem.propertyOwnerGui.core[mainItem.propertyName]?.length == 0
property bool canBeEmpty: true : mainItem.propertyOwner != undefined && mainItem.propertyOwner[mainItem.propertyName]?.length == 0
property bool canBeEmpty: true
signal validationChecked(bool valid) signal validationChecked(bool valid)
function resetText() { function resetText() {
text = initialText text = initialText
} }
signal enterPressed() signal enterPressed
onAccepted: {// No need to process changing focus because of TextEdited callback. onAccepted: {
idleTimer.stop() // No need to process changing focus because of TextEdited callback.
updateText() idleTimer.stop()
} updateText()
onTextEdited: { }
if(mainItem.toValidate) { onTextEdited: {
idleTimer.restart() if (mainItem.toValidate) {
} idleTimer.restart()
} }
function updateText() { }
mainItem.empty = text.length == 0 function updateText() {
if (initialReading) { mainItem.empty = text.length == 0
initialReading = false if (initialReading) {
} initialReading = false
if (mainItem.empty && !mainItem.canBeEmpty) { }
mainItem.validationChecked(false) if (mainItem.empty && !mainItem.canBeEmpty) {
return mainItem.validationChecked(false)
} return
if (mainItem.propertyName && isValid(text)) { }
if(mainItem.propertyOwnerGui){ if (mainItem.propertyName && isValid(text)) {
if (mainItem.propertyOwnerGui.core[mainItem.propertyName] != text) if (mainItem.propertyOwnerGui) {
mainItem.propertyOwnerGui.core[mainItem.propertyName] = text if (mainItem.propertyOwnerGui.core[mainItem.propertyName] != text)
}else{ mainItem.propertyOwnerGui.core[mainItem.propertyName] = text
if (mainItem.propertyOwner[mainItem.propertyName] != text) } else {
mainItem.propertyOwner[mainItem.propertyName] = text if (mainItem.propertyOwner[mainItem.propertyName] != text)
} mainItem.propertyOwner[mainItem.propertyName] = text
mainItem.validationChecked(true) }
} else mainItem.validationChecked(false) mainItem.validationChecked(true)
} } else
// Validation textfield functions mainItem.validationChecked(false)
Timer { }
id: idleTimer // Validation textfield functions
running: false Timer {
interval: mainItem.idleTimeOut id: idleTimer
repeat: false running: false
onTriggered: { interval: mainItem.idleTimeOut
mainItem.accepted() repeat: false
} onTriggered: {
} mainItem.accepted()
}
}
background: Rectangle { background: Rectangle {
id: inputBackground id: inputBackground
visible: mainItem.backgroundVisible visible: mainItem.backgroundVisible
anchors.fill: parent anchors.fill: parent
radius: 79 * DefaultStyle.dp radius: 79 * DefaultStyle.dp
color: mainItem.enabled ? mainItem.backgroundColor : mainItem.disabledBackgroundColor color: mainItem.enabled ? mainItem.backgroundColor : mainItem.disabledBackgroundColor
border.color: mainItem.isError border.color: mainItem.isError ? DefaultStyle.danger_500main : mainItem.activeFocus ? DefaultStyle.main1_500_main : mainItem.backgroundBorderColor
? DefaultStyle.danger_500main }
: mainItem.activeFocus
? DefaultStyle.main1_500_main
: mainItem.backgroundBorderColor
}
cursorDelegate: Rectangle { cursorDelegate: Rectangle {
id: cursor id: cursor
color: DefaultStyle.main1_500_main color: DefaultStyle.main1_500_main
width: 1 * DefaultStyle.dp width: 1 * DefaultStyle.dp
anchors.verticalCenter: mainItem.verticalCenter anchors.verticalCenter: mainItem.verticalCenter
SequentialAnimation { SequentialAnimation {
loops: Animation.Infinite loops: Animation.Infinite
running: mainItem.cursorVisible running: mainItem.cursorVisible
@ -145,36 +154,38 @@ Control.TextField {
cursor.visible = false cursor.visible = false
} }
} }
} }
Keys.onPressed: (event) => { Keys.onPressed: event => {
if (event.key == Qt.Key_Control) mainItem.controlIsDown = true if (event.key == Qt.Key_Control)
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { mainItem.controlIsDown = true
enterPressed() if (event.key === Qt.Key_Enter
if (mainItem.controlIsDown) { || event.key === Qt.Key_Return) {
enterPressed()
if (mainItem.controlIsDown) {
} }
} }
} }
Keys.onReleased: (event) => { Keys.onReleased: event => {
if (event.jey == Qt.Key_Control) mainItem.controlIsDown = false if (event.jey == Qt.Key_Control)
} mainItem.controlIsDown = false
}
Button { Button {
id: eyeButton id: eyeButton
KeyNavigation.left: mainItem KeyNavigation.left: mainItem
property int rightMargin: 15 * DefaultStyle.dp property int rightMargin: 15 * DefaultStyle.dp
z: 1 z: 1
visible: mainItem.hidden visible: mainItem.hidden
checkable: true checkable: true
style: ButtonStyle.noBackground style: ButtonStyle.noBackground
icon.source: eyeButton.checked ? AppIcons.eyeShow : AppIcons.eyeHide icon.source: eyeButton.checked ? AppIcons.eyeShow : AppIcons.eyeHide
width: 20 * DefaultStyle.dp width: 20 * DefaultStyle.dp
height: 20 * DefaultStyle.dp height: 20 * DefaultStyle.dp
icon.width: width icon.width: width
icon.height: height icon.height: height
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: rightMargin anchors.rightMargin: rightMargin
} }
} }