feat: Add logout functionality
Move the onboarding/login state machine to the top level in main.qml, so that logout events can trigger new states. Add Loader to statemachine so that each component is lazy-loaded. Initial tests saved 50MB of memory on startup. Currently, logging out, then logging back in to the same or different account results in a doubling-up of chats/messages/wallet accounts. These need to be reset, however I need help doing that and it would delayed and blown out this PR further. This reset has been done for Onboarding and Login, but needs to be done for chats, wallet, mailservers, etc.
This commit is contained in:
parent
bd8d743385
commit
4ec593baed
|
@ -3,6 +3,7 @@ import ../../status/libstatus/types as status_types
|
|||
import ../../signals/types
|
||||
import ../../status/status
|
||||
import view
|
||||
import ../../status/accounts as status_accounts
|
||||
|
||||
type LoginController* = ref object of SignalSubscriber
|
||||
status*: Status
|
||||
|
@ -19,11 +20,19 @@ proc delete*(self: LoginController) =
|
|||
delete self.view
|
||||
delete self.variant
|
||||
|
||||
proc init*(self: LoginController, nodeAccounts: seq[NodeAccount]) =
|
||||
proc init*(self: LoginController) =
|
||||
let nodeAccounts = self.status.accounts.openAccounts()
|
||||
self.status.accounts.nodeAccounts = nodeAccounts
|
||||
for nodeAccount in nodeAccounts:
|
||||
self.view.addAccountToList(nodeAccount)
|
||||
|
||||
proc reset*(self: LoginController) =
|
||||
self.view.removeAccounts()
|
||||
|
||||
proc handleNodeStopped(self: LoginController, data: Signal) =
|
||||
self.status.events.emit("nodeStopped", Args())
|
||||
self.view.onLoggedOut()
|
||||
|
||||
proc handleNodeLogin(self: LoginController, data: Signal) =
|
||||
let response = NodeSignal(data)
|
||||
if self.view.currentAccount.account != nil:
|
||||
|
@ -31,8 +40,13 @@ proc handleNodeLogin(self: LoginController, data: Signal) =
|
|||
if ?.response.event.error == "":
|
||||
self.status.events.emit("login", AccountArgs(account: self.view.currentAccount.account.toAccount))
|
||||
|
||||
proc handleNodeReady(self: LoginController, data: Signal) =
|
||||
self.status.events.emit("nodeReady", Args())
|
||||
|
||||
method onSignal(self: LoginController, data: Signal) =
|
||||
if data.signalType == SignalType.NodeLogin:
|
||||
self.handleNodeLogin(data)
|
||||
case data.signalType:
|
||||
of SignalType.NodeLogin: handleNodeLogin(self, data)
|
||||
of SignalType.NodeStopped: handleNodeStopped(self, data)
|
||||
of SignalType.NodeReady: handleNodeReady(self, data)
|
||||
else:
|
||||
discard
|
||||
|
|
|
@ -43,6 +43,11 @@ QtObject:
|
|||
self.accounts.add(account)
|
||||
self.endInsertRows()
|
||||
|
||||
proc removeAccounts*(self: LoginView) =
|
||||
self.beginRemoveRows(newQModelIndex(), self.accounts.len, self.accounts.len)
|
||||
self.accounts = @[]
|
||||
self.endRemoveRows()
|
||||
|
||||
method rowCount(self: LoginView, index: QModelIndex = nil): int =
|
||||
return self.accounts.len
|
||||
|
||||
|
@ -86,3 +91,5 @@ QtObject:
|
|||
|
||||
proc setLastLoginResponse*(self: LoginView, loginResponse: StatusGoError) =
|
||||
self.loginResponseChanged(loginResponse.error)
|
||||
|
||||
proc onLoggedOut*(self: LoginView) {.signal.}
|
|
@ -29,6 +29,9 @@ proc init*(self: OnboardingController) =
|
|||
for account in accounts:
|
||||
self.view.addAccountToList(account)
|
||||
|
||||
proc reset*(self: OnboardingController) =
|
||||
self.view.removeAccounts()
|
||||
|
||||
proc handleNodeLogin(self: OnboardingController, data: Signal) =
|
||||
let response = NodeSignal(data)
|
||||
if self.view.currentAccount.account != nil:
|
||||
|
@ -37,7 +40,7 @@ proc handleNodeLogin(self: OnboardingController, data: Signal) =
|
|||
self.status.events.emit("login", AccountArgs(account: self.view.currentAccount.account.toAccount))
|
||||
|
||||
method onSignal(self: OnboardingController, data: Signal) =
|
||||
if data.signalType == SignalType.NodeLogin:
|
||||
self.handleNodeLogin(data)
|
||||
case data.signalType:
|
||||
of SignalType.NodeLogin: handleNodeLogin(self, data)
|
||||
else:
|
||||
discard
|
||||
|
|
|
@ -40,6 +40,11 @@ QtObject:
|
|||
self.beginInsertRows(newQModelIndex(), self.accounts.len, self.accounts.len)
|
||||
self.accounts.add(account)
|
||||
self.endInsertRows()
|
||||
|
||||
proc removeAccounts*(self: OnboardingView) =
|
||||
self.beginResetModel()
|
||||
self.accounts = @[]
|
||||
self.endResetModel()
|
||||
|
||||
method rowCount(self: OnboardingView, index: QModelIndex = nil): int =
|
||||
return self.accounts.len
|
||||
|
|
|
@ -15,7 +15,7 @@ type ProfileController* = object
|
|||
proc newController*(status: Status): ProfileController =
|
||||
result = ProfileController()
|
||||
result.status = status
|
||||
result.view = newProfileView()
|
||||
result.view = newProfileView(status)
|
||||
result.variant = newQVariant(result.view)
|
||||
|
||||
proc delete*(self: ProfileController) =
|
||||
|
|
|
@ -3,12 +3,15 @@ import views/mailservers_list
|
|||
import views/contact_list
|
||||
import views/profile_info
|
||||
import ../../status/profile
|
||||
import ../../status/accounts as status_accounts
|
||||
import ../../status/status
|
||||
|
||||
QtObject:
|
||||
type ProfileView* = ref object of QObject
|
||||
profile*: ProfileInfoView
|
||||
mailserversList*: MailServersList
|
||||
contactList*: ContactList
|
||||
status*: Status
|
||||
|
||||
proc setup(self: ProfileView) =
|
||||
self.QObject.setup
|
||||
|
@ -16,12 +19,13 @@ QtObject:
|
|||
proc delete*(self: ProfileView) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newProfileView*(): ProfileView =
|
||||
proc newProfileView*(status: Status): ProfileView =
|
||||
new(result, delete)
|
||||
result = ProfileView()
|
||||
result.profile = newProfileInfoView()
|
||||
result.mailserversList = newMailServersList()
|
||||
result.contactList = newContactList()
|
||||
result.status = status
|
||||
result.setup
|
||||
|
||||
proc addMailServerToList*(self: ProfileView, mailserver: MailServer) =
|
||||
|
@ -50,3 +54,6 @@ QtObject:
|
|||
|
||||
QtProperty[QVariant] profile:
|
||||
read = getProfile
|
||||
|
||||
proc logout*(self: ProfileView) {.slot.} =
|
||||
self.status.profile.logout()
|
||||
|
|
|
@ -21,7 +21,7 @@ logScope:
|
|||
|
||||
proc mainProc() =
|
||||
let status = statuslib.newStatusInstance()
|
||||
let nodeAccounts = status.initNodeAccounts()
|
||||
status.initNode()
|
||||
|
||||
let app = newQApplication()
|
||||
let engine = newQQmlApplicationEngine()
|
||||
|
@ -43,13 +43,12 @@ proc mainProc() =
|
|||
engine.setRootContextProperty("chatsModel", chat.variant)
|
||||
|
||||
var node = node.newController(status)
|
||||
node.init()
|
||||
engine.setRootContextProperty("nodeModel", node.variant)
|
||||
|
||||
var profile = profile.newController(status)
|
||||
engine.setRootContextProperty("profileModel", profile.variant)
|
||||
|
||||
status.events.once("login") do(a: Args):
|
||||
status.events.on("login") do(a: Args):
|
||||
var args = AccountArgs(a)
|
||||
status.startMessenger()
|
||||
chat.init()
|
||||
|
@ -59,16 +58,37 @@ proc mainProc() =
|
|||
var login = login.newController(status)
|
||||
var onboarding = onboarding.newController(status)
|
||||
|
||||
# TODO: replace this with routing
|
||||
let showLogin = nodeAccounts.len > 0
|
||||
engine.setRootContextProperty("showLogin", newQVariant(showLogin))
|
||||
|
||||
login.init(nodeAccounts)
|
||||
engine.setRootContextProperty("loginModel", login.variant)
|
||||
|
||||
onboarding.init()
|
||||
engine.setRootContextProperty("onboardingModel", onboarding.variant)
|
||||
|
||||
# Initialize only controllers whose init functions
|
||||
# do not need a running node
|
||||
proc initControllers() =
|
||||
node.init()
|
||||
login.init()
|
||||
onboarding.init()
|
||||
|
||||
initControllers()
|
||||
|
||||
# Handle node.stopped signal when user has logged out
|
||||
status.events.on("nodeStopped") do(a: Args):
|
||||
# TODO: remove this once accounts are not tracked in the AccountsModel
|
||||
status.reset()
|
||||
|
||||
# 1. Reset controller data
|
||||
login.reset()
|
||||
onboarding.reset()
|
||||
# TODO: implement all controller resets
|
||||
# chat.reset()
|
||||
# node.reset()
|
||||
# wallet.reset()
|
||||
# profile.reset()
|
||||
|
||||
# 2. Re-init controllers that don't require a running node
|
||||
initControllers()
|
||||
|
||||
|
||||
signalController.init()
|
||||
signalController.addSubscriber(SignalType.Wallet, wallet)
|
||||
signalController.addSubscriber(SignalType.Wallet, node)
|
||||
|
@ -76,6 +96,9 @@ proc mainProc() =
|
|||
signalController.addSubscriber(SignalType.DiscoverySummary, chat)
|
||||
signalController.addSubscriber(SignalType.NodeLogin, login)
|
||||
signalController.addSubscriber(SignalType.NodeLogin, onboarding)
|
||||
signalController.addSubscriber(SignalType.NodeStopped, login)
|
||||
signalController.addSubscriber(SignalType.NodeStarted, login)
|
||||
signalController.addSubscriber(SignalType.NodeReady, login)
|
||||
|
||||
engine.setRootContextProperty("signals", signalController.variant)
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import libstatus/accounts as status_accounts
|
||||
import libstatus/types
|
||||
import options
|
||||
import eventemitter
|
||||
|
||||
type
|
||||
AccountModel* = ref object
|
||||
generatedAddresses*: seq[GeneratedAccount]
|
||||
nodeAccounts*: seq[NodeAccount]
|
||||
events: EventEmitter
|
||||
|
||||
proc newAccountModel*(): AccountModel =
|
||||
proc newAccountModel*(events: EventEmitter): AccountModel =
|
||||
result = AccountModel()
|
||||
result.events = events
|
||||
|
||||
proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] =
|
||||
var accounts = status_accounts.generateAddresses()
|
||||
|
@ -16,7 +19,10 @@ proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] =
|
|||
account.name = status_accounts.generateAlias(account.derived.whisper.publicKey)
|
||||
account.photoPath = status_accounts.generateIdenticon(account.derived.whisper.publicKey)
|
||||
self.generatedAddresses.add(account)
|
||||
self.generatedAddresses
|
||||
result = self.generatedAddresses
|
||||
|
||||
proc openAccounts*(self: AccountModel): seq[NodeAccount] =
|
||||
result = status_accounts.openAccounts()
|
||||
|
||||
proc login*(self: AccountModel, selectedAccountIndex: int, password: string): NodeAccount =
|
||||
let currentNodeAccount = self.nodeAccounts[selectedAccountIndex]
|
||||
|
@ -35,3 +41,7 @@ proc importMnemonic*(self: AccountModel, mnemonic: string): GeneratedAccount =
|
|||
importedAccount.name = status_accounts.generateAlias(importedAccount.derived.whisper.publicKey)
|
||||
importedAccount.photoPath = status_accounts.generateIdenticon(importedAccount.derived.whisper.publicKey)
|
||||
result = importedAccount
|
||||
|
||||
proc reset*(self: AccountModel) =
|
||||
self.nodeAccounts = @[]
|
||||
self.generatedAddresses = @[]
|
||||
|
|
|
@ -36,17 +36,15 @@ proc ensureDir(dirname: string) =
|
|||
# removeDir(dirname)
|
||||
createDir(dirname)
|
||||
|
||||
proc initNodeAccounts*(): seq[NodeAccount] =
|
||||
const datadir = "./data/"
|
||||
const keystoredir = "./data/keystore/"
|
||||
const nobackupdir = "./noBackup/"
|
||||
proc initNode*() =
|
||||
ensureDir(DATADIR)
|
||||
ensureDir(KEYSTOREDIR)
|
||||
ensureDir(NOBACKUPDIR)
|
||||
|
||||
ensureDir(datadir)
|
||||
ensureDir(keystoredir)
|
||||
ensureDir(nobackupdir)
|
||||
discard $libstatus.initKeystore(KEYSTOREDIR)
|
||||
|
||||
discard $libstatus.initKeystore(keystoredir);
|
||||
let strNodeAccounts = $libstatus.openAccounts(datadir);
|
||||
proc openAccounts*(): seq[NodeAccount] =
|
||||
let strNodeAccounts = $libstatus.openAccounts(DATADIR)
|
||||
result = Json.decode(strNodeAccounts, seq[NodeAccount])
|
||||
|
||||
proc saveAccountAndLogin*(
|
||||
|
@ -215,6 +213,8 @@ proc deriveAccounts*(accountId: string): MultiAccounts =
|
|||
"accountID": accountId,
|
||||
"paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET]
|
||||
}
|
||||
# libstatus.multiAccountImportMnemonic never results in an error given ANY input
|
||||
let deriveResult = $libstatus.multiAccountDeriveAddresses($deriveJson)
|
||||
result = Json.decode(deriveResult, MultiAccounts)
|
||||
|
||||
proc logout*(): StatusGoError =
|
||||
result = Json.decode($libstatus.logout(), StatusGoError)
|
||||
|
|
|
@ -174,4 +174,8 @@ let NODE_CONFIG* = %* {
|
|||
"WalletConfig": {
|
||||
"Enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DATADIR* = "./data/"
|
||||
const KEYSTOREDIR* = "./data/keystore/"
|
||||
const NOBACKUPDIR* = "./noBackup/"
|
|
@ -33,3 +33,5 @@ proc generateAlias*(p0: GoString): cstring {.importc: "GenerateAlias".}
|
|||
proc identicon*(p0: GoString): cstring {.importc: "Identicon".}
|
||||
|
||||
proc login*(acctData: cstring, password: cstring): cstring {.importc: "Login".}
|
||||
|
||||
proc logout*(): cstring {.importc: "Logout".}
|
||||
|
|
|
@ -9,6 +9,7 @@ type SignalType* {.pure.} = enum
|
|||
Wallet = "wallet"
|
||||
NodeReady = "node.ready"
|
||||
NodeStarted = "node.started"
|
||||
NodeStopped = "node.stopped"
|
||||
NodeLogin = "node.login"
|
||||
EnvelopeSent = "envelope.sent"
|
||||
EnvelopeExpired = "envelope.expired"
|
||||
|
|
|
@ -2,6 +2,7 @@ import json
|
|||
import eventemitter
|
||||
import libstatus/types
|
||||
import libstatus/core as libstatus_core
|
||||
import libstatus/accounts as status_accounts
|
||||
|
||||
type
|
||||
MailServer* = ref object
|
||||
|
@ -45,3 +46,13 @@ proc getContactByID*(id: string): Profile =
|
|||
let val = parseJSON($response)
|
||||
result = toProfileModel(val)
|
||||
|
||||
type
|
||||
ProfileModel* = ref object
|
||||
|
||||
proc newProfileModel*(): ProfileModel =
|
||||
result = ProfileModel()
|
||||
|
||||
proc logout*(self: ProfileModel) =
|
||||
discard status_accounts.logout()
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import accounts as accounts
|
|||
import wallet as wallet
|
||||
import node as node
|
||||
import mailservers as mailservers
|
||||
import profile
|
||||
import ../signals/types as signal_types
|
||||
|
||||
type Status* = ref object
|
||||
events*: EventEmitter
|
||||
|
@ -17,19 +19,33 @@ type Status* = ref object
|
|||
accounts*: AccountModel
|
||||
wallet*: WalletModel
|
||||
node*: NodeModel
|
||||
profile*: ProfileModel
|
||||
|
||||
proc newStatusInstance*(): Status =
|
||||
result = Status()
|
||||
result.events = createEventEmitter()
|
||||
result.chat = chat.newChatModel(result.events)
|
||||
result.accounts = accounts.newAccountModel()
|
||||
result.accounts = accounts.newAccountModel(result.events)
|
||||
result.wallet = wallet.newWalletModel(result.events)
|
||||
result.wallet.initEvents()
|
||||
result.node = node.newNodeModel()
|
||||
result.mailservers = mailservers.newMailserverModel(result.events)
|
||||
result.profile = profile.newProfileModel()
|
||||
|
||||
proc initNodeAccounts*(self: Status): seq[NodeAccount] =
|
||||
libstatus_accounts.initNodeAccounts()
|
||||
proc initNode*(self: Status) =
|
||||
libstatus_accounts.initNode()
|
||||
|
||||
proc startMessenger*(self: Status) =
|
||||
libstatus_core.startMessenger()
|
||||
|
||||
proc reset*(self: Status) =
|
||||
# TODO: remove this once accounts are not tracked in the AccountsModel
|
||||
self.accounts.reset()
|
||||
|
||||
# NOT NEEDED self.chat.reset()
|
||||
# NOT NEEDED self.wallet.reset()
|
||||
# NOT NEEDED self.node.reset()
|
||||
# NOT NEEDED self.mailservers.reset()
|
||||
# NOT NEEDED self.profile.reset()
|
||||
|
||||
# TODO: add all resets here
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.3
|
|||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.3
|
||||
import "../../../../imports"
|
||||
import "../../../../shared"
|
||||
|
||||
Item {
|
||||
id: signoutContainer
|
||||
|
@ -11,7 +12,7 @@ Item {
|
|||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
id: element10
|
||||
id: txtTitle
|
||||
text: qsTr("Sign out controls")
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 24
|
||||
|
@ -20,4 +21,15 @@ Item {
|
|||
font.weight: Font.Bold
|
||||
font.pixelSize: 20
|
||||
}
|
||||
|
||||
StyledButton {
|
||||
id: btnLogout
|
||||
anchors.top: txtTitle.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
label: qsTr("Logout")
|
||||
|
||||
onClicked: {
|
||||
profileModel.logout();
|
||||
}
|
||||
}
|
||||
}
|
148
ui/main.qml
148
ui/main.qml
|
@ -2,6 +2,7 @@ import QtQuick 2.3
|
|||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import QtQml.StateMachine 1.14 as DSM
|
||||
import "./onboarding"
|
||||
import "./app"
|
||||
|
||||
|
@ -13,6 +14,8 @@ ApplicationWindow {
|
|||
visible: true
|
||||
font.family: "Inter"
|
||||
|
||||
signal navigateTo(string path)
|
||||
|
||||
SystemTrayIcon {
|
||||
visible: true
|
||||
icon.source: "shared/img/status-logo.png"
|
||||
|
@ -30,18 +33,145 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
OnboardingMain {
|
||||
id: onboarding
|
||||
visible: !app.visible
|
||||
DSM.StateMachine {
|
||||
id: stateMachine
|
||||
initialState: onboardingState
|
||||
running: true
|
||||
|
||||
DSM.State {
|
||||
id: onboardingState
|
||||
initialState: loginModel.rowCount() ? stateLogin : stateIntro
|
||||
|
||||
DSM.State {
|
||||
id: stateIntro
|
||||
onEntered: loader.sourceComponent = intro
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: keysMainState
|
||||
signal: applicationWindow.navigateTo
|
||||
guard: path === "KeysMain"
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: keysMainState
|
||||
onEntered: loader.sourceComponent = keysMain
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: existingKeyState
|
||||
signal: applicationWindow.navigateTo
|
||||
guard: path === "ExistingKey"
|
||||
}
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: genKeyState
|
||||
signal: applicationWindow.navigateTo
|
||||
guard: path === "GenKey"
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: existingKeyState
|
||||
onEntered: loader.sourceComponent = existingKey
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: appState
|
||||
signal: onboardingModel.loginResponseChanged
|
||||
guard: !error
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: genKeyState
|
||||
onEntered: loader.sourceComponent = genKey
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: appState
|
||||
signal: onboardingModel.loginResponseChanged
|
||||
guard: !error
|
||||
}
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: existingKeyState
|
||||
signal: applicationWindow.navigateTo
|
||||
guard: path === "ExistingKey"
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: stateLogin
|
||||
onEntered: loader.sourceComponent = login
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: appState
|
||||
signal: loginModel.loginResponseChanged
|
||||
guard: !error
|
||||
}
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: genKeyState
|
||||
signal: applicationWindow.navigateTo
|
||||
guard: path === "GenKey"
|
||||
}
|
||||
}
|
||||
|
||||
DSM.FinalState {
|
||||
id: onboardingDoneState
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: appState
|
||||
onEntered: loader.sourceComponent = app
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: stateLogin
|
||||
signal: loginModel.onLoggedOut
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
AppMain {
|
||||
Component {
|
||||
id: app
|
||||
// TODO: Set this to a logic result determining when we need to show the onboarding screens
|
||||
// Set to true to hide the onboarding screens manually
|
||||
// Set to false to show the onboarding screens manually
|
||||
visible: false // logic.accountResult !== ""
|
||||
anchors.fill: parent
|
||||
AppMain {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: intro
|
||||
Intro {
|
||||
btnGetStarted.onClicked: applicationWindow.navigateTo("KeysMain")
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: keysMain
|
||||
KeysMain {
|
||||
btnGenKey.onClicked: applicationWindow.navigateTo("GenKey")
|
||||
btnExistingKey.onClicked: applicationWindow.navigateTo("ExistingKey")
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: existingKey
|
||||
ExistingKey {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: genKey
|
||||
GenKey {
|
||||
btnExistingKey.onClicked: applicationWindow.navigateTo("ExistingKey")
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: login
|
||||
Login {
|
||||
btnGenKey.onClicked: applicationWindow.navigateTo("GenKey")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -192,6 +192,19 @@ SwipeView {
|
|||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
id: passwordsDontMatchError
|
||||
title: "Error"
|
||||
text: "Passwords don't match"
|
||||
icon: StandardIcon.Warning
|
||||
standardButtons: StandardButton.Ok
|
||||
onAccepted: {
|
||||
txtConfirmPassword.clear();
|
||||
swipeView.currentIndex = 1;
|
||||
txtPassword.focus = true;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: onboardingModel
|
||||
ignoreUnknownSignals: true
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
import QtQuick 2.3
|
||||
import QtQml.StateMachine 1.14 as DSM
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
Page {
|
||||
id: onboardingMain
|
||||
property string state
|
||||
anchors.fill: parent
|
||||
|
||||
DSM.StateMachine {
|
||||
id: stateMachine
|
||||
initialState: showLogin ? stateLogin : stateIntro
|
||||
running: onboardingMain.visible
|
||||
|
||||
DSM.State {
|
||||
id: stateIntro
|
||||
onEntered: intro.visible = true
|
||||
onExited: intro.visible = false
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: keysMainState
|
||||
signal: intro.btnGetStarted.clicked
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: keysMainState
|
||||
onEntered: keysMain.visible = true
|
||||
onExited: keysMain.visible = false
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: existingKeyState
|
||||
signal: keysMain.btnExistingKey.clicked
|
||||
}
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: genKeyState
|
||||
signal: keysMain.btnGenKey.clicked
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: existingKeyState
|
||||
onEntered: existingKey.visible = true
|
||||
onExited: existingKey.visible = false
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: appState
|
||||
signal: onboardingModel.loginResponseChanged
|
||||
guard: !error
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: genKeyState
|
||||
onEntered: genKey.visible = true
|
||||
onExited: genKey.visible = false
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: appState
|
||||
signal: onboardingModel.loginResponseChanged
|
||||
guard: !error
|
||||
}
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: existingKeyState
|
||||
signal: genKey.btnExistingKey.clicked
|
||||
}
|
||||
}
|
||||
|
||||
DSM.State {
|
||||
id: stateLogin
|
||||
onEntered: login.visible = true
|
||||
onExited: login.visible = false
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: appState
|
||||
signal: loginModel.loginResponseChanged
|
||||
guard: !error
|
||||
}
|
||||
|
||||
DSM.SignalTransition {
|
||||
targetState: genKeyState
|
||||
signal: login.btnGenKey.clicked
|
||||
}
|
||||
}
|
||||
|
||||
DSM.FinalState {
|
||||
id: appState
|
||||
onEntered: app.visible = true
|
||||
onExited: app.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
Intro {
|
||||
id: intro
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
}
|
||||
|
||||
KeysMain {
|
||||
id: keysMain
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
}
|
||||
|
||||
ExistingKey {
|
||||
id: existingKey
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
}
|
||||
|
||||
GenKey {
|
||||
id: genKey
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
}
|
||||
|
||||
Login {
|
||||
id: login
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;autoSize:true;height:770;width:1232}
|
||||
}
|
||||
##^##*/
|
Loading…
Reference in New Issue