Improve setup wizard

This commit is contained in:
Michael Zanetti 2019-05-22 13:41:38 +02:00
parent 2ad82d80a6
commit 424547333f
10 changed files with 240 additions and 174 deletions

View File

@ -271,6 +271,7 @@ void JsonRpcClient::processCreateUser(const QVariantMap &data)
{
qDebug() << "create user response:" << data;
if (data.value("status").toString() == "success" && data.value("params").toMap().value("error").toString() == "UserErrorNoError") {
emit createUserSucceeded();
m_initialSetupRequired = false;
emit initialSetupRequiredChanged();
} else {

View File

@ -93,6 +93,7 @@ signals:
void invalidProtocolVersion(const QString &actualVersion, const QString &minimumVersion);
void authenticationFailed();
void pushButtonAuthFailed();
void createUserSucceeded();
void createUserFailed(const QString &error);
void cloudConnectionStateChanged();

View File

@ -2,7 +2,7 @@
<qresource prefix="/">
<file>ui/Nymea.qml</file>
<file>ui/SettingsPage.qml</file>
<file>ui/LoginPage.qml</file>
<file>ui/connection/LoginPage.qml</file>
<file>ui/MagicPage.qml</file>
<file>ui/PushButtonAuthPage.qml</file>
<file>ui/KeyboardLoader.qml</file>
@ -182,5 +182,6 @@
<file>ui/magic/SelectStatePage.qml</file>
<file>ui/system/SystemUpdatePage.qml</file>
<file>ui/components/UpdateRunningOverlay.qml</file>
<file>ui/connection/SetupWizard.qml</file>
</qresource>
</RCC>

View File

@ -1,24 +1,32 @@
import QtQuick 2.0
import QtQuick 2.4
Item {
id: root
implicitHeight: childrenRect.height
implicitHeight: active ? childrenRect.height : 0
property bool active: d.kbd && d.kbd.active
Behavior on implicitHeight { NumberAnimation { duration: 130; easing.type: Easing.InOutQuad } }
QtObject {
id: d
property var kbd: null
property string virtualKeyboardString:
'
import QtQuick 2.8;
import QtQuick.VirtualKeyboard 2.1
InputPanel {
id: inputPanel
y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
'
}
property string virtualKeyboardString:
'
import QtQuick 2.8;
import QtQuick.VirtualKeyboard 2.1
InputPanel {
id: inputPanel
y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
'
Component.onCompleted: {
if (useVirtualKeyboard) {
var kbd = Qt.createQmlObject(virtualKeyboardString, root);
d.kbd = Qt.createQmlObject(d.virtualKeyboardString, root);
}
}
}

View File

@ -1,141 +0,0 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: qsTr("Welcome to %1!").arg(app.systemName)
backButtonVisible: true
onBackPressed: root.backPressed()
}
Connections {
target: engine.jsonRpcClient
onAuthenticationFailed: {
var popup = errorDialog.createObject(root)
popup.text = qsTr("Sorry, that wasn't right. Try again please.")
popup.open();
}
onCreateUserFailed: {
print("createUser failed")
var message;
switch (error) {
case "UserErrorInvalidUserId":
message = qsTr("The email you've entered isn't valid.")
break;
case "UserErrorDuplicateUserId":
message = qsTr("The email you've entered is already used.")
break;
case "UserErrorBadPassword":
message = qsTr("The password you've chose is too weak.")
break;
case "UserErrorBackendError":
message = qsTr("An error happened with the user storage. Please make sure your %1 box is installed correctly.")
break;
}
var popup = errorDialog.createObject(root, {text: message});
popup.open();
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
spacing: app.margins
Label {
Layout.fillWidth: true
text: engine.jsonRpcClient.initialSetupRequired ?
qsTr("In order to use your %1 system, please enter your email address and set a password for your nymea box.").arg(app.systemName)
: qsTr("In order to use your %1 system, please log in.").arg(app.systemName)
wrapMode: Text.WordWrap
}
ColumnLayout {
Layout.fillWidth: true
Label {
text: qsTr("Your e-mail address:")
Layout.fillWidth: true
}
TextField {
id: usernameTextField
Layout.fillWidth: true
inputMethodHints: Qt.ImhEmailCharactersOnly
placeholderText: "john.smith@cooldomain.com"
}
}
ColumnLayout {
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Password:")
}
TextField {
id: passwordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
ColumnLayout {
Layout.fillWidth: true
visible: engine.jsonRpcClient.initialSetupRequired
Label {
Layout.fillWidth: true
text: qsTr("Confirm password:")
}
TextField {
id: confirmPasswordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
Label {
Layout.fillWidth: true
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
Layout.preferredHeight: confirmPasswordTextField.height * 2
color: app.accentColor
}
Button {
Layout.fillWidth: true
text: qsTr("OK")
enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8
&& (!engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: {
if (engine.jsonRpcClient.initialSetupRequired) {
print("create user")
engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.text);
} else {
print("authenticate", usernameTextField.text, passwordTextField.text, "nymea-app")
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app");
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
}
Component {
id: errorDialog
ErrorDialog {
}
}
}

View File

@ -54,6 +54,7 @@ ApplicationWindow {
RootItem {
id: rootItem
anchors.fill: parent
anchors.bottomMargin: keyboardRect.height
}
NymeaDiscovery {

View File

@ -33,31 +33,30 @@ Page {
ColumnLayout {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
anchors.margins: app.margins
spacing: app.margins
spacing: app.margins * 2
RowLayout {
Label {
Layout.fillWidth: true
spacing: app.margins
horizontalAlignment: Text.AlignHCenter
color: app.accentColor
text: qsTr("Authentication required")
wrapMode: Text.WordWrap
font.pixelSize: app.largeFont
}
ColorIcon {
height: app.iconSize * 2
width: height
color: app.accentColor
name: "../images/info.svg"
}
Label {
color: app.accentColor
text: qsTr("Authentication required")
wrapMode: Text.WordWrap
Layout.fillWidth: true
font.pixelSize: app.largeFont
}
Image {
Layout.preferredWidth: app.iconSize * 6
Layout.preferredHeight: width
source: "images/nymea-box-setup.svg"
Layout.alignment: Qt.AlignHCenter
sourceSize.width: width
sourceSize.height: height
}
Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
text: qsTr("Please press the button on your %1 box to authenticate this device.").arg(app.systemName)
wrapMode: Text.WordWrap
}

View File

@ -145,7 +145,17 @@ Item {
})
return;
} else {
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
if (engine.jsonRpcClient.initialSetupRequired) {
var page = pageStack.push(Qt.resolvedUrl("connection/SetupWizard.qml"));
page.backPressed.connect(function() {
tabSettings.lastConnectedHost = "";
engine.connection.disconnect()
init();
})
return;
}
var page = pageStack.push(Qt.resolvedUrl("connection/LoginPage.qml"));
page.backPressed.connect(function() {
tabSettings.lastConnectedHost = "";
engine.connection.disconnect()

View File

@ -0,0 +1,158 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: qsTr("Welcome to %1!").arg(app.systemName)
backButtonVisible: true
onBackPressed: root.backPressed()
}
Connections {
target: engine.jsonRpcClient
onAuthenticationFailed: {
var popup = errorDialog.createObject(root)
popup.text = qsTr("Sorry, that wasn't right. Try again please.")
popup.open();
}
onCreateUserSucceeded: {
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app");
}
onCreateUserFailed: {
print("createUser failed")
var message;
switch (error) {
case "UserErrorInvalidUserId":
message = qsTr("The email you've entered isn't valid.")
break;
case "UserErrorDuplicateUserId":
message = qsTr("The email you've entered is already used.")
break;
case "UserErrorBadPassword":
message = qsTr("The password you've chose is too weak.")
break;
case "UserErrorBackendError":
message = qsTr("An error happened with the user storage. Please make sure your %1 box is installed correctly.")
break;
}
var popup = errorDialog.createObject(root, {text: message});
popup.open();
}
}
Flickable {
anchors.fill: parent
contentHeight: contentColumn.implicitHeight
ColumnLayout {
id: contentColumn
width: parent.width
spacing: app.margins
RowLayout {
Layout.margins: app.margins
spacing: app.margins
ColorIcon {
Layout.preferredHeight: app.iconSize * 2
Layout.preferredWidth: app.iconSize * 2
name: "../images/lock-closed.svg"
color: app.accentColor
}
Label {
Layout.fillWidth: true
text: engine.jsonRpcClient.initialSetupRequired ?
qsTr("In order to use your %1 system, please enter your email address and set a password for your %1 box.").arg(app.systemName)
: qsTr("In order to use your %1 system, please log in.").arg(app.systemName)
wrapMode: Text.WordWrap
}
}
GridLayout {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
columns: app.width > 400 ? 2 : 1
Label {
text: qsTr("Your e-mail address:")
Layout.fillWidth: true
}
TextField {
id: usernameTextField
Layout.fillWidth: true
inputMethodHints: Qt.ImhEmailCharactersOnly
placeholderText: "john.smith@cooldomain.com"
}
Label {
Layout.fillWidth: true
text: qsTr("Password:")
}
TextField {
id: passwordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
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 {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.bottomMargin: app.margins
text: qsTr("OK")
enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8
&& (!engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: {
if (engine.jsonRpcClient.initialSetupRequired) {
print("create user")
engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.text);
} else {
print("authenticate", usernameTextField.text, passwordTextField.text, "nymea-app")
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app");
}
}
}
}
}
Component {
id: errorDialog
ErrorDialog {
}
}
}

View File

@ -0,0 +1,28 @@
import QtQuick 2.5
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: qsTr("First setup")
backButtonVisible: true
onBackPressed: root.backPressed()
}
EmptyViewPlaceholder {
anchors.centerIn: parent
width: parent.width - app.margins * 2
title: qsTr("Welcome to %1!").arg(app.systemName)
text: qsTr("This %1 system has not been set up yet. This wizard will guide you through a few simple steps to set it up.").arg(app.systemName)
imageSource: "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle)
buttonText: qsTr("Next")
onButtonClicked: {
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
}
}
}