Improve login page

This commit is contained in:
Michael Zanetti 2019-06-20 22:35:19 +02:00
parent e056c79c0b
commit 354a2ae9fe
5 changed files with 28 additions and 41 deletions

View File

@ -218,6 +218,7 @@ int JsonRpcClient::authenticate(const QString &username, const QString &password
params.insert("username", username); params.insert("username", username);
params.insert("password", password); params.insert("password", password);
params.insert("deviceName", deviceName); params.insert("deviceName", deviceName);
qDebug() << "Authenticating:" << username << password << deviceName;
JsonRpcReply* reply = createReply("JSONRPC.Authenticate", params, this, "processAuthenticate"); JsonRpcReply* reply = createReply("JSONRPC.Authenticate", params, this, "processAuthenticate");
m_replies.insert(reply->commandId(), reply); m_replies.insert(reply->commandId(), reply);
m_connection->sendData(QJsonDocument::fromVariant(reply->requestMap()).toJson()); m_connection->sendData(QJsonDocument::fromVariant(reply->requestMap()).toJson());
@ -262,7 +263,7 @@ void JsonRpcClient::processAuthenticate(const QVariantMap &data)
setNotificationsEnabled(true); setNotificationsEnabled(true);
} else { } else {
qWarning() << "Authentication failed"; qWarning() << "Authentication failed" << data;
emit authenticationFailed(); emit authenticationFailed();
} }
} }

View File

@ -41,7 +41,7 @@
<file>ui/components/MainPageTile.qml</file> <file>ui/components/MainPageTile.qml</file>
<file>ui/components/BusyOverlay.qml</file> <file>ui/components/BusyOverlay.qml</file>
<file>ui/components/SwipeDelegateGroup.qml</file> <file>ui/components/SwipeDelegateGroup.qml</file>
<file>ui/components/AWSPasswordTextField.qml</file> <file>ui/components/PasswordTextField.qml</file>
<file>ui/components/BrightnessSlider.qml</file> <file>ui/components/BrightnessSlider.qml</file>
<file>ui/components/SegmentedImage.qml</file> <file>ui/components/SegmentedImage.qml</file>
<file>ui/components/SegmentRenderer.qml</file> <file>ui/components/SegmentRenderer.qml</file>

View File

@ -324,7 +324,7 @@ Page {
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("Password") text: qsTr("Password")
} }
AWSPasswordTextField { PasswordTextField {
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
@ -564,7 +564,7 @@ Page {
text: qsTr("Pick a new password:") text: qsTr("Pick a new password:")
} }
AWSPasswordTextField { PasswordTextField {
id: passwordTextField id: passwordTextField
Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins Layout.fillWidth: true; Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
} }

View File

@ -5,26 +5,30 @@ import QtQuick.Layouts 1.2
ColumnLayout { ColumnLayout {
id: root id: root
property int minPasswordLength: 12
property bool signup: true
readonly property alias password: passwordTextField.text readonly property alias password: passwordTextField.text
readonly property bool isValidPassword: isLongEnough && hasLower && hasUpper && hasNumbers && hasSpecialChar && confirmationMatches readonly property bool isValidPassword: isLongEnough && hasLower && hasUpper && hasNumbers && hasSpecialChar && (confirmationMatches || !signup)
readonly property bool isLongEnough: passwordTextField.text.length >= 12 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
RowLayout { RowLayout {
Layout.fillWidth: true
TextField { TextField {
id: passwordTextField id: passwordTextField
Layout.fillWidth: true Layout.fillWidth: true
echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal echoMode: root.hiddenPassword ? TextInput.Password : TextInput.Normal
placeholderText: qsTr("Pick a password") placeholderText: root.signup ? qsTr("Pick a password") : ""
} }
ColorIcon { ColorIcon {
Layout.preferredHeight: app.iconSize Layout.preferredHeight: app.iconSize
@ -44,11 +48,13 @@ ColumnLayout {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
visible: root.signup
// TRANSLATORS: %1 will be replaced with the normal text color, %2 the color for the length check // 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 12 characters long</font><font color=\"%1\">, contain </font><font color=\"%3\">lowercase</font><font color=\"%1\">, </font><font color=\"%4\">uppercase</font><font color=\"%1\"> letters as well as </font><font color=\"%5\">numbers</font><font color=\"%1\"> and </font><font color=\"%6\">special characters</font><font color=\"%1\">.</font>") 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(app.accentColor)
.arg(!root.isLongEnough ? "red" : app.accentColor) .arg(!root.isLongEnough ? "red" : app.accentColor)
.arg(root.minPasswordLength)
.arg(!root.hasLower ? "red" : app.accentColor) .arg(!root.hasLower ? "red" : app.accentColor)
.arg(!root.hasUpper ? "red" : app.accentColor) .arg(!root.hasUpper ? "red" : app.accentColor)
.arg(!root.hasNumbers ? "red" : app.accentColor) .arg(!root.hasNumbers ? "red" : app.accentColor)
@ -57,6 +63,7 @@ ColumnLayout {
} }
RowLayout { RowLayout {
visible: root.signup
TextField { TextField {
id: confirmationPasswordTextField id: confirmationPasswordTextField
@ -83,6 +90,7 @@ ColumnLayout {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap 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") 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 font.pixelSize: app.smallFont

View File

@ -23,7 +23,7 @@ Page {
popup.open(); popup.open();
} }
onCreateUserSucceeded: { onCreateUserSucceeded: {
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app"); engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.password, "nymea-app");
} }
onCreateUserFailed: { onCreateUserFailed: {
@ -82,11 +82,13 @@ Page {
GridLayout { GridLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
columns: app.width > 400 ? 2 : 1 columns: app.width > 500 ? 2 : 1
columnSpacing: app.margins
Label { Label {
text: qsTr("Your e-mail address:") text: qsTr("Your e-mail address:")
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumWidth: implicitWidth
} }
TextField { TextField {
id: usernameTextField id: usernameTextField
@ -98,50 +100,26 @@ Page {
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Password:") text: qsTr("Password:")
} }
TextField { PasswordTextField {
id: passwordTextField id: passwordTextField
Layout.fillWidth: true Layout.fillWidth: true
echoMode: TextInput.Password minPasswordLength: 8
signup: engine.jsonRpcClient.initialSetupRequired
} }
Label {
visible: engine.jsonRpcClient.initialSetupRequired
Layout.fillWidth: true
text: qsTr("Confirm password:")
}
TextField {
id: confirmPasswordTextField
visible: engine.jsonRpcClient.initialSetupRequired
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
visible: engine.jsonRpcClient.initialSetupRequired
opacity: (passwordTextField.text.length > 0 && passwordTextField.text.length < 8) || passwordTextField.text != confirmPasswordTextField.text ? 1 : 0
text: passwordTextField.text.length < 8 ? qsTr("This password isn't long enought to be secure, add some more characters please.")
: qsTr("The passwords don't match.")
wrapMode: Text.WordWrap
color: app.accentColor
font.pixelSize: app.smallFont
} }
Button { Button {
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: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8 enabled: passwordTextField.isValidPassword
&& (!engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: { onClicked: {
if (engine.jsonRpcClient.initialSetupRequired) { if (engine.jsonRpcClient.initialSetupRequired) {
print("create user") print("create user")
engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.text); engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.password);
} else { } else {
print("authenticate", usernameTextField.text, passwordTextField.text, "nymea-app") print("authenticate", usernameTextField.text, passwordTextField.text, "nymea-app")
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app"); engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.password, "nymea-app");
} }
} }
} }