From 234ee7a2e9da9b1f42e873e8e86bd2cba3c5154c Mon Sep 17 00:00:00 2001
From: Ming Rui Zhang <mingrui.zhang@savoirfairelinux.com>
Date: Fri, 16 Jul 2021 10:34:50 -0400
Subject: [PATCH] wizardview: refactor account creation ui and enhance flow

1. Use MaterialToolTip in MaterialButton
2. Add BubbleLabel and BackButton
3. Add WizardViewStepModel
4. Focus re-visit

Gitlab: #470

Change-Id: I818da76c4b97cb08d2b6df6b2c8e2752d7a522f2
---
 CMakeLists.txt                                |   2 +
 qml.qrc                                       |   2 +
 src/MainApplicationWindow.qml                 |   3 -
 src/accountadapter.cpp                        |  10 +-
 src/accountadapter.h                          |   2 +-
 src/appsettingsmanager.h                      |   4 +-
 src/commoncomponents/BackButton.qml           |  32 ++
 src/commoncomponents/BubbleLabel.qml          |  36 ++
 src/commoncomponents/MaterialButton.qml       |  14 +-
 src/commoncomponents/PushButton.qml           |   1 -
 src/constant/JamiQmlUtils.qml                 |   8 +
 src/constant/JamiStrings.qml                  |  27 +-
 src/constant/JamiTheme.qml                    |  10 +
 src/mainview/MainView.qml                     |  14 +-
 src/qmlregister.cpp                           |  11 +-
 src/wizardview/WizardView.qml                 | 326 +++---------------
 src/wizardview/components/BackupKeyPage.qml   |  89 +++--
 .../ConnectToAccountManagerPage.qml           |  81 +++--
 .../components/CreateAccountPage.qml          | 175 ++++------
 .../components/CreateSIPAccountPage.qml       |  81 ++---
 .../components/ImportFromBackupPage.qml       |  70 ++--
 .../components/ImportFromDevicePage.qml       |  67 ++--
 src/wizardview/components/ProfilePage.qml     |  91 ++---
 src/wizardview/components/WelcomePage.qml     |  93 +++--
 src/wizardviewstepmodel.cpp                   | 144 ++++++++
 src/wizardviewstepmodel.h                     |  83 +++++
 26 files changed, 791 insertions(+), 685 deletions(-)
 create mode 100644 src/commoncomponents/BackButton.qml
 create mode 100644 src/commoncomponents/BubbleLabel.qml
 create mode 100644 src/wizardviewstepmodel.cpp
 create mode 100644 src/wizardviewstepmodel.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c28717ab7..42449864e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,6 +86,7 @@ set(COMMON_SOURCES
     ${SRC_DIR}/searchresultslistmodel.cpp
     ${SRC_DIR}/calloverlaymodel.cpp
     ${SRC_DIR}/filestosendlistmodel.cpp
+    ${SRC_DIR}/wizardviewstepmodel.cpp
     ${SRC_DIR}/avatarregistry.cpp)
 
 set(COMMON_HEADERS
@@ -143,6 +144,7 @@ set(COMMON_HEADERS
     ${SRC_DIR}/searchresultslistmodel.h
     ${SRC_DIR}/calloverlaymodel.h
     ${SRC_DIR}/filestosendlistmodel.h
+    ${SRC_DIR}/wizardviewstepmodel.h
     ${SRC_DIR}/avatarregistry.h)
 
 set(QML_LIBS
diff --git a/qml.qrc b/qml.qrc
index e4a1b61f8..297d67ee8 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -157,5 +157,7 @@
         <file>src/mainview/components/InvitationView.qml</file>
         <file>src/commoncomponents/GeneralWebEngineView.qml</file>
         <file>src/constant/JamiResources.qml</file>
+        <file>src/commoncomponents/BubbleLabel.qml</file>
+        <file>src/commoncomponents/BackButton.qml</file>
     </qresource>
 </RCC>
diff --git a/src/MainApplicationWindow.qml b/src/MainApplicationWindow.qml
index 5da265bdf..0579e722d 100644
--- a/src/MainApplicationWindow.qml
+++ b/src/MainApplicationWindow.qml
@@ -106,9 +106,6 @@ ApplicationWindow {
     }
 
     function startClient(){
-        setX(Screen.width / 2 - width / 2)
-        setY(Screen.height / 2 - height / 2)
-
         if (UtilsAdapter.getAccountListSize() !== 0) {
             mainApplicationLoader.setSource(JamiQmlUtils.mainViewLoadPath)
         } else {
diff --git a/src/accountadapter.cpp b/src/accountadapter.cpp
index f65dd4c96..eb3f1395e 100644
--- a/src/accountadapter.cpp
+++ b/src/accountadapter.cpp
@@ -107,20 +107,15 @@ AccountAdapter::createJamiAccount(QString registeredName,
             confProps.isRendezVous = settings["isRendezVous"].toBool();
             lrcInstance_->accountModel().setAccountConfig(accountId, confProps);
 
-            auto showBackup = isCreating
-                              && !settingsManager_->getValue(Settings::Key::NeverShowMeAgain)
-                                      .toBool();
             if (!registeredName.isEmpty()) {
                 QObject::disconnect(registeredNameSavedConnection_);
                 registeredNameSavedConnection_
                     = connect(&lrcInstance_->accountModel(),
                               &lrc::api::NewAccountModel::profileUpdated,
-                              [this, showBackup, addedAccountId = accountId](
-                                  const QString& accountId) {
+                              [this, addedAccountId = accountId](const QString& accountId) {
                                   if (addedAccountId == accountId) {
                                       Q_EMIT lrcInstance_->accountListChanged();
                                       Q_EMIT accountAdded(accountId,
-                                                          showBackup,
                                                           lrcInstance_->accountModel()
                                                               .getAccountList()
                                                               .indexOf(accountId));
@@ -134,7 +129,6 @@ AccountAdapter::createJamiAccount(QString registeredName,
             } else {
                 Q_EMIT lrcInstance_->accountListChanged();
                 Q_EMIT accountAdded(accountId,
-                                    showBackup,
                                     lrcInstance_->accountModel().getAccountList().indexOf(
                                         accountId));
             }
@@ -172,7 +166,6 @@ AccountAdapter::createSIPAccount(const QVariantMap& settings)
 
                               Q_EMIT lrcInstance_->accountListChanged();
                               Q_EMIT accountAdded(accountId,
-                                                  false,
                                                   lrcInstance_->accountModel()
                                                       .getAccountList()
                                                       .indexOf(accountId));
@@ -208,7 +201,6 @@ AccountAdapter::createJAMSAccount(const QVariantMap& settings)
                               lrcInstance_->accountModel().setAccountConfig(accountId, confProps);
 
                               Q_EMIT accountAdded(accountId,
-                                                  false,
                                                   lrcInstance_->accountModel()
                                                       .getAccountList()
                                                       .indexOf(accountId));
diff --git a/src/accountadapter.h b/src/accountadapter.h
index 7ffcbce76..f4f8e2280 100644
--- a/src/accountadapter.h
+++ b/src/accountadapter.h
@@ -95,7 +95,7 @@ Q_SIGNALS:
 
     // Send report failure to QML to make it show the right UI state .
     void reportFailure();
-    void accountAdded(QString accountId, bool showBackUp, int index);
+    void accountAdded(QString accountId, int index);
 
 private:
     // Implement what to do when account creation fails.
diff --git a/src/appsettingsmanager.h b/src/appsettingsmanager.h
index 6ff083ff1..6c4f5d0dc 100644
--- a/src/appsettingsmanager.h
+++ b/src/appsettingsmanager.h
@@ -94,8 +94,8 @@ public:
     explicit AppSettingsManager(QObject* parent = nullptr);
     ~AppSettingsManager() = default;
 
-    QVariant getValue(const Settings::Key key);
-    void setValue(const Settings::Key key, const QVariant& value);
+    Q_INVOKABLE QVariant getValue(const Settings::Key key);
+    Q_INVOKABLE void setValue(const Settings::Key key, const QVariant& value);
 
 private:
     QSettings* settings_;
diff --git a/src/commoncomponents/BackButton.qml b/src/commoncomponents/BackButton.qml
new file mode 100644
index 000000000..9f523b009
--- /dev/null
+++ b/src/commoncomponents/BackButton.qml
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 by Savoir-faire Linux
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+
+import net.jami.Constants 1.0
+
+PushButton {
+    id: root
+
+    normalColor: JamiTheme.backgroundColor
+    imageColor: JamiTheme.primaryForegroundColor
+
+    source: JamiResources.ic_arrow_back_24dp_svg
+    toolTipText: JamiStrings.back
+}
diff --git a/src/commoncomponents/BubbleLabel.qml b/src/commoncomponents/BubbleLabel.qml
new file mode 100644
index 000000000..1b81e5499
--- /dev/null
+++ b/src/commoncomponents/BubbleLabel.qml
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 by Savoir-faire Linux
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+
+import net.jami.Constants 1.0
+
+Label {
+    id: root
+
+    property color textColor: JamiTheme.whiteColor
+    property color bubbleColor: JamiTheme.wizardGreenColor
+
+    padding: 8
+
+    background: Rectangle {
+        color: bubbleColor
+        radius: 24
+    }
+}
diff --git a/src/commoncomponents/MaterialButton.qml b/src/commoncomponents/MaterialButton.qml
index 09c835bcd..578c9922b 100644
--- a/src/commoncomponents/MaterialButton.qml
+++ b/src/commoncomponents/MaterialButton.qml
@@ -28,7 +28,7 @@ Button {
 
     property alias fontCapitalization: buttonText.font.capitalization
     property alias source: buttonImage.source
-    property string toolTipText: ""
+    property alias toolTipText: toolTip.text
     property var color: "transparent"
     property var hoveredColor: undefined
     property var pressedColor: undefined
@@ -50,6 +50,14 @@ Button {
 
     hoverEnabled: hoveredColor !== undefined
 
+    MaterialToolTip {
+        id: toolTip
+
+        parent: root
+        visible: hovered && (toolTipText.length > 0)
+        delay: Qt.styleHints.mousePressAndHoldInterval
+    }
+
     contentItem: Item {
         Rectangle {
             anchors.fill: parent
@@ -131,10 +139,6 @@ Button {
         }
     }
 
-    ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
-    ToolTip.visible: hovered && (toolTipText.length > 0)
-    ToolTip.text: toolTipText
-
     background: Rectangle {
         id: backgroundRect
         anchors.fill: parent
diff --git a/src/commoncomponents/PushButton.qml b/src/commoncomponents/PushButton.qml
index 4bf762c74..ef9bbb011 100644
--- a/src/commoncomponents/PushButton.qml
+++ b/src/commoncomponents/PushButton.qml
@@ -80,7 +80,6 @@ AbstractButton {
     hoverEnabled: true
     focusPolicy: Qt.TabFocus
 
-
     MaterialToolTip {
         id: toolTip
 
diff --git a/src/constant/JamiQmlUtils.qml b/src/constant/JamiQmlUtils.qml
index a7ebbf6f4..58395c029 100644
--- a/src/constant/JamiQmlUtils.qml
+++ b/src/constant/JamiQmlUtils.qml
@@ -35,6 +35,14 @@ Item {
     property bool callIsFullscreen: false
     signal fullScreenCallEnded
 
+    property var accountCreationInputParaObject: ({})
+
+    function setUpAccountCreationInputPara(inputPara) {
+        JamiQmlUtils.accountCreationInputParaObject = {}
+        Object.assign(JamiQmlUtils.accountCreationInputParaObject, inputPara)
+        return accountCreationInputParaObject
+    }
+
     // MessageBar buttons in mainview points
     property var mainViewRectObj
     property var messageBarButtonsRowObj
diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml
index e8319e3d9..f8876d7d0 100644
--- a/src/constant/JamiStrings.qml
+++ b/src/constant/JamiStrings.qml
@@ -177,8 +177,12 @@ Item {
     property string backupAccount: qsTr("Backup your account!")
     property string backupAccountBtn: qsTr("Backup account")
     property string skip: qsTr("Skip")
+    property string success: qsTr("Success")
+    property string error: qsTr("Error")
     property string neverShowAgain: qsTr("Never show me this again")
     property string recommended: qsTr("Recommended")
+    property string jamiArchiveFiles: qsTr("Jami archive files")
+    property string allFiles: qsTr("All files")
 
     // BannedItemDelegate
     property string reinstateContact: qsTr("Reinstate as contact")
@@ -247,7 +251,7 @@ Item {
     property string jamiManagementServerURL: qsTr("Jami Account Management Server URL")
     property string jamsCredentials: qsTr("Enter your JAMS credentials")
     property string connect: qsTr("Connect")
-    property string generatingAccount: qsTr("Creating account…")
+    property string creatingAccount: qsTr("Creating account…")
     property string backToWelcome: qsTr("Back to welcome page")
 
     // CreateAccountPage
@@ -259,7 +263,14 @@ Item {
     property string confirmPassword: qsTr("Confirm password")
     property string notePasswordRecovery: qsTr("Choose a password to encrypt your account on this device. Note that the password cannot be recovered.")
     property string optional: qsTr("Optional")
-    property string chooseNameRV: qsTr("Choose a name for your rendezvous point")
+    property string chooseUsernameForAccount: qsTr("Choose a username for your account")
+    property string chooseUsernameForRV: qsTr("Choose a name for your rendezvous point")
+    property string chooseAName: qsTr("Choose a name")
+    property string chooseYourUserName: qsTr("Choose your username")
+    property string invalidName: qsTr("Invalid name")
+    property string invalidUsername: qsTr("Invalid username")
+    property string nameAlreadyTaken: qsTr("Name already taken")
+    property string usernameAlreadyTaken: qsTr("Username already taken")
 
     // CreateSIPAccountPage
     property string proxy: qsTr("Proxy")
@@ -375,12 +386,15 @@ Item {
                                                    "in the account settings. " +
                                                    "This will create a .gz file on your device.")
     property string connectFromBackup: qsTr("Restore an account from backup")
+    property string generatingAccount: qsTr("Generating account…")
+    property string importFromBackup: qsTr("Import from backup")
 
     // ImportFromDevicePage
     property string mainAccountPassword: qsTr("Enter Jami account password")
     property string enterPIN: qsTr("Enter the PIN from another configured Jami account. " +
                                 "Use the \"Link Another Device\" feature to obtain a PIN.")
     property string connectFromAnotherDevice: qsTr("Link device")
+    property string pin: qsTr("PIN")
 
     // LinkDevicesDialog
     property string pinTimerInfos: qsTr("The PIN and the account password should be entered in your device within 10 minutes.")
@@ -423,7 +437,9 @@ Item {
     property string chooseImageFile: qsTr("Choose image file")
 
     // ProfilePage
+    property string profileSharedWithContacts: qsTr("Profile is only shared with contacts")
     property string saveProfile: qsTr("Save profile")
+    property string enterYourName: qsTr("Enter your name")
     property string enterRVName: qsTr("Enter the rendezvous point's name")
     property string generatingRV: qsTr("Creating rendezvous point…")
     property string information: qsTr("Information")
@@ -443,6 +459,8 @@ Item {
     // WelcomePage
     property string shareInvite: qsTr("This is your Jami username.\nCopy and share it with your friends!")
     property string linkFromAnotherDevice: qsTr("Link this device to an existing account")
+    property string importAccountFromOtherDevice: qsTr("Import account from other device")
+    property string importAccountFromBackup: qsTr("Import account from backup file")
     property string advancedFeatures: qsTr("Advanced features")
     property string showAdvancedFeatures: qsTr("Show advanced features")
     property string connectJAMSServer: qsTr("Connect to a JAMS server")
@@ -450,8 +468,11 @@ Item {
     property string addSIPAccount: qsTr("Add a SIP account")
     property string errorCreateAccount: qsTr("Error while creating your account. Check your credentials.")
     property string createNewRV: qsTr("Create new rendezvous point")
-    property string createNewJA: qsTr("Create a Jami account")
+    property string createAJamiAccount: qsTr("Create a Jami account")
+    property string createNewJamiAccount: qsTr("Create new Jami account")
+    property string createNewSipAccount: qsTr("Create new SIP account")
     property string aboutJami: qsTr("About Jami")
+    property string welcomeTo: qsTr("Welcome to")
 
     // SmartList
     property string clearText: qsTr("Clear Text")
diff --git a/src/constant/JamiTheme.qml b/src/constant/JamiTheme.qml
index ae77e712b..9958f963d 100644
--- a/src/constant/JamiTheme.qml
+++ b/src/constant/JamiTheme.qml
@@ -287,6 +287,16 @@ Item {
     property real invitationViewButtonIconSize: 24
     property real invitationViewButtonsSpacing: 30
 
+    // WizardView
+    property real wizardViewPageLayoutSpacing: 12
+    property real wizardViewPageBackButtonMargins: 20
+    property real wizardViewPageBackButtonSize: 35
+
+    // WizardView Welcome Page
+    property real welcomeLabelPointSize: 30
+    property real welcomeLogoWidth: 330
+    property real welcomeLogoHeight: 110
+
     // Main application spec
     property real mainViewMinWidth: 300
     property real mainViewMinHeight: 500
diff --git a/src/mainview/MainView.qml b/src/mainview/MainView.qml
index 68d9ec2eb..f468972c8 100644
--- a/src/mainview/MainView.qml
+++ b/src/mainview/MainView.qml
@@ -232,6 +232,15 @@ Rectangle {
         }
     }
 
+    Connections {
+        target: WizardViewStepModel
+
+        function onCloseWizardView() {
+            mainViewStackLayout.currentIndex = 0
+            backToMainView()
+        }
+    }
+
     StackLayout {
         id: mainViewStackLayout
 
@@ -329,11 +338,6 @@ Rectangle {
                 mainViewStackLayout.currentIndex = 0
                 backToMainView()
             }
-
-            onWizardViewIsClosed: {
-                mainViewStackLayout.currentIndex = 0
-                backToMainView()
-            }
         }
     }
 
diff --git a/src/qmlregister.cpp b/src/qmlregister.cpp
index 1bb6ebfa7..891761daf 100644
--- a/src/qmlregister.cpp
+++ b/src/qmlregister.cpp
@@ -54,6 +54,7 @@
 #include "videoformatfpsmodel.h"
 #include "videoformatresolutionmodel.h"
 #include "videoinputdevicemodel.h"
+#include "wizardviewstepmodel.h"
 
 #include "api/peerdiscoverymodel.h"
 #include "api/newcodecmodel.h"
@@ -125,9 +126,6 @@ registerTypes(QQmlEngine* engine,
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, settingsAdapter, "SettingsAdapter");
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_ADAPTERS, pluginAdapter, "PluginAdapter");
 
-    auto avatarRegistry = new AvatarRegistry(lrcInstance, parent);
-    QML_REGISTERSINGLETONTYPE_POBJECT(NS_HELPERS, avatarRegistry, "AvatarRegistry");
-
     // TODO: remove these
     QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, AVModel, &lrcInstance->avModel())
     QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, PluginModel, &lrcInstance->pluginModel())
@@ -178,6 +176,12 @@ registerTypes(QQmlEngine* engine,
 
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_CONSTANTS, screenInfo, "ScreenInfo")
     QML_REGISTERSINGLETONTYPE_POBJECT(NS_CONSTANTS, lrcInstance, "LRCInstance")
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_CONSTANTS, appSettingsManager, "AppSettingsManager")
+
+    auto avatarRegistry = new AvatarRegistry(lrcInstance, parent);
+    auto wizardViewStepModel = new WizardViewStepModel(lrcInstance, accountAdapter, appSettingsManager, parent);
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_HELPERS, avatarRegistry, "AvatarRegistry");
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, wizardViewStepModel, "WizardViewStepModel")
 
     // C++ singletons
     // TODO: remove this
@@ -207,6 +211,7 @@ registerTypes(QQmlEngine* engine,
     // Enums
     QML_REGISTERUNCREATABLE(NS_ENUMS, Settings);
     QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager);
+    QML_REGISTERUNCREATABLE(NS_ENUMS, WizardViewStepModel)
 
     engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance));
     engine->addImageProvider(QLatin1String("avatarImage"),
diff --git a/src/wizardview/WizardView.qml b/src/wizardview/WizardView.qml
index 029cfcbbd..ef726f044 100644
--- a/src/wizardview/WizardView.qml
+++ b/src/wizardview/WizardView.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,6 +26,7 @@ import QtGraphicalEffects 1.14
 import net.jami.Models 1.0
 import net.jami.Adapters 1.0
 import net.jami.Constants 1.0
+import net.jami.Enums 1.0
 
 import "../"
 import "../commoncomponents"
@@ -33,148 +35,40 @@ import "components"
 Rectangle {
     id: root
 
-    enum Mode {
-        CREATE,
-        IMPORT,
-        MIGRATE,
-        CREATESIP,
-        CONNECTMANAGER
-    }
-
-    enum WizardViewPageIndex {
-        WELCOMEPAGE = 0,
-        CREATEACCOUNTPAGE,
-        CREATESIPACCOUNTPAGE,
-        IMPORTFROMBACKUPPAGE,
-        BACKUPKEYSPAGE,
-        IMPORTFROMDEVICEPAGE,
-        CONNECTTOACCOUNTMANAGERPAGE,
-        PROFILEPAGE,
-        CREATERENDEZVOUS
-    }
-
-    readonly property int layoutSpacing: 12
-    readonly property int backButtonMargins: 20
-
-    property int textFontSize: 9
-    property int wizardMode: WizardView.CREATE
-    property int addedAccountIndex: -1
-    property bool isRdv: false
-    property bool showBackUp: false
-    property bool showProfile: false
-    property bool showBottom: false
-    property string fileToImport: ""
-    property string registeredName: ""
-
-    property var inputParaObject: ({})
-
     // signal to redirect the page to main view
     signal loaderSourceChangeRequested(int sourceToLoad)
-    signal wizardViewIsClosed
 
-    visible: true
     color: JamiTheme.backgroundColor
 
-    Component.onCompleted: {
-        changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-    }
-
     Connections{
         target: AccountAdapter
 
-        enabled: controlPanelStackView.currentIndex !== WizardView.WizardViewPageIndex.WELCOMEPAGE
-
-        function onAccountAdded(accountId, showBackUp, index) {
-            addedAccountIndex = index
-            AccountAdapter.changeAccount(index)
-            if (showProfile) {
-                changePageQML(WizardView.WizardViewPageIndex.PROFILEPAGE)
-                profilePage.readyToSaveDetails()
-                profilePage.isRdv = isRdv
-                profilePage.createdAccountId = accountId
-            } else if (controlPanelStackView.currentIndex === WizardView.WizardViewPageIndex.PROFILEPAGE) {
-                profilePage.readyToSaveDetails()
-                profilePage.isRdv = isRdv
-                profilePage.createdAccountId = accountId
-            } else if (showBackUp) {
-                changePageQML(WizardView.WizardViewPageIndex.BACKUPKEYSPAGE)
-            } else {
-                changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
-            }
-        }
-
         // reportFailure
         function onReportFailure() {
             var errorMessage = JamiStrings.errorCreateAccount
 
             switch(controlPanelStackView.currentIndex) {
-            case WizardView.WizardViewPageIndex.IMPORTFROMDEVICEPAGE:
+            case importFromDevicePage.stackLayoutIndex:
                 importFromDevicePage.errorOccured(errorMessage)
                 break
-            case WizardView.WizardViewPageIndex.IMPORTFROMBACKUPPAGE:
+            case importFromBackupPage.stackLayoutIndex:
                 importFromBackupPage.errorOccured(errorMessage)
                 break
-            case WizardView.WizardViewPageIndex.CONNECTTOACCOUNTMANAGERPAGE:
+            case connectToAccountManagerPage.stackLayoutIndex:
                 connectToAccountManagerPage.errorOccured(errorMessage)
                 break
             }
         }
     }
 
-    function changePageQML(pageIndex) {
-        controlPanelStackView.currentIndex = pageIndex
-        if (pageIndex === WizardView.WizardViewPageIndex.WELCOMEPAGE) {
-            fileToImport = ""
-            isRdv = false
-            createAccountPage.nameRegistrationUIState = UsernameLineEdit.NameRegistrationState.BLANK
-        } else if (pageIndex === WizardView.WizardViewPageIndex.CREATEACCOUNTPAGE) {
-            createAccountPage.initializeOnShowUp(false)
-        } else if (pageIndex === WizardView.WizardViewPageIndex.CREATESIPACCOUNTPAGE) {
-            createSIPAccountPage.initializeOnShowUp()
-        } else if (pageIndex === WizardView.WizardViewPageIndex.IMPORTFROMDEVICEPAGE) {
-            importFromDevicePage.initializeOnShowUp()
-        } else if (pageIndex === WizardView.WizardViewPageIndex.CONNECTTOACCOUNTMANAGERPAGE) {
-            connectToAccountManagerPage.initializeOnShowUp()
-        } else if (pageIndex === WizardView.WizardViewPageIndex.IMPORTFROMBACKUPPAGE) {
-            importFromBackupPage.clearAllTextFields()
-            fileToImport = ""
-        } else if (pageIndex === WizardView.WizardViewPageIndex.PROFILEPAGE) {
-            profilePage.initializeOnShowUp()
-            profilePage.showBottom = showBottom
-        } else if (pageIndex === WizardView.WizardViewPageIndex.CREATERENDEZVOUS) {
-            isRdv = true
-            controlPanelStackView.currentIndex = WizardView.WizardViewPageIndex.CREATEACCOUNTPAGE
-            createAccountPage.initializeOnShowUp(true)
-        }
-    }
-
-    PasswordDialog {
-        id: passwordDialog
-
-        visible: false
-        purpose: PasswordDialog.ExportAccount
+    Connections {
+        target: WizardViewStepModel
 
-        onDoneSignal: {
-            if (currentPurpose === passwordDialog.ExportAccount) {
-                var title = success ? qsTr("Success") : qsTr("Error")
-                var info = success ? JamiStrings.backupSuccessful : JamiStrings.backupFailed
-
-                AccountAdapter.passwordSetStatusMessageBox(success,
-                                                         title, info)
-                if (success) {
-                    console.log("Account Export Succeed")
-                    loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
-                }
-            }
+        function onCloseWizardView() {
+            loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
         }
     }
 
-    MouseArea {
-        anchors.fill: parent
-        onClicked: forceActiveFocus()
-    }
-
     ScrollView {
         id: wizardViewScrollView
 
@@ -191,36 +85,23 @@ Rectangle {
         StackLayout {
             id: controlPanelStackView
 
+            function setPage(obj) {
+                for (var i in this.children) {
+                    if (this.children[i] === obj) {
+                        currentIndex = i
+                        return
+                    }
+                }
+            }
+
             anchors.centerIn: parent
 
             width: wizardViewScrollView.width
 
-            currentIndex: WizardView.WizardViewPageIndex.WELCOMEPAGE
-
-            Component.onCompleted: {
-                // avoid binding loop
-                height = Qt.binding(function (){
-                    var index = currentIndex
-                            === WizardView.WizardViewPageIndex.CREATERENDEZVOUS ?
-                                WizardView.WizardViewPageIndex.CREATEACCOUNTPAGE : currentIndex
-                    return Math.max(
-                                controlPanelStackView.itemAt(index).preferredHeight,
-                                wizardViewScrollView.height)
-                })
-            }
-
             WelcomePage {
                 id: welcomePage
 
-                Layout.alignment: Qt.AlignCenter
-
-                onWelcomePageRedirectPage: {
-                    changePageQML(toPageIndex)
-                }
-
-                onLeavePage: {
-                    wizardViewIsClosed()
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
 
                 onScrollToBottom: {
                     if (welcomePage.preferredHeight > root.height)
@@ -231,172 +112,55 @@ Rectangle {
             CreateAccountPage {
                 id: createAccountPage
 
-                Layout.alignment: Qt.AlignCenter
-
-                onCreateAccount: {
-                    inputParaObject = {}
-                    inputParaObject["isRendezVous"] = isRdv
-                    inputParaObject["password"] = text_passwordEditAlias
-                    AccountAdapter.createJamiAccount(
-                        createAccountPage.text_usernameEditAlias,
-                        inputParaObject,
-                        true)
-                    showBackUp = !isRdv
-                    showBottom = true
-                    changePageQML(WizardView.WizardViewPageIndex.PROFILEPAGE)
-                }
-
-                onLeavePage: {
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
             }
 
-            CreateSIPAccountPage {
-                id: createSIPAccountPage
-
-                Layout.alignment: Qt.AlignCenter
-
-                onLeavePage: {
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                }
-
-                onCreateAccount: {
-                    inputParaObject = {}
-                    inputParaObject["hostname"] = createSIPAccountPage.text_sipServernameEditAlias
-                    inputParaObject["username"] = createSIPAccountPage.text_sipUsernameEditAlias
-                    inputParaObject["password"] = createSIPAccountPage.text_sipPasswordEditAlias
-                    inputParaObject["proxy"] = createSIPAccountPage.text_sipProxyEditAlias
-                    createSIPAccountPage.clearAllTextFields()
-
-                    AccountAdapter.createSIPAccount(inputParaObject, "")
-                    showBackUp = false
-                    showBottom = false
-                    changePageQML(WizardView.WizardViewPageIndex.PROFILEPAGE)
-                    controlPanelStackView.profilePage.readyToSaveDetails()
-                }
-            }
-
-            ImportFromBackupPage {
-                id: importFromBackupPage
-
-                Layout.alignment: Qt.AlignCenter
-
-                onLeavePage: {
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                }
+            ProfilePage {
+                id: profilePage
 
-                onImportAccount: {
-                    inputParaObject = {}
-                    inputParaObject["archivePath"] = UtilsAdapter.getAbsPath(importFromBackupPage.filePath)
-                    inputParaObject["password"] = importFromBackupPage.text_passwordFromBackupEditAlias
-                    showBackUp = false
-                    showBottom = false
-                    showProfile = false
-                    AccountAdapter.createJamiAccount(
-                        "", inputParaObject, "", false)
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
             }
 
             BackupKeyPage {
                 id: backupKeysPage
 
-                Layout.alignment: Qt.AlignCenter
-
-                onNeverShowAgainBoxClicked: {
-                    SettingsAdapter.setValue(Settings.NeverShowMeAgain, isChecked)
-                }
-
-                onExport_Btn_FileDialogAccepted: {
-                    if (accepted) {
-                        // is there password? If so, go to password dialog, else, go to following directly
-                        if (AccountAdapter.hasPassword()) {
-                            passwordDialog.path = UtilsAdapter.getAbsPath(folderDir)
-                            passwordDialog.open()
-                            return
-                        } else {
-                            if (folderDir.length > 0) {
-                                AccountAdapter.exportToFile(
-                                            LRCInstance.currentAccountId,
-                                            UtilsAdapter.getAbsPath(folderDir))
-                            }
-                        }
-                    }
-
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                    loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
-                }
-
-                onLeavePage: {
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                    loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
             }
 
             ImportFromDevicePage {
                 id: importFromDevicePage
 
-                Layout.alignment: Qt.AlignCenter
-
-                onLeavePage: {
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
+            }
 
-                onImportAccount: {
-                    inputParaObject = {}
-                    inputParaObject["archivePin"] = importFromDevicePage.text_pinFromDeviceAlias
-                    inputParaObject["password"] = importFromDevicePage.text_passwordFromDeviceAlias
+            ImportFromBackupPage {
+                id: importFromBackupPage
 
-                    showProfile = false
-                    showBackUp = false
-                    showBottom = false
-                    AccountAdapter.createJamiAccount(
-                        "", inputParaObject, "", false)
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
             }
 
             ConnectToAccountManagerPage {
                 id: connectToAccountManagerPage
 
-                Layout.alignment: Qt.AlignCenter
-
-                onCreateAccount: {
-                    inputParaObject = {}
-                    inputParaObject["username"]
-                            = connectToAccountManagerPage.text_usernameManagerEditAlias
-                    inputParaObject["password"]
-                            = connectToAccountManagerPage.text_passwordManagerEditAlias
-                    inputParaObject["manager"]
-                            = connectToAccountManagerPage.text_accountManagerEditAlias
-                    AccountAdapter.createJAMSAccount(inputParaObject)
-                }
-
-                onLeavePage: {
-                    changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
             }
 
-            ProfilePage {
-                id: profilePage
-
-                Layout.alignment: Qt.AlignCenter
-
-                function leave() {
-                    if (showBackUp)
-                        changePageQML(WizardView.WizardViewPageIndex.BACKUPKEYSPAGE)
-                    else {
-                        changePageQML(WizardView.WizardViewPageIndex.WELCOMEPAGE)
-                        loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
-                    }
-
-                    profilePage.initializeOnShowUp()
-                }
+            CreateSIPAccountPage {
+                id: createSIPAccountPage
 
-                onSaveProfile: {
-                    AccountAdapter.setCurrAccDisplayName(profilePage.displayName)
-                    leave()
-                }
+                onShowThisPage: controlPanelStackView.setPage(this)
+            }
 
-                onLeavePage: leave()
+            Component.onCompleted: {
+                // avoid binding loop
+                height = Qt.binding(function (){
+                    var index = currentIndex
+                            === WizardViewStepModel.MainSteps.CreateRendezVous ?
+                                WizardViewStepModel.MainSteps.CreateJamiAccount : currentIndex
+                    return Math.max(
+                                controlPanelStackView.itemAt(index).preferredHeight,
+                                wizardViewScrollView.height)
+                })
             }
         }
     }
diff --git a/src/wizardview/components/BackupKeyPage.qml b/src/wizardview/components/BackupKeyPage.qml
index cf69527f3..49fde1695 100644
--- a/src/wizardview/components/BackupKeyPage.qml
+++ b/src/wizardview/components/BackupKeyPage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +23,9 @@ import QtQuick.Controls 2.14
 import Qt.labs.platform 1.1
 
 import net.jami.Models 1.0
+import net.jami.Adapters 1.0
 import net.jami.Constants 1.0
+import net.jami.Enums 1.0
 
 import "../../commoncomponents"
 import "../../settingsview/components"
@@ -32,28 +35,59 @@ Rectangle {
 
     property int preferredHeight: backupKeysPageColumnLayout.implicitHeight
 
-    signal neverShowAgainBoxClicked(bool isChecked)
-    signal leavePage
-    signal export_Btn_FileDialogAccepted(bool accepted, string folderDir)
+    signal showThisPage
+
+    Connections {
+        target: WizardViewStepModel
+
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.BackupKeys)
+                root.showThisPage()
+        }
+    }
+
+    PasswordDialog {
+        id: passwordDialog
+
+        visible: false
+        purpose: PasswordDialog.ExportAccount
+
+        onDoneSignal: {
+            var title = success ? JamiStrings.success : JamiStrings.error
+            var info = success ? JamiStrings.backupSuccessful : JamiStrings.backupFailed
+
+            AccountAdapter.passwordSetStatusMessageBox(success, title, info)
+            if (success)
+                loaderSourceChangeRequested(MainApplicationWindow.LoadedSource.MainView)
+        }
+    }
 
     // JamiFileDialog for exporting account
     JamiFileDialog {
-        id: exportBtn_Dialog
+        id: exportDialog
 
         mode: JamiFileDialog.SaveFile
 
         title: JamiStrings.backupAccountHere
         folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/Desktop"
 
-        nameFilters: [qsTr("Jami archive files") + " (*.gz)", qsTr(
-                "All files") + " (*)"]
+        nameFilters: [JamiStrings.jamiArchiveFiles + " (*.gz)", JamiStrings.allFiles + " (*)"]
 
         onAccepted: {
-            export_Btn_FileDialogAccepted(true, file)
-        }
+            // Is there password? If so, go to password dialog, else, go to following directly
+            if (AccountAdapter.hasPassword()) {
+                passwordDialog.path = UtilsAdapter.getAbsPath(folder)
+                passwordDialog.open()
+                return
+            } else {
+                if (folder.length > 0) {
+                    AccountAdapter.exportToFile(
+                                LRCInstance.currentAccountId,
+                                UtilsAdapter.getAbsPath(folder))
+                }
+            }
 
-        onRejected: {
-            export_Btn_FileDialogAccepted(false, folder)
+            WizardViewStepModel.nextStep()
         }
 
         onVisibleChanged: {
@@ -68,16 +102,16 @@ Rectangle {
     ColumnLayout {
         id: backupKeysPageColumnLayout
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         anchors.horizontalCenter: parent.horizontalCenter
         anchors.verticalCenter: parent.verticalCenter
 
         RowLayout {
-            spacing: layoutSpacing
+            spacing: JamiTheme.wizardViewPageLayoutSpacing
 
             Layout.alignment: Qt.AlignCenter
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: backupBtn.width
 
             Label {
@@ -86,18 +120,10 @@ Rectangle {
                 font.pointSize: JamiTheme.textFontSize + 3
             }
 
-            Label {
+            BubbleLabel {
                 Layout.alignment: Qt.AlignRight
 
                 text: JamiStrings.recommended
-                color: "white"
-                padding: 8
-
-                background: Rectangle {
-                    color: JamiTheme.wizardGreenColor
-                    radius: 24
-                    anchors.fill: parent
-                }
             }
         }
 
@@ -121,7 +147,7 @@ Rectangle {
         }
 
         RowLayout {
-            spacing: layoutSpacing
+            spacing: JamiTheme.wizardViewPageLayoutSpacing
 
             Layout.alignment: Qt.AlignCenter
 
@@ -135,9 +161,7 @@ Rectangle {
                 id: passwordSwitch
                 Layout.alignment: Qt.AlignRight
 
-                onToggled: {
-                    neverShowAgainBoxClicked(checked)
-                }
+                onToggled: AppSettingsManager.setValue(Settings.NeverShowMeAgain, checked)
             }
         }
 
@@ -153,15 +177,12 @@ Rectangle {
             hoveredColor: JamiTheme.buttonTintedGreyHovered
             pressedColor: JamiTheme.buttonTintedGreyPressed
 
-            onClicked: {
-                exportBtn_Dialog.open()
-                leavePage()
-            }
+            onClicked: exportDialog.open()
         }
 
         MaterialButton {
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: backButtonMargins
+            Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
@@ -171,9 +192,7 @@ Rectangle {
             pressedColor: JamiTheme.buttonTintedGreyPressed
             outlined: true
 
-            onClicked: {
-                leavePage()
-            }
+            onClicked: WizardViewStepModel.nextStep()
         }
     }
 }
diff --git a/src/wizardview/components/ConnectToAccountManagerPage.qml b/src/wizardview/components/ConnectToAccountManagerPage.qml
index 378821f86..d7dcd89e4 100644
--- a/src/wizardview/components/ConnectToAccountManagerPage.qml
+++ b/src/wizardview/components/ConnectToAccountManagerPage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,18 +29,10 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    property alias text_usernameManagerEditAlias: usernameManagerEdit.text
-    property alias text_passwordManagerEditAlias: passwordManagerEdit.text
-    property alias text_accountManagerEditAlias: accountManagerEdit.text
-    property string errorText: ""
     property int preferredHeight: connectToAccountManagerPageColumnLayout.implicitHeight
+    property string errorText: ""
 
-    signal leavePage
-    signal createAccount
-
-    function initializeOnShowUp() {
-        clearAllTextFields()
-    }
+    signal showThisPage
 
     function clearAllTextFields() {
         connectBtn.spinnerTriggered = false
@@ -54,6 +47,19 @@ Rectangle {
         errorText = errorMessage
     }
 
+    Connections {
+        target: WizardViewStepModel
+
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.AccountCreation &&
+                    WizardViewStepModel.accountCreationOption ===
+                    WizardViewStepModel.AccountCreationOption.ConnectToAccountManager) {
+                clearAllTextFields()
+                root.showThisPage()
+            }
+        }
+    }
+
     color: JamiTheme.backgroundColor
 
     onVisibleChanged: {
@@ -64,16 +70,16 @@ Rectangle {
     ColumnLayout {
         id: connectToAccountManagerPageColumnLayout
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         anchors.horizontalCenter: parent.horizontalCenter
         anchors.verticalCenter: parent.verticalCenter
 
         RowLayout {
-            spacing: layoutSpacing
+            spacing: JamiTheme.wizardViewPageLayoutSpacing
 
             Layout.alignment: Qt.AlignCenter
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: implicitWidth
 
             Label {
@@ -82,18 +88,12 @@ Rectangle {
                 font.pointSize: JamiTheme.textFontSize + 3
             }
 
-            Label {
+            BubbleLabel {
                 Layout.alignment: Qt.AlignRight
 
                 text: JamiStrings.required
-                color: JamiTheme.requiredFieldColor
-                padding: 8
-
-                background: Rectangle {
-                    color: JamiTheme.requiredFieldBackgroundColor
-                    radius: 24
-                    anchors.fill: parent
-                }
+                textColor: JamiTheme.requiredFieldColor
+                bubbleColor: JamiTheme.requiredFieldBackgroundColor
             }
         }
 
@@ -106,7 +106,7 @@ Rectangle {
 
             selectByMouse: true
             placeholderText: JamiStrings.jamiManagementServerURL
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             borderColorMode: MaterialLineEdit.NORMAL
@@ -135,7 +135,7 @@ Rectangle {
 
             selectByMouse: true
             placeholderText: JamiStrings.username
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             borderColorMode: MaterialLineEdit.NORMAL
@@ -152,7 +152,7 @@ Rectangle {
 
             selectByMouse: true
             placeholderText: JamiStrings.password
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             echoMode: TextInput.Password
@@ -165,11 +165,11 @@ Rectangle {
             id: connectBtn
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: errorLabel.visible ? 0 : backButtonMargins
+            Layout.bottomMargin: errorLabel.visible ? 0 : JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
-            spinnerTriggeredtext: JamiStrings.generatingAccount
+            spinnerTriggeredtext: JamiStrings.creatingAccount
             normalText: JamiStrings.connect
 
             enabled: accountManagerEdit.text.length !== 0
@@ -179,7 +179,13 @@ Rectangle {
 
             onClicked: {
                 spinnerTriggered = true
-                createAccount()
+
+                WizardViewStepModel.accountCreationInfo =
+                        JamiQmlUtils.setUpAccountCreationInputPara(
+                            {username : usernameManagerEdit.text,
+                             password : passwordManagerEdit.text,
+                             manager : accountManagerEdit.text})
+                WizardViewStepModel.nextStep()
             }
         }
 
@@ -187,32 +193,25 @@ Rectangle {
             id: errorLabel
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: backButtonMargins
+            Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
 
             visible: errorText.length !== 0
             text: errorText
 
             font.pointSize: JamiTheme.textFontSize
-            color: "red"
+            color: JamiTheme.redColor
         }
     }
 
-    PushButton {
+    BackButton {
         id: backButton
 
         anchors.left: parent.left
         anchors.top: parent.top
         anchors.margins: 20
 
-        width: 35
-        height: 35
-
-        normalColor: root.color
-        imageColor: JamiTheme.primaryForegroundColor
-
-        source: JamiResources.ic_arrow_back_24dp_svg
-        toolTipText: JamiStrings.backToWelcome
+        preferredSize: JamiTheme.wizardViewPageBackButtonSize
 
-        onClicked: leavePage()
+        onClicked: WizardViewStepModel.previousStep()
     }
 }
diff --git a/src/wizardview/components/CreateAccountPage.qml b/src/wizardview/components/CreateAccountPage.qml
index 0329736b4..9156aceb4 100644
--- a/src/wizardview/components/CreateAccountPage.qml
+++ b/src/wizardview/components/CreateAccountPage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +23,7 @@ import QtQuick.Controls 2.14
 import Qt.labs.platform 1.1
 
 import net.jami.Models 1.0
+import net.jami.Adapters 1.0
 import net.jami.Constants 1.0
 
 import "../"
@@ -31,18 +33,14 @@ import "../../settingsview/components"
 Rectangle {
     id: root
 
-    property alias text_usernameEditAlias: usernameEdit.text
-    property alias nameRegistrationUIState: usernameEdit.nameRegistrationState
     property bool isRendezVous: false
-    property alias text_passwordEditAlias: passwordEdit.text
     property int preferredHeight: {
         if (createAccountStack.currentIndex === 0)
             return usernameColumnLayout.implicitHeight
         return passwordColumnLayout.implicitHeight
     }
 
-    signal createAccount
-    signal leavePage
+    signal showThisPage
 
     function initializeOnShowUp(isRdv) {
         isRendezVous = isRdv
@@ -59,34 +57,18 @@ Rectangle {
 
     color: JamiTheme.backgroundColor
 
-    onVisibleChanged: {
-        if (visible && createAccountStack.currentIndex === 0)
-            usernameEdit.focus = true
-    }
-
-    // JamiFileDialog for exporting account
-    JamiFileDialog {
-        id: exportBtn_Dialog
-
-        mode: JamiFileDialog.SaveFile
-
-        title: JamiStrings.backupAccountHere
-        folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/Desktop"
-
-        nameFilters: [qsTr("Jami archive files") + " (*.gz)", qsTr(
-                "All files") + " (*)"]
-
-        onAccepted: {
-            export_Btn_FileDialogAccepted(true, file)
-        }
-
-        onRejected: {
-            export_Btn_FileDialogAccepted(false, folder)
-        }
-
-        onVisibleChanged: {
-            if (!visible) {
-                rejected()
+    Connections {
+        target: WizardViewStepModel
+
+        function onMainStepChanged() {
+            var currentMainStep = WizardViewStepModel.mainStep
+            if (currentMainStep === WizardViewStepModel.MainSteps.NameRegistration) {
+                createAccountStack.currentIndex = nameRegistrationPage.stackIndex
+                initializeOnShowUp(WizardViewStepModel.accountCreationOption ===
+                                   WizardViewStepModel.AccountCreationOption.CreateRendezVous)
+                root.showThisPage()
+            } else if (currentMainStep === WizardViewStepModel.MainSteps.SetPassword) {
+                createAccountStack.currentIndex = passwordSetupPage.stackIndex
             }
         }
     }
@@ -96,45 +78,40 @@ Rectangle {
 
         anchors.fill: parent
 
-        currentIndex: 0
-
         Rectangle {
+            id: nameRegistrationPage
+
+            property int stackIndex: 0
+
             color: JamiTheme.backgroundColor
 
             ColumnLayout {
                 id: usernameColumnLayout
 
-                spacing: layoutSpacing
+                spacing: JamiTheme.wizardViewPageLayoutSpacing
 
                 anchors.centerIn: parent
 
                 width: root.width
 
                 RowLayout {
-                    spacing: layoutSpacing
+                    spacing: JamiTheme.wizardViewPageLayoutSpacing
 
                     Layout.alignment: Qt.AlignCenter
-                    Layout.topMargin: backButtonMargins
+                    Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
                     Layout.preferredWidth: usernameEdit.width
 
                     Label {
-                        text: isRendezVous ? JamiStrings.chooseNameRV : qsTr("Choose a username for your account")
+                        text: isRendezVous ? JamiStrings.chooseUsernameForRV :
+                                             JamiStrings.chooseUsernameForAccount
                         color: JamiTheme.textColor
                         font.pointSize: JamiTheme.textFontSize + 3
                     }
 
-                    Label {
+                    BubbleLabel {
                         Layout.alignment: Qt.AlignRight
 
                         text: JamiStrings.recommended
-                        color: JamiTheme.whiteColor
-                        padding: 8
-
-                        background: Rectangle {
-                            color: JamiTheme.wizardGreenColor
-                            radius: 24
-                            anchors.fill: parent
-                        }
                     }
                 }
 
@@ -146,7 +123,10 @@ Rectangle {
                     Layout.preferredWidth:  chooseUsernameButton.width
                     Layout.alignment: Qt.AlignHCenter
 
-                    placeholderText: isRendezVous ? qsTr("Choose a name") : qsTr("Choose your username")
+                    focus: visible
+
+                    placeholderText: isRendezVous ? JamiStrings.chooseAName :
+                                                    JamiStrings.chooseYourUserName
                 }
 
                 Label {
@@ -155,19 +135,21 @@ Rectangle {
                     visible: text.length !==0
 
                     text: {
-                        switch(nameRegistrationUIState){
+                        switch(usernameEdit.nameRegistrationState){
                         case UsernameLineEdit.NameRegistrationState.BLANK:
                         case UsernameLineEdit.NameRegistrationState.SEARCHING:
                         case UsernameLineEdit.NameRegistrationState.FREE:
                             return ""
                         case UsernameLineEdit.NameRegistrationState.INVALID:
-                            return isRendezVous ? qsTr("Invalid name") : qsTr("Invalid username")
+                            return isRendezVous ? JamiStrings.invalidName :
+                                                  JamiStrings.invalidUsername
                         case UsernameLineEdit.NameRegistrationState.TAKEN:
-                            return isRendezVous ? qsTr("Name already taken") : qsTr("Username already taken")
+                            return isRendezVous ? JamiStrings.nameAlreadyTaken :
+                                                  JamiStrings.usernameAlreadyTaken
                         }
                     }
                     font.pointSize: JamiTheme.textFontSize
-                    color: "red"
+                    color: JamiTheme.redColor
                 }
 
                 MaterialButton {
@@ -179,17 +161,14 @@ Rectangle {
 
                     fontCapitalization: Font.AllUppercase
                     text: isRendezVous ? JamiStrings.chooseName : JamiStrings.chooseUsername
-                    enabled: nameRegistrationUIState === UsernameLineEdit.NameRegistrationState.FREE
-                    color: nameRegistrationUIState === UsernameLineEdit.NameRegistrationState.FREE ?
+                    enabled: usernameEdit.nameRegistrationState === UsernameLineEdit.NameRegistrationState.FREE
+                    color: usernameEdit.nameRegistrationState === UsernameLineEdit.NameRegistrationState.FREE ?
                                JamiTheme.wizardBlueButtons :
                                JamiTheme.buttonTintedGreyInactive
                     hoveredColor: JamiTheme.buttonTintedBlueHovered
                     pressedColor: JamiTheme.buttonTintedBluePressed
 
-                    onClicked: {
-                        if (nameRegistrationUIState === UsernameLineEdit.NameRegistrationState.FREE)
-                            createAccountStack.currentIndex = createAccountStack.currentIndex + 1
-                    }
+                    onClicked: WizardViewStepModel.nextStep()
                 }
 
                 MaterialButton {
@@ -207,39 +186,42 @@ Rectangle {
 
                     onClicked: {
                         usernameEdit.clear()
-                        createAccountStack.currentIndex =
-                                createAccountStack.currentIndex + 1
+                        WizardViewStepModel.nextStep()
                     }
                 }
 
                 AccountCreationStepIndicator {
-                    Layout.topMargin: backButtonMargins
-                    Layout.bottomMargin: backButtonMargins
+                    Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
+                    Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
                     Layout.alignment: Qt.AlignHCenter
 
-                    spacing: layoutSpacing
-                    steps: 3
+                    spacing: JamiTheme.wizardViewPageLayoutSpacing
+                    steps: 2
                     currentStep: 1
                 }
             }
         }
 
         Rectangle {
+            id: passwordSetupPage
+
+            property int stackIndex: 1
+
             color: JamiTheme.backgroundColor
 
             ColumnLayout {
                 id: passwordColumnLayout
 
-                spacing: layoutSpacing
+                spacing: JamiTheme.wizardViewPageLayoutSpacing
 
                 anchors.centerIn: parent
                 width: root.width
 
                 RowLayout {
-                    spacing: layoutSpacing
+                    spacing: JamiTheme.wizardViewPageLayoutSpacing
 
                     Layout.alignment: Qt.AlignCenter
-                    Layout.topMargin: backButtonMargins
+                    Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
                     Layout.preferredWidth: usernameEdit.width
 
                     Label {
@@ -253,22 +235,15 @@ Rectangle {
                         id: passwordSwitch
 
                         Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
-                        Layout.leftMargin:  -layoutSpacing
+                        Layout.leftMargin: -JamiTheme.wizardViewPageLayoutSpacing
                         Layout.topMargin: 5
                     }
 
-                    Label {
+                    BubbleLabel {
                         Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
 
                         text: JamiStrings.optional
-                        color: "white"
-                        padding: 8
-
-                        background: Rectangle {
-                            color: JamiTheme.wizardBlueButtons
-                            radius: 24
-                            anchors.fill: parent
-                        }
+                        bubbleColor: JamiTheme.wizardBlueButtons
                     }
                 }
 
@@ -279,12 +254,13 @@ Rectangle {
                     Layout.preferredWidth: createAccountButton.width
                     Layout.alignment: Qt.AlignHCenter
 
+                    focus: visible
                     visible: passwordSwitch.checked
 
                     selectByMouse: true
                     echoMode: TextInput.Password
                     placeholderText: JamiStrings.password
-                    font.pointSize: 9
+                    font.pointSize: JamiTheme.textFontSize
                     font.kerning: true
                 }
 
@@ -300,7 +276,7 @@ Rectangle {
                     selectByMouse: true
                     echoMode: TextInput.Password
                     placeholderText: JamiStrings.confirmPassword
-                    font.pointSize: 9
+                    font.pointSize: JamiTheme.textFontSize
                     font.kerning: true
                 }
 
@@ -337,45 +313,38 @@ Rectangle {
                     pressedColor: JamiTheme.buttonTintedBluePressed
 
                     onClicked: {
-                        createAccount()
-                        createAccountStack.currentIndex += 1
+                        WizardViewStepModel.accountCreationInfo =
+                                JamiQmlUtils.setUpAccountCreationInputPara(
+                                    {isRendezVous : WizardViewStepModel.accountCreationOption ===
+                                                    WizardViewStepModel.AccountCreationOption.CreateRendezVous,
+                                     password : passwordEdit.text,
+                                     registeredName : usernameEdit.text})
+                        WizardViewStepModel.nextStep()
                     }
                 }
 
                 AccountCreationStepIndicator {
-                    Layout.topMargin: backButtonMargins
-                    Layout.bottomMargin: backButtonMargins
+                    Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
+                    Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
                     Layout.alignment: Qt.AlignHCenter
 
-                    spacing: layoutSpacing
-                    steps: 3
+                    spacing: JamiTheme.wizardViewPageLayoutSpacing
+                    steps: 2
                     currentStep: 2
                 }
             }
         }
     }
 
-    PushButton {
+    BackButton {
         id: backButton
 
         anchors.left: parent.left
         anchors.top: parent.top
-        anchors.margins: backButtonMargins
+        anchors.margins: JamiTheme.wizardViewPageBackButtonMargins
 
-        width: 35
-        height: 35
+        preferredSize: JamiTheme.wizardViewPageBackButtonSize
 
-        normalColor: root.color
-        imageColor: JamiTheme.primaryForegroundColor
-
-        source: JamiResources.ic_arrow_back_24dp_svg
-        toolTipText: JamiStrings.back
-
-        onClicked: {
-            if (createAccountStack.currentIndex == 0)
-                leavePage()
-            else
-                createAccountStack.currentIndex -= 1
-        }
+        onClicked: WizardViewStepModel.previousStep()
     }
 }
diff --git a/src/wizardview/components/CreateSIPAccountPage.qml b/src/wizardview/components/CreateSIPAccountPage.qml
index bb3ed416a..c8bdb197d 100644
--- a/src/wizardview/components/CreateSIPAccountPage.qml
+++ b/src/wizardview/components/CreateSIPAccountPage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,6 +21,7 @@ import QtQuick 2.14
 import QtQuick.Layouts 1.14
 import QtQuick.Controls 2.14
 
+import net.jami.Models 1.0
 import net.jami.Constants 1.0
 
 import "../../commoncomponents"
@@ -27,18 +29,9 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    property alias text_sipServernameEditAlias: sipServernameEdit.text
-    property alias text_sipProxyEditAlias: sipProxyEdit.text
-    property alias text_sipUsernameEditAlias: sipUsernameEdit.text
-    property alias text_sipPasswordEditAlias: sipPasswordEdit.text
     property int preferredHeight: createSIPAccountPageColumnLayout.implicitHeight
 
-    signal createAccount
-    signal leavePage
-
-    function initializeOnShowUp() {
-        clearAllTextFields()
-    }
+    signal showThisPage
 
     function clearAllTextFields() {
         sipUsernameEdit.clear()
@@ -48,25 +41,33 @@ Rectangle {
         sipUsernameEdit.clear()
     }
 
-    color: JamiTheme.backgroundColor
+    Connections {
+        target: WizardViewStepModel
 
-    onVisibleChanged: {
-        if (visible)
-            sipServernameEdit.focus = true
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.AccountCreation &&
+                    WizardViewStepModel.accountCreationOption ===
+                    WizardViewStepModel.AccountCreationOption.CreateSipAccount) {
+                clearAllTextFields()
+                root.showThisPage()
+            }
+        }
     }
 
+    color: JamiTheme.backgroundColor
+
     ColumnLayout {
         id: createSIPAccountPageColumnLayout
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         anchors.centerIn: parent
 
         RowLayout {
-            spacing: layoutSpacing
+            spacing: JamiTheme.wizardViewPageLayoutSpacing
 
             Layout.alignment: Qt.AlignCenter
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: createAccountButton.width
 
             Label {
@@ -75,18 +76,11 @@ Rectangle {
                 font.pointSize: JamiTheme.textFontSize + 3
             }
 
-            Label {
+            BubbleLabel {
                 Layout.alignment: Qt.AlignRight
 
                 text: JamiStrings.optional
-                color: JamiTheme.whiteColor
-                padding: 8
-
-                background: Rectangle {
-                    color: JamiTheme.wizardBlueButtons
-                    radius: 24
-                    anchors.fill: parent
-                }
+                bubbleColor: JamiTheme.wizardBlueButtons
             }
         }
 
@@ -97,9 +91,11 @@ Rectangle {
             Layout.preferredHeight: fieldLayoutHeight
             Layout.preferredWidth: createAccountButton.width
 
+            focus: visible
+
             selectByMouse: true
             placeholderText: JamiStrings.server
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
         }
 
@@ -112,7 +108,7 @@ Rectangle {
 
             selectByMouse: true
             placeholderText: JamiStrings.proxy
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
         }
 
@@ -125,7 +121,7 @@ Rectangle {
 
             selectByMouse: true
             placeholderText: JamiStrings.username
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
         }
 
@@ -139,7 +135,7 @@ Rectangle {
             selectByMouse: true
             echoMode: TextInput.Password
             placeholderText: JamiStrings.password
-            font.pointSize: 9
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
         }
 
@@ -147,7 +143,7 @@ Rectangle {
             id: createAccountButton
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: backButtonMargins
+            Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
@@ -157,27 +153,26 @@ Rectangle {
             pressedColor: JamiTheme.buttonTintedBluePressed
 
             onClicked: {
-                createAccount()
+                WizardViewStepModel.accountCreationInfo =
+                        JamiQmlUtils.setUpAccountCreationInputPara(
+                            {hostname : sipServernameEdit.text,
+                             username : sipUsernameEdit.text,
+                             password : sipPasswordEdit.text,
+                             proxy : sipProxyEdit.text})
+                WizardViewStepModel.nextStep()
             }
         }
     }
 
-    PushButton {
+    BackButton {
         id: backButton
 
         anchors.left: parent.left
         anchors.top: parent.top
         anchors.margins: 20
 
-        width: 35
-        height: 35
-
-        normalColor: root.color
-        imageColor: JamiTheme.primaryForegroundColor
-
-        source: JamiResources.ic_arrow_back_24dp_svg
-        toolTipText: JamiStrings.backToWelcome
+        preferredSize: JamiTheme.wizardViewPageBackButtonSize
 
-        onClicked: leavePage()
+        onClicked: WizardViewStepModel.previousStep()
     }
 }
diff --git a/src/wizardview/components/ImportFromBackupPage.qml b/src/wizardview/components/ImportFromBackupPage.qml
index a7e5f67e3..d53d50809 100644
--- a/src/wizardview/components/ImportFromBackupPage.qml
+++ b/src/wizardview/components/ImportFromBackupPage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,15 +31,13 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    property alias text_passwordFromBackupEditAlias: passwordFromBackupEdit.text
-    property string fileImportBtnText: JamiStrings.archive
     property int preferredHeight: importFromBackupPageColumnLayout.implicitHeight
 
+    property string fileImportBtnText: JamiStrings.archive
     property string filePath: ""
     property string errorText: ""
 
-    signal leavePage
-    signal importAccount
+    signal showThisPage
 
     function clearAllTextFields() {
         connectBtn.spinnerTriggered = false
@@ -52,16 +51,29 @@ Rectangle {
         connectBtn.spinnerTriggered = false
     }
 
+    Connections {
+        target: WizardViewStepModel
+
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.AccountCreation &&
+                    WizardViewStepModel.accountCreationOption ===
+                    WizardViewStepModel.AccountCreationOption.ImportFromBackup) {
+                clearAllTextFields()
+                root.showThisPage()
+            }
+        }
+    }
+
     color: JamiTheme.backgroundColor
 
     JamiFileDialog {
-        id: importFromFile_Dialog
+        id: importFromFileDialog
 
         mode: JamiFileDialog.OpenFile
         title: JamiStrings.openFile
         folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/Desktop"
 
-        nameFilters: [qsTr("Jami archive files") + " (*.gz)", qsTr("All files") + " (*)"]
+        nameFilters: [JamiStrings.jamiArchiveFiles + " (*.gz)", JamiStrings.allFiles + " (*)"]
 
         onAccepted: {
             filePath = file
@@ -76,16 +88,16 @@ Rectangle {
     ColumnLayout {
         id: importFromBackupPageColumnLayout
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         anchors.horizontalCenter: parent.horizontalCenter
         anchors.verticalCenter: parent.verticalCenter
 
         Text {
             Layout.alignment: Qt.AlignCenter
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
 
-            text: qsTr("Import from backup")
+            text: JamiStrings.importFromBackup
             color: JamiTheme.textColor
             font.pointSize: JamiTheme.menuFontSize
         }
@@ -106,14 +118,14 @@ Rectangle {
 
             onClicked: {
                 errorText = ""
-                importFromFile_Dialog.open()
+                importFromFileDialog.open()
             }
         }
 
         Text {
             // For multiline text, recursive rearrange warning will show up when
             // directly assigning contentHeight to Layout.preferredHeight
-            property int preferredHeight: layoutSpacing
+            property int preferredHeight: JamiTheme.wizardViewPageLayoutSpacing
 
             Layout.alignment: Qt.AlignCenter
             Layout.preferredWidth: fileImportBtn.width
@@ -137,9 +149,11 @@ Rectangle {
             Layout.preferredWidth: connectBtn.width
             Layout.alignment: Qt.AlignCenter
 
+            focus: visible
+
             selectByMouse: true
-            placeholderText: qsTr("Password")
-            font.pointSize: 9
+            placeholderText: JamiStrings.password
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             echoMode: TextInput.Password
@@ -152,11 +166,11 @@ Rectangle {
             id: connectBtn
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: errorLabel.visible ? 0 : backButtonMargins
+            Layout.bottomMargin: errorLabel.visible ? 0 : JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
-            spinnerTriggeredtext: qsTr("Generating account…")
+            spinnerTriggeredtext: JamiStrings.generatingAccount
             normalText: JamiStrings.connectFromBackup
 
             enabled: {
@@ -169,7 +183,12 @@ Rectangle {
 
             onClicked: {
                 spinnerTriggered = true
-                importAccount()
+
+                WizardViewStepModel.accountCreationInfo =
+                        JamiQmlUtils.setUpAccountCreationInputPara(
+                            {archivePath : UtilsAdapter.getAbsPath(filePath),
+                             password : passwordFromBackupEdit.text})
+                WizardViewStepModel.nextStep()
             }
         }
 
@@ -177,32 +196,25 @@ Rectangle {
             id: errorLabel
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: backButtonMargins
+            Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
 
             visible: errorText.length !== 0
 
             text: errorText
             font.pointSize: JamiTheme.textFontSize
-            color: "red"
+            color: JamiTheme.redColor
         }
     }
 
-    PushButton {
+    BackButton {
         id: backButton
 
         anchors.left: parent.left
         anchors.top: parent.top
         anchors.margins: 20
 
-        width: 35
-        height: 35
-
-        normalColor: root.color
-        imageColor: JamiTheme.primaryForegroundColor
-
-        source: JamiResources.ic_arrow_back_24dp_svg
-        toolTipText: qsTr("Back to welcome page")
+        preferredSize: JamiTheme.wizardViewPageBackButtonSize
 
-        onClicked: leavePage()
+        onClicked: WizardViewStepModel.previousStep()
     }
 }
diff --git a/src/wizardview/components/ImportFromDevicePage.qml b/src/wizardview/components/ImportFromDevicePage.qml
index 2c26e271d..c6feb9f31 100644
--- a/src/wizardview/components/ImportFromDevicePage.qml
+++ b/src/wizardview/components/ImportFromDevicePage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,13 +29,10 @@ import "../../commoncomponents"
 Rectangle {
     id: root
 
-    property alias text_pinFromDeviceAlias: pinFromDevice.text
-    property alias text_passwordFromDeviceAlias: passwordFromDevice.text
     property string errorText: ""
     property int preferredHeight: importFromDevicePageColumnLayout.implicitHeight
 
-    signal leavePage
-    signal importAccount
+    signal showThisPage
 
     function initializeOnShowUp() {
         clearAllTextFields()
@@ -51,17 +49,23 @@ Rectangle {
         connectBtn.spinnerTriggered = false
     }
 
-    color: JamiTheme.backgroundColor
+    Connections {
+        target: WizardViewStepModel
 
-    onVisibleChanged: {
-        if (visible)
-            pinFromDevice.focus = true
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.AccountCreation &&
+                    WizardViewStepModel.accountCreationOption ===
+                    WizardViewStepModel.AccountCreationOption.ImportFromDevice)
+                root.showThisPage()
+        }
     }
 
+    color: JamiTheme.backgroundColor
+
     ColumnLayout {
         id: importFromDevicePageColumnLayout
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         // Prevent possible anchor loop detected on centerIn.
         anchors.horizontalCenter: parent.horizontalCenter
@@ -69,7 +73,7 @@ Rectangle {
 
         Text {
             Layout.alignment: Qt.AlignCenter
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
 
             text: JamiStrings.mainAccountPassword
             color: JamiTheme.textColor
@@ -84,8 +88,8 @@ Rectangle {
             Layout.alignment: Qt.AlignCenter
 
             selectByMouse: true
-            placeholderText: qsTr("Password")
-            font.pointSize: 9
+            placeholderText: JamiStrings.password
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             echoMode: TextInput.Password
@@ -95,7 +99,8 @@ Rectangle {
         }
 
         Text {
-            property int preferredHeight: layoutSpacing
+            property int preferredHeight: JamiTheme.wizardViewPageLayoutSpacing
+
 
             Layout.alignment: Qt.AlignCenter
             Layout.preferredWidth: connectBtn.width
@@ -119,9 +124,11 @@ Rectangle {
             Layout.preferredWidth: connectBtn.width
             Layout.alignment: Qt.AlignCenter
 
+            focus: visible
+
             selectByMouse: true
-            placeholderText: qsTr("PIN")
-            font.pointSize: 9
+            placeholderText: JamiStrings.pin
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             borderColorMode: MaterialLineEdit.NORMAL
@@ -133,18 +140,23 @@ Rectangle {
             id: connectBtn
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: errorLabel.visible ? 0 : backButtonMargins
+            Layout.bottomMargin: errorLabel.visible ? 0 : JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
-            spinnerTriggeredtext: qsTr("Generating account…")
+            spinnerTriggeredtext: JamiStrings.generatingAccount
             normalText: JamiStrings.connectFromAnotherDevice
 
             enabled: pinFromDevice.text.length !== 0 && !spinnerTriggered
 
             onClicked: {
                 spinnerTriggered = true
-                importAccount()
+
+                WizardViewStepModel.accountCreationInfo =
+                        JamiQmlUtils.setUpAccountCreationInputPara(
+                            {archivePin : pinFromDevice.text,
+                             password : passwordFromDevice.text})
+                WizardViewStepModel.nextStep()
             }
         }
 
@@ -152,33 +164,26 @@ Rectangle {
             id: errorLabel
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: backButtonMargins
+            Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
 
             visible: errorText.length !== 0
 
             text: errorText
 
             font.pointSize: JamiTheme.textFontSize
-            color: "red"
+            color: JamiTheme.redColor
         }
     }
 
-    PushButton {
+    BackButton {
         id: backButton
 
         anchors.left: parent.left
         anchors.top: parent.top
         anchors.margins: 20
 
-        width: 35
-        height: 35
-
-        normalColor: root.color
-        imageColor: JamiTheme.primaryForegroundColor
-
-        source: JamiResources.ic_arrow_back_24dp_svg
-        toolTipText: qsTr("Back to welcome page")
+        preferredSize: JamiTheme.wizardViewPageBackButtonSize
 
-        onClicked: leavePage()
+        onClicked: WizardViewStepModel.previousStep()
     }
 }
diff --git a/src/wizardview/components/ProfilePage.qml b/src/wizardview/components/ProfilePage.qml
index a92c16f83..e02be77d3 100644
--- a/src/wizardview/components/ProfilePage.qml
+++ b/src/wizardview/components/ProfilePage.qml
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,6 +24,7 @@ import QtQuick.Controls 2.14
 import net.jami.Adapters 1.0
 import net.jami.Constants 1.0
 import net.jami.Helpers 1.0
+import net.jami.Models 1.0
 
 import "../../commoncomponents"
 
@@ -32,13 +34,8 @@ Rectangle {
     // trigger a default avatar prior to account generation
     property string createdAccountId: "dummy"
     property int preferredHeight: profilePageColumnLayout.implicitHeight
-    property bool showBottom: false
-    property alias displayName: aliasEdit.text
-    property bool isRdv: false
-    property alias avatarBooth: setAvatarWidget
 
-    signal leavePage
-    signal saveProfile
+    signal showThisPage
 
     function initializeOnShowUp() {
         createdAccountId = "dummy"
@@ -50,46 +47,52 @@ Rectangle {
         aliasEdit.clear()
     }
 
-    function readyToSaveDetails() {
-        saveProfileBtn.spinnerTriggered = false
-    }
-
     color: JamiTheme.backgroundColor
 
+    Connections {
+        target: WizardViewStepModel
+
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.Profile) {
+                initializeOnShowUp()
+                root.showThisPage()
+            }
+        }
+
+        function onAccountIsReady(accountId) {
+            saveProfileBtn.spinnerTriggered = false
+            createdAccountId = accountId
+            aliasEdit.forceActiveFocus()
+        }
+    }
+
     ColumnLayout {
         id: profilePageColumnLayout
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         width: parent.width
         anchors.horizontalCenter: parent.horizontalCenter
         anchors.verticalCenter: parent.verticalCenter
 
         RowLayout {
-            spacing: layoutSpacing
+            spacing: JamiTheme.wizardViewPageLayoutSpacing
 
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: saveProfileBtn.width
             Layout.alignment: Qt.AlignCenter
 
             Label {
-                text: qsTr("Profile is only shared with contacts")
+                text: JamiStrings.profileSharedWithContacts
                 color: JamiTheme.textColor
                 font.pointSize: JamiTheme.textFontSize + 3
             }
 
-            Label {
+            BubbleLabel {
                 Layout.alignment: Qt.AlignRight
 
-                text: qsTr("Optional")
-                color: JamiTheme.whiteColor
-                padding: 8
-
-                background: Rectangle {
-                    color: JamiTheme.wizardBlueButtons
-                    radius: 24
-                    anchors.fill: parent
-                }
+                text: JamiStrings.optional
+                bubbleColor: JamiTheme.wizardBlueButtons
             }
         }
 
@@ -116,9 +119,17 @@ Rectangle {
             Layout.preferredWidth: fieldLayoutWidth
             Layout.alignment: Qt.AlignCenter
 
+            focus: visible
+
             selectByMouse: true
-            placeholderText: isRdv ? JamiStrings.enterRVName : qsTr("Enter your name")
-            font.pointSize: 9
+            placeholderText: {
+                if (WizardViewStepModel.accountCreationOption !==
+                        WizardViewStepModel.AccountCreationOption.CreateRendezVous)
+                    return JamiStrings.enterYourName
+                else
+                    return JamiStrings.enterRVName
+            }
+            font.pointSize: JamiTheme.textFontSize
             font.kerning: true
 
             borderColorMode: MaterialLineEdit.NORMAL
@@ -147,8 +158,18 @@ Rectangle {
 
             enabled: !spinnerTriggered
             normalText: JamiStrings.saveProfile
-            spinnerTriggeredtext: root.isRdv ? JamiStrings.generatingRV : qsTr("Generating account…")
-            onClicked: saveProfile()
+            spinnerTriggeredtext: {
+                if (WizardViewStepModel.accountCreationOption ===
+                        WizardViewStepModel.AccountCreationOption.CreateRendezVous)
+                    return JamiStrings.generatingRV
+                else
+                    return JamiStrings.creatingAccount
+            }
+
+            onClicked: {
+                AccountAdapter.setCurrAccDisplayName(aliasEdit.text)
+                WizardViewStepModel.nextStep()
+            }
         }
 
         MaterialButton {
@@ -166,18 +187,8 @@ Rectangle {
             onClicked: {
                 AccountAdapter.setCurrentAccountAvatarBase64()
                 aliasEdit.clear()
-                saveProfile()
+                WizardViewStepModel.nextStep()
             }
         }
-
-        AccountCreationStepIndicator {
-            Layout.topMargin: backButtonMargins
-            Layout.bottomMargin: backButtonMargins
-            Layout.alignment: Qt.AlignHCenter
-
-            spacing: layoutSpacing
-            steps: 3
-            currentStep: 3
-        }
     }
 }
diff --git a/src/wizardview/components/WelcomePage.qml b/src/wizardview/components/WelcomePage.qml
index 7338c77d4..197efdeb9 100644
--- a/src/wizardview/components/WelcomePage.qml
+++ b/src/wizardview/components/WelcomePage.qml
@@ -1,7 +1,8 @@
 /*
- * Copyright (C) 2020 by Savoir-faire Linux
+ * Copyright (C) 2021 by Savoir-faire Linux
  * Author: Yang Wang <yang.wang@savoirfairelinux.com>
  * Author: Sébastien blin <sebastien.blin@savoirfairelinux.com>
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -33,32 +34,40 @@ Rectangle {
 
     property int preferredHeight: welcomePageColumnLayout.implicitHeight
 
-    signal welcomePageRedirectPage(int toPageIndex)
-    signal leavePage
     signal scrollToBottom
+    signal showThisPage
 
-    color: "transparent"
+    color: JamiTheme.transparentColor
+
+    Connections {
+        target: WizardViewStepModel
+
+        function onMainStepChanged() {
+            if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.Initial)
+                root.showThisPage()
+        }
+    }
 
     ColumnLayout {
         id: welcomePageColumnLayout
 
         anchors.centerIn: parent
 
-        spacing: layoutSpacing
+        spacing: JamiTheme.wizardViewPageLayoutSpacing
 
         Text {
             id: welcomeLabel
 
             Layout.alignment: Qt.AlignCenter
-            Layout.topMargin: backButtonMargins
+            Layout.topMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredHeight: contentHeight
 
-            text: qsTr("Welcome to")
+            text: JamiStrings.welcomeTo
             color: JamiTheme.textColor
             horizontalAlignment: Text.AlignHCenter
             verticalAlignment: Text.AlignVCenter
 
-            font.pointSize: 30
+            font.pointSize: JamiTheme.welcomeLabelPointSize
             font.kerning: true
         }
 
@@ -66,8 +75,8 @@ Rectangle {
             id: welcomeLogo
 
             Layout.alignment: Qt.AlignCenter
-            Layout.preferredWidth: 330
-            Layout.preferredHeight: 110
+            Layout.preferredWidth: JamiTheme.welcomeLogoWidth
+            Layout.preferredHeight: JamiTheme.welcomeLogoHeight
 
             source: JamiTheme.darkTheme ?
                         JamiResources.logo_jami_standard_coul_white_svg :
@@ -81,17 +90,16 @@ Rectangle {
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
-            text: JamiStrings.createNewJA
+            text: JamiStrings.createAJamiAccount
             fontCapitalization: Font.AllUppercase
-            toolTipText: qsTr("Create new Jami account")
+            toolTipText: JamiStrings.createNewJamiAccount
             source: JamiResources.default_avatar_overlay_svg
             color: JamiTheme.buttonTintedBlue
             hoveredColor: JamiTheme.buttonTintedBlueHovered
             pressedColor: JamiTheme.buttonTintedBluePressed
 
-            onClicked: {
-                welcomePageRedirectPage(1)
-            }
+            onClicked: WizardViewStepModel.startAccountCreationFlow(
+                           WizardViewStepModel.AccountCreationOption.CreateJamiAccount)
         }
 
         MaterialButton {
@@ -109,9 +117,8 @@ Rectangle {
             hoveredColor: JamiTheme.buttonTintedBlueHovered
             pressedColor: JamiTheme.buttonTintedBluePressed
 
-            onClicked: {
-                welcomePageRedirectPage(8)
-            }
+            onClicked: WizardViewStepModel.startAccountCreationFlow(
+                           WizardViewStepModel.AccountCreationOption.CreateRendezVous)
         }
 
         MaterialButton {
@@ -123,15 +130,14 @@ Rectangle {
 
             text: JamiStrings.linkFromAnotherDevice
             fontCapitalization: Font.AllUppercase
-            toolTipText: qsTr("Import account from other device")
+            toolTipText: JamiStrings.importAccountFromOtherDevice
             source: JamiResources.devices_24dp_svg
             color: JamiTheme.buttonTintedBlue
             hoveredColor: JamiTheme.buttonTintedBlueHovered
             pressedColor: JamiTheme.buttonTintedBluePressed
 
-            onClicked: {
-                welcomePageRedirectPage(5)
-            }
+            onClicked: WizardViewStepModel.startAccountCreationFlow(
+                           WizardViewStepModel.AccountCreationOption.ImportFromDevice)
         }
 
         MaterialButton {
@@ -143,22 +149,22 @@ Rectangle {
 
             text: JamiStrings.connectFromBackup
             fontCapitalization: Font.AllUppercase
-            toolTipText: qsTr("Import account from backup file")
+            toolTipText: JamiStrings.importAccountFromBackup
             source: JamiResources.backup_24dp_svg
             color: JamiTheme.buttonTintedBlue
             hoveredColor: JamiTheme.buttonTintedBlueHovered
             pressedColor: JamiTheme.buttonTintedBluePressed
 
-            onClicked: {
-                welcomePageRedirectPage(3)
-            }
+            onClicked: WizardViewStepModel.startAccountCreationFlow(
+                           WizardViewStepModel.AccountCreationOption.ImportFromBackup)
         }
 
         MaterialButton {
             id: showAdvancedButton
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: newSIPAccountButton.visible ? 0 : backButtonMargins
+            Layout.bottomMargin: newSIPAccountButton.visible ?
+                                     0 : JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
@@ -172,10 +178,6 @@ Rectangle {
 
             hoverEnabled: true
 
-            ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
-            ToolTip.visible: hovered
-            ToolTip.text: JamiStrings.showAdvancedFeatures
-
             onClicked: {
                 connectAccountManagerButton.visible = !connectAccountManagerButton.visible
                 newSIPAccountButton.visible = !newSIPAccountButton.visible
@@ -199,16 +201,15 @@ Rectangle {
             hoveredColor: JamiTheme.buttonTintedBlueHovered
             pressedColor: JamiTheme.buttonTintedBluePressed
 
-            onClicked: {
-                welcomePageRedirectPage(6)
-            }
+            onClicked: WizardViewStepModel.startAccountCreationFlow(
+                           WizardViewStepModel.AccountCreationOption.ConnectToAccountManager)
         }
 
         MaterialButton {
             id: newSIPAccountButton
 
             Layout.alignment: Qt.AlignCenter
-            Layout.bottomMargin: backButtonMargins
+            Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
             Layout.preferredWidth: preferredWidth
             Layout.preferredHeight: preferredHeight
 
@@ -216,26 +217,25 @@ Rectangle {
 
             text: JamiStrings.addSIPAccount
             fontCapitalization: Font.AllUppercase
-            toolTipText: qsTr("Create new SIP account")
+            toolTipText: JamiStrings.createNewSipAccount
             source: JamiResources.default_avatar_overlay_svg
             color: JamiTheme.buttonTintedBlue
             hoveredColor: JamiTheme.buttonTintedBlueHovered
             pressedColor: JamiTheme.buttonTintedBluePressed
 
-            onClicked: {
-                welcomePageRedirectPage(2)
-            }
+            onClicked: WizardViewStepModel.startAccountCreationFlow(
+                           WizardViewStepModel.AccountCreationOption.CreateSipAccount)
         }
 
         onHeightChanged: scrollToBottom()
     }
 
-    PushButton {
+    BackButton {
         id: backButton
 
         anchors.left: parent.left
         anchors.top: parent.top
-        anchors.margins: backButtonMargins
+        anchors.margins: JamiTheme.wizardViewPageBackButtonMargins
 
         Connections {
             target: LRCInstance
@@ -245,17 +245,10 @@ Rectangle {
             }
         }
 
-        width: 35
-        height: 35
+        preferredSize: JamiTheme.wizardViewPageBackButtonSize
 
         visible: UtilsAdapter.getAccountListSize()
 
-        normalColor: root.color
-        imageColor: JamiTheme.primaryForegroundColor
-
-        source: JamiResources.ic_arrow_back_24dp_svg
-        toolTipText: JamiStrings.back
-
-        onClicked: leavePage()
+        onClicked: WizardViewStepModel.previousStep()
     }
 }
diff --git a/src/wizardviewstepmodel.cpp b/src/wizardviewstepmodel.cpp
new file mode 100644
index 000000000..7efe12e59
--- /dev/null
+++ b/src/wizardviewstepmodel.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 by Savoir-faire Linux
+ * Author: Mingrui Zhang   <mingrui.zhang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "wizardviewstepmodel.h"
+
+#include "accountadapter.h"
+#include "appsettingsmanager.h"
+
+WizardViewStepModel::WizardViewStepModel(LRCInstance* lrcInstance,
+                                         AccountAdapter* accountAdapter,
+                                         AppSettingsManager* appSettingsManager,
+                                         QObject* parent)
+    : QObject(parent)
+    , lrcInstance_(lrcInstance)
+    , accountAdapter_(accountAdapter)
+    , appSettingsManager_(appSettingsManager)
+{
+    reset();
+
+    connect(accountAdapter_, &AccountAdapter::accountAdded, [this](QString accountId, int index) {
+        accountAdapter_->changeAccount(index);
+
+        auto accountCreationOption = get_accountCreationOption();
+        if (accountCreationOption == AccountCreationOption::ConnectToAccountManager
+            || accountCreationOption == AccountCreationOption::ImportFromBackup
+            || accountCreationOption == AccountCreationOption::ImportFromDevice)
+            set_mainStep(MainSteps::Profile);
+
+        Q_EMIT accountIsReady(accountId);
+    });
+}
+
+void
+WizardViewStepModel::startAccountCreationFlow(AccountCreationOption accountCreationOption)
+{
+    set_accountCreationOption(accountCreationOption);
+    if (accountCreationOption == AccountCreationOption::CreateJamiAccount
+        || accountCreationOption == AccountCreationOption::CreateRendezVous)
+        set_mainStep(MainSteps::NameRegistration);
+    else
+        set_mainStep(MainSteps::AccountCreation);
+}
+
+void
+WizardViewStepModel::nextStep()
+{
+    auto accountCreationOption = get_accountCreationOption();
+    if (accountCreationOption == AccountCreationOption::None)
+        return;
+
+    switch (get_mainStep()) {
+    case MainSteps::AccountCreation: {
+        switch (get_accountCreationOption()) {
+        case AccountCreationOption::ImportFromBackup:
+        case AccountCreationOption::ImportFromDevice: {
+            accountAdapter_->createJamiAccount("", get_accountCreationInfo(), false);
+            break;
+        }
+        case AccountCreationOption::ConnectToAccountManager: {
+            accountAdapter_->createJAMSAccount(get_accountCreationInfo());
+            break;
+        }
+        case AccountCreationOption::CreateSipAccount: {
+            set_mainStep(MainSteps::Profile);
+            accountAdapter_->createSIPAccount(get_accountCreationInfo());
+            break;
+        }
+        }
+        break;
+    }
+    case MainSteps::NameRegistration: {
+        set_mainStep(MainSteps::SetPassword);
+        break;
+    }
+    case MainSteps::SetPassword: {
+        set_mainStep(MainSteps::Profile);
+
+        auto accountCreationInfo = get_accountCreationInfo();
+        accountAdapter_->createJamiAccount(accountCreationInfo["registeredName"].toString(),
+                                           accountCreationInfo,
+                                           true);
+        break;
+    }
+    case MainSteps::Profile: {
+        auto showBackup = (accountCreationOption == AccountCreationOption::CreateJamiAccount
+                           || accountCreationOption == AccountCreationOption::CreateRendezVous)
+                          && !appSettingsManager_->getValue(Settings::Key::NeverShowMeAgain).toBool();
+        if (showBackup)
+            set_mainStep(MainSteps::BackupKeys);
+        else {
+            Q_EMIT closeWizardView();
+            reset();
+        }
+        break;
+    }
+    case MainSteps::BackupKeys: {
+        Q_EMIT closeWizardView();
+        reset();
+        break;
+    }
+    }
+}
+
+void
+WizardViewStepModel::previousStep()
+{
+    switch (get_mainStep()) {
+    case MainSteps::Initial: {
+        Q_EMIT closeWizardView();
+        break;
+    }
+    case MainSteps::AccountCreation:
+    case MainSteps::NameRegistration: {
+        reset();
+        break;
+    }
+    case MainSteps::SetPassword: {
+        set_mainStep(MainSteps::NameRegistration);
+        break;
+    }
+    }
+}
+
+void
+WizardViewStepModel::reset()
+{
+    set_accountCreationOption(AccountCreationOption::None);
+    set_mainStep(MainSteps::Initial);
+}
diff --git a/src/wizardviewstepmodel.h b/src/wizardviewstepmodel.h
new file mode 100644
index 000000000..54765057c
--- /dev/null
+++ b/src/wizardviewstepmodel.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 by Savoir-faire Linux
+ * Author: Mingrui Zhang   <mingrui.zhang@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QVariant>
+#include <QMap>
+
+#include "qtutils.h"
+
+class AccountAdapter;
+class LRCInstance;
+class AppSettingsManager;
+
+class WizardViewStepModel : public QObject
+{
+    Q_OBJECT
+    Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+
+public:
+    enum class MainSteps {
+        Initial,          // Initial welcome step.
+        AccountCreation,  // General account creation step.
+        NameRegistration, // Name registration step : CreateJamiAccount, CreateRendezVous
+        SetPassword,      // Password set up step: CreateJamiAccount, CreateRendezVous
+        Profile,          // Profile set up.
+        BackupKeys        // Backup set up.
+    };
+    Q_ENUM(MainSteps)
+
+    enum class AccountCreationOption {
+        None,
+        CreateJamiAccount,       // Jami account creation.
+        CreateRendezVous,        // Jami rendezvous account creation.
+        ImportFromDevice,        // Jami account creation from device.
+        ImportFromBackup,        // Jami account creation from backup.
+        ConnectToAccountManager, // Account manager creation.
+        CreateSipAccount         // SIP account creation.
+    };
+    Q_ENUM(AccountCreationOption)
+
+    QML_PROPERTY(MainSteps, mainStep)
+    QML_PROPERTY(AccountCreationOption, accountCreationOption)
+
+    QML_PROPERTY(QVariantMap, accountCreationInfo)
+
+public:
+    explicit WizardViewStepModel(LRCInstance* lrcInstance,
+                                 AccountAdapter* accountAdapter,
+                                 AppSettingsManager* appSettingsManager,
+                                 QObject* parent = nullptr);
+
+    Q_INVOKABLE void startAccountCreationFlow(AccountCreationOption accountCreationOption);
+    Q_INVOKABLE void nextStep();
+    Q_INVOKABLE void previousStep();
+
+Q_SIGNALS:
+    void accountIsReady(QString accountId);
+    void closeWizardView();
+
+private:
+    void reset();
+
+    LRCInstance* lrcInstance_;
+    AccountAdapter* accountAdapter_;
+    AppSettingsManager* appSettingsManager_;
+};
-- 
GitLab