Update password entry fields

This commit is contained in:
Michael Zanetti 2019-11-22 17:31:46 +01:00
parent 1f40b7f963
commit ff232f2e4b
4 changed files with 74 additions and 66 deletions

View File

@ -180,23 +180,10 @@ Page {
} }
RowLayout { RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
TextField { PasswordTextField {
id: passwordTextField id: passwordTextField
Layout.fillWidth: true Layout.fillWidth: true
echoMode: hiddenPassword ? TextInput.Password : TextInput.Normal signup: false
property bool hiddenPassword: true
}
ColorIcon {
Layout.preferredHeight: app.iconSize
Layout.preferredWidth: app.iconSize
name: "../images/eye.svg"
color: passwordTextField.hiddenPassword ? keyColor : app.accentColor
MouseArea {
anchors.fill: parent
onClicked: {
passwordTextField.hiddenPassword = !passwordTextField.hiddenPassword
}
}
} }
} }
@ -208,7 +195,7 @@ Page {
enabled: usernameTextField.acceptableInput enabled: usernameTextField.acceptableInput
onClicked: { onClicked: {
busyOverlay.shown = true busyOverlay.shown = true
AWSClient.login(usernameTextField.text, passwordTextField.text); AWSClient.login(usernameTextField.text, passwordTextField.password);
} }
} }
@ -338,13 +325,18 @@ Page {
id: passwordTextField id: passwordTextField
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
Layout.fillWidth: true Layout.fillWidth: true
minPasswordLength: 8
requireLowerCaseLetter: true
requireUpperCaseLetter: true
requireNumber: true
requireSpecialChar: false
} }
Button { Button {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.topMargin: app.margins Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.topMargin: app.margins
text: qsTr("Sign up") text: qsTr("Sign up")
enabled: usernameTextField.acceptableInput && passwordTextField.isValidPassword enabled: usernameTextField.acceptableInput && passwordTextField.isValid
onClicked: { onClicked: {
busyOverlay.shown = true; busyOverlay.shown = true;
AWSClient.signup(usernameTextField.text, passwordTextField.password) AWSClient.signup(usernameTextField.text, passwordTextField.password)
@ -576,13 +568,18 @@ Page {
PasswordTextField { PasswordTextField {
id: passwordTextField id: passwordTextField
minPasswordLength: 8
requireLowerCaseLetter: true
requireUpperCaseLetter: true
requireNumber: true
requireSpecialChar: false
Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
} }
Button { Button {
Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("Reset password") text: qsTr("Reset password")
enabled: passwordTextField.isValidPassword && codeTextField.text.length > 0 enabled: passwordTextField.isValid && codeTextField.text.length > 0
onClicked: { onClicked: {
busyOverlay.shown = true busyOverlay.shown = true
AWSClient.confirmForgotPassword(confirmResetPasswordPage.email, codeTextField.text, passwordTextField.password) AWSClient.confirmForgotPassword(confirmResetPasswordPage.email, codeTextField.text, passwordTextField.password)

View File

@ -5,18 +5,31 @@ import QtQuick.Layouts 1.2
ColumnLayout { ColumnLayout {
id: root id: root
property int minPasswordLength: 12
property bool signup: true property bool signup: true
// Only used when signup is true
property int minPasswordLength: 12
property bool requireSpecialChar: true
property bool requireNumber: true
property bool requireUpperCaseLetter: true
property bool requireLowerCaseLetter: true
readonly property alias password: passwordTextField.text readonly property alias password: passwordTextField.text
readonly property bool isValidPassword: isLongEnough && hasLower && hasUpper && hasNumbers && hasSpecialChar && (confirmationMatches || !signup) readonly property bool isValidPassword:
isLongEnough &&
(hasLower || !requireLowerCaseLetter) &&
(hasUpper || !requireUpperCaseLetter) &&
(hasNumbers || !requireNumber) &&
(hasSpecialChar || !requireSpecialChar)
readonly property bool isValid: !signup || (isValidPassword && confirmationMatches)
readonly property bool isLongEnough: passwordTextField.text.length >= minPasswordLength readonly property bool isLongEnough: passwordTextField.text.length >= minPasswordLength
readonly property bool hasLower: passwordTextField.text.search(/[a-z]/) >= 0 readonly property bool hasLower: passwordTextField.text.search(/[a-z]/) >= 0
readonly property bool hasUpper: passwordTextField.text.search(/[A-Z/]/) >= 0 readonly property bool hasUpper: passwordTextField.text.search(/[A-Z/]/) >= 0
readonly property bool hasNumbers: passwordTextField.text.search(/[0-9]/) >= 0 readonly property bool hasNumbers: passwordTextField.text.search(/[0-9]/) >= 0
readonly property bool hasSpecialChar: passwordTextField.text.search(/[\.,\*!"$%&/()=?`'+#'¡^°²³¼\[\]|{}\\@]/) >= 0 readonly property bool hasSpecialChar: passwordTextField.text.search(/(?=.*?[$*.\[\]{}()?\-'"!@#%&/\\,><':;|_~`^])/) >= 0
readonly property bool confirmationMatches: passwordTextField.text === confirmationPasswordTextField.text readonly property bool confirmationMatches: passwordTextField.text === confirmationPasswordTextField.text
property bool hiddenPassword: true property bool hiddenPassword: true
@ -29,6 +42,41 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal
placeholderText: root.signup ? qsTr("Pick a password") : "" placeholderText: root.signup ? qsTr("Pick a password") : ""
ToolTip.visible: root.signup && focus && !root.isValidPassword
ToolTip.delay: 1000
ToolTip.onVisibleChanged: print("Tooltip visible changed:", ToolTip.visible, focus, root.isValidPassword)
ToolTip.text: {
var texts = []
var checks = []
texts.push(qsTr("Minimum %1 characters").arg(root.minPasswordLength))
checks.push(root.isLongEnough)
if (root.requireLowerCaseLetter) {
texts.push(qsTr("Lowercase letters"))
checks.push(root.hasLower)
}
if (root.requireUpperCaseLetter) {
texts.push(qsTr("Uppercase letters"))
checks.push(root.hasUpper)
}
if (root.requireNumber) {
texts.push(qsTr("Numbers"))
checks.push(root.hasNumbers)
}
if (root.requireSpecialChar) {
texts.push(qsTr("Special characters"))
checks.push(root.hasSpecialChar)
}
var ret = []
for (var i = 0; i < texts.length; i++) {
var entry = "<font color=\"%1\">• ".arg(checks[i] ? app.foregroundColor : app.accentColor)
entry += texts[i]
entry += "</font>"
ret.push(entry)
}
return ret.join("<br>")
}
} }
ColorIcon { ColorIcon {
Layout.preferredHeight: app.iconSize Layout.preferredHeight: app.iconSize
@ -44,24 +92,6 @@ ColumnLayout {
} }
} }
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
visible: root.signup
// TRANSLATORS: %1 will be replaced with the normal text color, %2 the color for the length check
text: qsTr("<font color=\"%1\">The password needs to be </font><font color=\"%2\">at least %3 characters long</font><font color=\"%1\">, contain </font><font color=\"%4\">lowercase</font><font color=\"%1\">, </font><font color=\"%5\">uppercase</font><font color=\"%1\"> letters as well as </font><font color=\"%6\">numbers</font><font color=\"%1\"> and </font><font color=\"%7\">special characters</font><font color=\"%1\">.</font>")
.arg(app.accentColor)
.arg(!root.isLongEnough ? "red" : app.accentColor)
.arg(root.minPasswordLength)
.arg(!root.hasLower ? "red" : app.accentColor)
.arg(!root.hasUpper ? "red" : app.accentColor)
.arg(!root.hasNumbers ? "red" : app.accentColor)
.arg(!root.hasSpecialChar ? "red" : app.accentColor)
font.pixelSize: app.smallFont
}
RowLayout { RowLayout {
visible: root.signup visible: root.signup
@ -71,28 +101,5 @@ ColumnLayout {
echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal
placeholderText: qsTr("Confirm password") placeholderText: qsTr("Confirm password")
} }
ColorIcon {
Layout.preferredHeight: app.iconSize
Layout.preferredWidth: app.iconSize
name: "../images/eye.svg"
color: root.hiddenPassword ? keyColor : app.accentColor
MouseArea {
anchors.fill: parent
onClicked: {
root.hiddenPassword = !root.hiddenPassword
}
}
}
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
visible: root.signup
text: root.confirmationMatches ? qsTr("<font color=\"%1\">The passwords match.</font>").arg(app.accentColor) : qsTr("<font color=\"%1\">The passwords </font><font color=\"%2\">do not</font><font color=\"%1\"> match.</font>").arg(app.accentColor).arg("red")
font.pixelSize: app.smallFont
} }
} }

View File

@ -104,6 +104,10 @@ Page {
id: passwordTextField id: passwordTextField
Layout.fillWidth: true Layout.fillWidth: true
minPasswordLength: 8 minPasswordLength: 8
requireLowerCaseLetter: true
requireUpperCaseLetter: true
requireNumber: true
requireSpecialChar: false
signup: engine.jsonRpcClient.initialSetupRequired signup: engine.jsonRpcClient.initialSetupRequired
} }
} }
@ -112,7 +116,7 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.bottomMargin: app.margins Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.bottomMargin: app.margins
text: qsTr("OK") text: qsTr("OK")
enabled: passwordTextField.isValidPassword enabled: passwordTextField.isValid
onClicked: { onClicked: {
if (engine.jsonRpcClient.initialSetupRequired) { if (engine.jsonRpcClient.initialSetupRequired) {
print("create user") print("create user")

View File

@ -440,11 +440,11 @@ Page {
visible: pairingPage.setupMethod === "SetupMethodUserAndPassword" visible: pairingPage.setupMethod === "SetupMethodUserAndPassword"
} }
TextField { PasswordTextField {
id: pinTextField id: pinTextField
Layout.fillWidth: true Layout.fillWidth: true
visible: pairingPage.setupMethod === "SetupMethodDisplayPin" || pairingPage.setupMethod === "SetupMethodUserAndPassword" visible: pairingPage.setupMethod === "SetupMethodDisplayPin" || pairingPage.setupMethod === "SetupMethodUserAndPassword"
echoMode: TextField.Password signup: false
} }