Improve setup wizard
This commit is contained in:
parent
2ad82d80a6
commit
424547333f
@ -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 {
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,6 +54,7 @@ ApplicationWindow {
|
||||
RootItem {
|
||||
id: rootItem
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: keyboardRect.height
|
||||
}
|
||||
|
||||
NymeaDiscovery {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
158
nymea-app/ui/connection/LoginPage.qml
Normal file
158
nymea-app/ui/connection/LoginPage.qml
Normal 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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
28
nymea-app/ui/connection/SetupWizard.qml
Normal file
28
nymea-app/ui/connection/SetupWizard.qml
Normal 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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user