feat: Add import account functionality
Allow user to import an existing mnemonic. TODO: add mnemonic validation with the `validateMnemonic` status-go function.
This commit is contained in:
parent
dc6793a0f0
commit
691717990d
|
@ -25,10 +25,11 @@ proc init*(self: LoginController, nodeAccounts: seq[NodeAccount]) =
|
||||||
self.view.addAccountToList(nodeAccount)
|
self.view.addAccountToList(nodeAccount)
|
||||||
|
|
||||||
proc handleNodeLogin(self: LoginController, data: Signal) =
|
proc handleNodeLogin(self: LoginController, data: Signal) =
|
||||||
var response = NodeSignal(data)
|
let response = NodeSignal(data)
|
||||||
self.view.setLastLoginResponse($response.event.toJson)
|
if self.status.accounts.currentLoginAccount != nil:
|
||||||
if ?.response.event.error == "" and self.status.accounts.currentAccount != nil:
|
self.view.setLastLoginResponse(response.event)
|
||||||
self.status.events.emit("login", AccountArgs(account: self.status.accounts.currentAccount))
|
if ?.response.event.error == "":
|
||||||
|
self.status.events.emit("login", AccountArgs(account: self.status.accounts.currentLoginAccount))
|
||||||
|
|
||||||
method onSignal(self: LoginController, data: Signal) =
|
method onSignal(self: LoginController, data: Signal) =
|
||||||
if data.signalType == SignalType.NodeLogin:
|
if data.signalType == SignalType.NodeLogin:
|
||||||
|
|
|
@ -23,7 +23,6 @@ QtObject:
|
||||||
type LoginView* = ref object of QAbstractListModel
|
type LoginView* = ref object of QAbstractListModel
|
||||||
status: Status
|
status: Status
|
||||||
accounts: seq[NodeAccount]
|
accounts: seq[NodeAccount]
|
||||||
lastLoginResponse: string
|
|
||||||
|
|
||||||
proc setup(self: LoginView) =
|
proc setup(self: LoginView) =
|
||||||
self.QAbstractListModel.setup
|
self.QAbstractListModel.setup
|
||||||
|
@ -35,7 +34,6 @@ QtObject:
|
||||||
proc newLoginView*(status: Status): LoginView =
|
proc newLoginView*(status: Status): LoginView =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.accounts = @[]
|
result.accounts = @[]
|
||||||
result.lastLoginResponse = ""
|
|
||||||
result.status = status
|
result.status = status
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
|
@ -72,18 +70,9 @@ QtObject:
|
||||||
let
|
let
|
||||||
e = getCurrentException()
|
e = getCurrentException()
|
||||||
msg = getCurrentExceptionMsg()
|
msg = getCurrentExceptionMsg()
|
||||||
result = SignalError(error: msg).toJson
|
result = StatusGoError(error: msg).toJson
|
||||||
|
|
||||||
proc lastLoginResponse*(self: LoginView): string =
|
proc loginResponseChanged*(self: LoginView, error: string) {.signal.}
|
||||||
result = self.lastLoginResponse
|
|
||||||
|
|
||||||
proc loginResponseChanged*(self: LoginView, response: string) {.signal.}
|
proc setLastLoginResponse*(self: LoginView, loginResponse: StatusGoError) =
|
||||||
|
self.loginResponseChanged(loginResponse.error)
|
||||||
proc setLastLoginResponse*(self: LoginView, loginResponse: string) {.slot.} =
|
|
||||||
self.lastLoginResponse = loginResponse
|
|
||||||
self.loginResponseChanged(loginResponse)
|
|
||||||
|
|
||||||
QtProperty[string] loginResponse:
|
|
||||||
read = lastLoginResponse
|
|
||||||
write = setLastLoginResponse
|
|
||||||
notify = loginResponseChanged
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import view
|
||||||
import chronicles
|
import chronicles
|
||||||
import ../../signals/types
|
import ../../signals/types
|
||||||
import std/wrapnils
|
import std/wrapnils
|
||||||
|
|
||||||
import ../../status/status
|
import ../../status/status
|
||||||
|
|
||||||
type OnboardingController* = ref object of SignalSubscriber
|
type OnboardingController* = ref object of SignalSubscriber
|
||||||
|
@ -31,10 +30,11 @@ proc init*(self: OnboardingController) =
|
||||||
self.view.addAccountToList(account)
|
self.view.addAccountToList(account)
|
||||||
|
|
||||||
proc handleNodeLogin(self: OnboardingController, data: Signal) =
|
proc handleNodeLogin(self: OnboardingController, data: Signal) =
|
||||||
var response = NodeSignal(data)
|
let response = NodeSignal(data)
|
||||||
self.view.setLastLoginResponse($response.event.toJson)
|
if self.status.accounts.currentOnboardingAccount != nil:
|
||||||
if ?.response.event.error == "" and self.status.accounts.currentAccount != nil:
|
self.view.setLastLoginResponse(response.event)
|
||||||
self.status.events.emit("login", AccountArgs(account: self.status.accounts.currentAccount))
|
if ?.response.event.error == "":
|
||||||
|
self.status.events.emit("login", AccountArgs(account: self.status.accounts.currentOnboardingAccount))
|
||||||
|
|
||||||
method onSignal(self: OnboardingController, data: Signal) =
|
method onSignal(self: OnboardingController, data: Signal) =
|
||||||
if data.signalType == SignalType.NodeLogin:
|
if data.signalType == SignalType.NodeLogin:
|
||||||
|
|
|
@ -6,6 +6,8 @@ import ../../signals/types
|
||||||
import strformat
|
import strformat
|
||||||
import json_serialization
|
import json_serialization
|
||||||
import ../../status/accounts as AccountModel
|
import ../../status/accounts as AccountModel
|
||||||
|
import views/account_info
|
||||||
|
import strutils
|
||||||
import ../../status/status
|
import ../../status/status
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -17,7 +19,7 @@ type
|
||||||
QtObject:
|
QtObject:
|
||||||
type OnboardingView* = ref object of QAbstractListModel
|
type OnboardingView* = ref object of QAbstractListModel
|
||||||
accounts*: seq[GeneratedAccount]
|
accounts*: seq[GeneratedAccount]
|
||||||
lastLoginResponse: string
|
importedAccount: AccountInfoView
|
||||||
status*: Status
|
status*: Status
|
||||||
|
|
||||||
proc setup(self: OnboardingView) =
|
proc setup(self: OnboardingView) =
|
||||||
|
@ -30,7 +32,7 @@ QtObject:
|
||||||
proc newOnboardingView*(status: Status): OnboardingView =
|
proc newOnboardingView*(status: Status): OnboardingView =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.accounts = @[]
|
result.accounts = @[]
|
||||||
result.lastLoginResponse = ""
|
result.importedAccount = newAccountInfoView()
|
||||||
result.status = status
|
result.status = status
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ QtObject:
|
||||||
case assetRole:
|
case assetRole:
|
||||||
of AccountRoles.Username: result = newQVariant(asset.name)
|
of AccountRoles.Username: result = newQVariant(asset.name)
|
||||||
of AccountRoles.Identicon: result = newQVariant(asset.photoPath)
|
of AccountRoles.Identicon: result = newQVariant(asset.photoPath)
|
||||||
of AccountRoles.Key: result = newQVariant(asset.keyUid)
|
of AccountRoles.Key: result = newQVariant(asset.derived.whisper.address)
|
||||||
|
|
||||||
method roleNames(self: OnboardingView): Table[int, string] =
|
method roleNames(self: OnboardingView): Table[int, string] =
|
||||||
{ AccountRoles.Username.int:"username",
|
{ AccountRoles.Username.int:"username",
|
||||||
|
@ -67,18 +69,35 @@ QtObject:
|
||||||
let
|
let
|
||||||
e = getCurrentException()
|
e = getCurrentException()
|
||||||
msg = getCurrentExceptionMsg()
|
msg = getCurrentExceptionMsg()
|
||||||
result = SignalError(error: msg).toJson
|
result = StatusGoError(error: msg).toJson
|
||||||
|
|
||||||
proc lastLoginResponse*(self: OnboardingView): string =
|
proc getImportedAccount*(self: OnboardingView): QVariant {.slot.} =
|
||||||
result = self.lastLoginResponse
|
result = newQVariant(self.importedAccount)
|
||||||
|
|
||||||
proc loginResponseChanged*(self: OnboardingView, response: string) {.signal.}
|
proc setImportedAccount*(self: OnboardingView, importedAccount: GeneratedAccount) =
|
||||||
|
self.importedAccount.setAccount(importedAccount)
|
||||||
|
|
||||||
proc setLastLoginResponse*(self: OnboardingView, loginResponse: string) {.slot.} =
|
QtProperty[QVariant] importedAccount:
|
||||||
self.lastLoginResponse = loginResponse
|
read = getImportedAccount
|
||||||
self.loginResponseChanged(loginResponse)
|
|
||||||
|
|
||||||
QtProperty[string] loginResponse:
|
proc importMnemonic(self: OnboardingView, mnemonic: string): string {.slot.} =
|
||||||
read = lastLoginResponse
|
try:
|
||||||
write = setLastLoginResponse
|
let importResult = self.status.accounts.importMnemonic(mnemonic)
|
||||||
notify = loginResponseChanged
|
result = importResult.toJson
|
||||||
|
self.setImportedAccount(importResult)
|
||||||
|
except StatusGoException as e:
|
||||||
|
result = StatusGoError(error: e.msg).toJson
|
||||||
|
|
||||||
|
proc storeDerivedAndLogin(self: OnboardingView, password: string): string {.slot.} =
|
||||||
|
try:
|
||||||
|
result = self.status.accounts.storeDerivedAndLogin(self.importedAccount.account, password).toJson
|
||||||
|
except StatusGoException as e:
|
||||||
|
var msg = e.msg
|
||||||
|
if e.msg.contains("account already exists"):
|
||||||
|
msg = "Account already exists. Please try importing another account."
|
||||||
|
result = StatusGoError(error: msg).toJson
|
||||||
|
|
||||||
|
proc loginResponseChanged*(self: OnboardingView, error: string) {.signal.}
|
||||||
|
|
||||||
|
proc setLastLoginResponse*(self: OnboardingView, loginResponse: StatusGoError) =
|
||||||
|
self.loginResponseChanged(loginResponse.error)
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import NimQml
|
||||||
|
import ../../../status/libstatus/types
|
||||||
|
import std/wrapnils
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type AccountInfoView* = ref object of QObject
|
||||||
|
account*: GeneratedAccount
|
||||||
|
|
||||||
|
proc setup(self: AccountInfoView) =
|
||||||
|
self.QObject.setup
|
||||||
|
|
||||||
|
proc delete*(self: AccountInfoView) =
|
||||||
|
self.QObject.delete
|
||||||
|
|
||||||
|
proc newAccountInfoView*(): AccountInfoView =
|
||||||
|
new(result, delete)
|
||||||
|
result = AccountInfoView()
|
||||||
|
result.setup
|
||||||
|
|
||||||
|
proc accountChanged*(self: AccountInfoView) {.signal.}
|
||||||
|
|
||||||
|
proc setAccount*(self: AccountInfoView, account: GeneratedAccount) =
|
||||||
|
self.account = account
|
||||||
|
self.accountChanged()
|
||||||
|
|
||||||
|
proc username*(self: AccountInfoView): string {.slot.} = result = ?.self.account.name
|
||||||
|
QtProperty[string] username:
|
||||||
|
read = username
|
||||||
|
notify = accountChanged
|
||||||
|
|
||||||
|
proc identicon*(self: AccountInfoView): string {.slot.} = result = ?.self.account.photoPath
|
||||||
|
QtProperty[string] identicon:
|
||||||
|
read = identicon
|
||||||
|
notify = accountChanged
|
||||||
|
|
||||||
|
proc address*(self: AccountInfoView): string {.slot.} = result = ?.self.account.derived.whisper.publicKey
|
||||||
|
QtProperty[string] address:
|
||||||
|
read = address
|
||||||
|
notify = accountChanged
|
||||||
|
|
||||||
|
proc id*(self: AccountInfoView): string {.slot.} = result = ?.self.account.id
|
||||||
|
QtProperty[string] id:
|
||||||
|
read = id
|
||||||
|
notify = accountChanged
|
|
@ -1,7 +1,6 @@
|
||||||
import NimQml
|
import NimQml
|
||||||
import eventemitter
|
import eventemitter
|
||||||
import chronicles
|
import chronicles
|
||||||
import json_serialization
|
|
||||||
|
|
||||||
import app/chat/core as chat
|
import app/chat/core as chat
|
||||||
import app/wallet/core as wallet
|
import app/wallet/core as wallet
|
||||||
|
|
|
@ -8,11 +8,11 @@ type SignalSubscriber* = ref object of RootObj
|
||||||
type Signal* = ref object of RootObj
|
type Signal* = ref object of RootObj
|
||||||
signalType* {.serializedFieldName("type").}: SignalType
|
signalType* {.serializedFieldName("type").}: SignalType
|
||||||
|
|
||||||
type SignalError* = object
|
type StatusGoError* = object
|
||||||
error*: string
|
error*: string
|
||||||
|
|
||||||
type NodeSignal* = ref object of Signal
|
type NodeSignal* = ref object of Signal
|
||||||
event*: SignalError
|
event*: StatusGoError
|
||||||
|
|
||||||
type WalletSignal* = ref object of Signal
|
type WalletSignal* = ref object of Signal
|
||||||
content*: string
|
content*: string
|
||||||
|
|
|
@ -6,11 +6,13 @@ type
|
||||||
AccountModel* = ref object
|
AccountModel* = ref object
|
||||||
generatedAddresses*: seq[GeneratedAccount]
|
generatedAddresses*: seq[GeneratedAccount]
|
||||||
nodeAccounts*: seq[NodeAccount]
|
nodeAccounts*: seq[NodeAccount]
|
||||||
currentAccount*: Account
|
currentLoginAccount*: Account
|
||||||
|
currentOnboardingAccount*: Account
|
||||||
|
|
||||||
proc newAccountModel*(): AccountModel =
|
proc newAccountModel*(): AccountModel =
|
||||||
result = AccountModel()
|
result = AccountModel()
|
||||||
result.currentAccount = nil
|
result.currentLoginAccount = nil
|
||||||
|
result.currentOnboardingAccount = nil
|
||||||
|
|
||||||
proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] =
|
proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] =
|
||||||
var accounts = status_accounts.generateAddresses()
|
var accounts = status_accounts.generateAddresses()
|
||||||
|
@ -22,10 +24,21 @@ proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] =
|
||||||
|
|
||||||
proc login*(self: AccountModel, selectedAccountIndex: int, password: string): NodeAccount =
|
proc login*(self: AccountModel, selectedAccountIndex: int, password: string): NodeAccount =
|
||||||
let currentNodeAccount = self.nodeAccounts[selectedAccountIndex]
|
let currentNodeAccount = self.nodeAccounts[selectedAccountIndex]
|
||||||
self.currentAccount = currentNodeAccount.toAccount
|
self.currentLoginAccount = currentNodeAccount.toAccount
|
||||||
result = status_accounts.login(currentNodeAccount, password)
|
result = status_accounts.login(currentNodeAccount, password)
|
||||||
|
|
||||||
proc storeAccountAndLogin*(self: AccountModel, selectedAccountIndex: int, password: string): Account =
|
proc storeAccountAndLogin*(self: AccountModel, selectedAccountIndex: int, password: string): Account =
|
||||||
let generatedAccount: GeneratedAccount = self.generatedAddresses[selectedAccountIndex]
|
let generatedAccount: GeneratedAccount = self.generatedAddresses[selectedAccountIndex]
|
||||||
result = status_accounts.setupAccount(generatedAccount, password)
|
result = status_accounts.setupAccount(generatedAccount, password)
|
||||||
self.currentAccount = generatedAccount.toAccount
|
self.currentOnboardingAccount = generatedAccount.toAccount
|
||||||
|
|
||||||
|
proc storeDerivedAndLogin*(self: AccountModel, importedAccount: GeneratedAccount, password: string): Account =
|
||||||
|
result = status_accounts.setupAccount(importedAccount, password)
|
||||||
|
self.currentOnboardingAccount = importedAccount.toAccount
|
||||||
|
|
||||||
|
proc importMnemonic*(self: AccountModel, mnemonic: string): GeneratedAccount =
|
||||||
|
let importedAccount = status_accounts.multiAccountImportMnemonic(mnemonic)
|
||||||
|
importedAccount.derived = status_accounts.deriveAccounts(importedAccount.id)
|
||||||
|
importedAccount.name = status_accounts.generateAlias(importedAccount.derived.whisper.publicKey)
|
||||||
|
importedAccount.photoPath = status_accounts.generateIdenticon(importedAccount.derived.whisper.publicKey)
|
||||||
|
result = importedAccount
|
||||||
|
|
|
@ -9,6 +9,7 @@ import uuids
|
||||||
import types
|
import types
|
||||||
import json_serialization
|
import json_serialization
|
||||||
import chronicles
|
import chronicles
|
||||||
|
import ../../signals/types as signal_types
|
||||||
|
|
||||||
proc queryAccounts*(): string =
|
proc queryAccounts*(): string =
|
||||||
var response = callPrivateRPC("eth_accounts")
|
var response = callPrivateRPC("eth_accounts")
|
||||||
|
@ -19,9 +20,10 @@ proc generateAddresses*(): seq[GeneratedAccount] =
|
||||||
"n": 5,
|
"n": 5,
|
||||||
"mnemonicPhraseLength": 12,
|
"mnemonicPhraseLength": 12,
|
||||||
"bip39Passphrase": "",
|
"bip39Passphrase": "",
|
||||||
"paths": [PATH_WHISPER, PATH_WALLET_ROOT, PATH_DEFAULT_WALLET]
|
"paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET]
|
||||||
}
|
}
|
||||||
result = Json.decode($libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig), seq[GeneratedAccount])
|
let generatedAccounts = $libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig)
|
||||||
|
result = Json.decode(generatedAccounts, seq[GeneratedAccount])
|
||||||
|
|
||||||
proc generateAlias*(publicKey: string): string =
|
proc generateAlias*(publicKey: string): string =
|
||||||
result = $libstatus.generateAlias(publicKey.toGoString)
|
result = $libstatus.generateAlias(publicKey.toGoString)
|
||||||
|
@ -48,9 +50,7 @@ proc initNodeAccounts*(): seq[NodeAccount] =
|
||||||
result = Json.decode(strNodeAccounts, seq[NodeAccount])
|
result = Json.decode(strNodeAccounts, seq[NodeAccount])
|
||||||
|
|
||||||
proc saveAccountAndLogin*(
|
proc saveAccountAndLogin*(
|
||||||
multiAccounts: MultiAccounts,
|
account: GeneratedAccount,
|
||||||
alias: string,
|
|
||||||
identicon: string,
|
|
||||||
accountData: string,
|
accountData: string,
|
||||||
password: string,
|
password: string,
|
||||||
configJSON: string,
|
configJSON: string,
|
||||||
|
@ -58,18 +58,18 @@ proc saveAccountAndLogin*(
|
||||||
let hashedPassword = "0x" & $keccak_256.digest(password)
|
let hashedPassword = "0x" & $keccak_256.digest(password)
|
||||||
let subaccountData = %* [
|
let subaccountData = %* [
|
||||||
{
|
{
|
||||||
"public-key": multiAccounts.defaultWallet.publicKey,
|
"public-key": account.derived.defaultWallet.publicKey,
|
||||||
"address": multiAccounts.defaultWallet.address,
|
"address": account.derived.defaultWallet.address,
|
||||||
"color": "#4360df",
|
"color": "#4360df",
|
||||||
"wallet": true,
|
"wallet": true,
|
||||||
"path": constants.PATH_DEFAULT_WALLET,
|
"path": constants.PATH_DEFAULT_WALLET,
|
||||||
"name": "Status account"
|
"name": "Status account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"public-key": multiAccounts.whisper.publicKey,
|
"public-key": account.derived.whisper.publicKey,
|
||||||
"address": multiAccounts.whisper.address,
|
"address": account.derived.whisper.address,
|
||||||
"name": alias,
|
"name": account.name,
|
||||||
"photo-path": identicon,
|
"photo-path": account.photoPath,
|
||||||
"path": constants.PATH_WHISPER,
|
"path": constants.PATH_WHISPER,
|
||||||
"chat": true
|
"chat": true
|
||||||
}
|
}
|
||||||
|
@ -81,47 +81,52 @@ proc saveAccountAndLogin*(
|
||||||
|
|
||||||
if error == "":
|
if error == "":
|
||||||
debug "Account saved succesfully"
|
debug "Account saved succesfully"
|
||||||
result = Account(name: alias, photoPath: identicon)
|
result = account.toAccount
|
||||||
return
|
return
|
||||||
|
|
||||||
raise newException(LoginError, "Error saving account and logging in: " & error)
|
raise newException(StatusGoException, "Error saving account and logging in: " & error)
|
||||||
|
|
||||||
proc generateMultiAccounts*(account: GeneratedAccount, password: string): MultiAccounts =
|
proc storeDerivedAccounts*(account: GeneratedAccount, password: string): MultiAccounts =
|
||||||
let hashedPassword = "0x" & $keccak_256.digest(password)
|
let hashedPassword = "0x" & $keccak_256.digest(password)
|
||||||
let multiAccount = %* {
|
let multiAccount = %* {
|
||||||
"accountID": account.id,
|
"accountID": account.id,
|
||||||
"paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET],
|
"paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET],
|
||||||
"password": hashedPassword
|
"password": hashedPassword
|
||||||
}
|
}
|
||||||
var response = $libstatus.multiAccountStoreDerivedAccounts($multiAccount);
|
let response = $libstatus.multiAccountStoreDerivedAccounts($multiAccount);
|
||||||
result = Json.decode($response, MultiAccounts)
|
|
||||||
|
try:
|
||||||
|
result = Json.decode($response, MultiAccounts)
|
||||||
|
except:
|
||||||
|
let err = Json.decode($response, StatusGoError)
|
||||||
|
raise newException(StatusGoException, "Error storing multiaccount derived accounts: " & err.error)
|
||||||
|
|
||||||
proc getAccountData*(account: GeneratedAccount, alias: string, identicon: string): JsonNode =
|
proc getAccountData*(account: GeneratedAccount): JsonNode =
|
||||||
result = %* {
|
result = %* {
|
||||||
"name": alias,
|
"name": account.name,
|
||||||
"address": account.address,
|
"address": account.address,
|
||||||
"photo-path": identicon,
|
"photo-path": account.photoPath,
|
||||||
"key-uid": account.keyUid,
|
"key-uid": account.keyUid,
|
||||||
"keycard-pairing": nil
|
"keycard-pairing": nil
|
||||||
}
|
}
|
||||||
|
|
||||||
proc getAccountSettings*(account: GeneratedAccount, alias: string, identicon: string, multiAccounts: MultiAccounts, defaultNetworks: JsonNode): JsonNode =
|
proc getAccountSettings*(account: GeneratedAccount, defaultNetworks: JsonNode): JsonNode =
|
||||||
result = %* {
|
result = %* {
|
||||||
"key-uid": account.keyUid,
|
"key-uid": account.keyUid,
|
||||||
"mnemonic": account.mnemonic,
|
"mnemonic": account.mnemonic,
|
||||||
"public-key": multiAccounts.whisper.publicKey,
|
"public-key": account.derived.whisper.publicKey,
|
||||||
"name": alias,
|
"name": account.name,
|
||||||
"address": account.address,
|
"address": account.address,
|
||||||
"eip1581-address": multiAccounts.eip1581.address,
|
"eip1581-address": account.derived.eip1581.address,
|
||||||
"dapps-address": multiAccounts.defaultWallet.address,
|
"dapps-address": account.derived.defaultWallet.address,
|
||||||
"wallet-root-address": multiAccounts.walletRoot.address,
|
"wallet-root-address": account.derived.walletRoot.address,
|
||||||
"preview-privacy?": true,
|
"preview-privacy?": true,
|
||||||
"signing-phrase": generateSigningPhrase(3),
|
"signing-phrase": generateSigningPhrase(3),
|
||||||
"log-level": "INFO",
|
"log-level": "INFO",
|
||||||
"latest-derived-path": 0,
|
"latest-derived-path": 0,
|
||||||
"networks/networks": defaultNetworks,
|
"networks/networks": defaultNetworks,
|
||||||
"currency": "usd",
|
"currency": "usd",
|
||||||
"photo-path": identicon,
|
"photo-path": account.photoPath,
|
||||||
"waku-enabled": true,
|
"waku-enabled": true,
|
||||||
"wallet/visible-tokens": {
|
"wallet/visible-tokens": {
|
||||||
"mainnet": ["SNT"]
|
"mainnet": ["SNT"]
|
||||||
|
@ -132,20 +137,20 @@ proc getAccountSettings*(account: GeneratedAccount, alias: string, identicon: st
|
||||||
}
|
}
|
||||||
|
|
||||||
proc setupAccount*(account: GeneratedAccount, password: string): Account =
|
proc setupAccount*(account: GeneratedAccount, password: string): Account =
|
||||||
let multiAccounts = generateMultiAccounts(account, password)
|
try:
|
||||||
|
let storeDerivedResult = storeDerivedAccounts(account, password)
|
||||||
|
let accountData = getAccountData(account)
|
||||||
|
var settingsJSON = getAccountSettings(account, constants.DEFAULT_NETWORKS)
|
||||||
|
|
||||||
let whisperPubKey = account.derived.whisper.publicKey
|
result = saveAccountAndLogin(account, $accountData, password, $constants.NODE_CONFIG, $settingsJSON)
|
||||||
let alias = generateAlias(whisperPubKey)
|
|
||||||
let identicon =generateIdenticon(whisperPubKey)
|
|
||||||
|
|
||||||
let accountData = getAccountData(account, alias, identicon)
|
except StatusGoException as e:
|
||||||
var settingsJSON = getAccountSettings(account, alias, identicon, multiAccounts, constants.DEFAULT_NETWORKS)
|
raise newException(StatusGoException, "Error setting up account: " & e.msg)
|
||||||
|
|
||||||
result = saveAccountAndLogin(multiAccounts, alias, identicon, $accountData, password, $constants.NODE_CONFIG, $settingsJSON)
|
finally:
|
||||||
|
# TODO this is needed for now for the retrieving of past messages. We'll either move or remove it later
|
||||||
# TODO this is needed for now for the retrieving of past messages. We'll either move or remove it later
|
let peer = "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443"
|
||||||
let peer = "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443"
|
discard libstatus.addPeer(peer)
|
||||||
discard libstatus.addPeer(peer)
|
|
||||||
|
|
||||||
proc login*(nodeAccount: NodeAccount, password: string): NodeAccount =
|
proc login*(nodeAccount: NodeAccount, password: string): NodeAccount =
|
||||||
let hashedPassword = "0x" & $keccak_256.digest(password)
|
let hashedPassword = "0x" & $keccak_256.digest(password)
|
||||||
|
@ -158,4 +163,22 @@ proc login*(nodeAccount: NodeAccount, password: string): NodeAccount =
|
||||||
result = nodeAccount
|
result = nodeAccount
|
||||||
return
|
return
|
||||||
|
|
||||||
raise newException(LoginError, "Error logging in: " & error)
|
raise newException(StatusGoException, "Error logging in: " & error)
|
||||||
|
|
||||||
|
proc multiAccountImportMnemonic*(mnemonic: string): GeneratedAccount =
|
||||||
|
let mnemonicJson = %* {
|
||||||
|
"mnemonicPhrase": mnemonic,
|
||||||
|
"Bip39Passphrase": ""
|
||||||
|
}
|
||||||
|
# libstatus.multiAccountImportMnemonic never results in an error given ANY input
|
||||||
|
let importResult = $libstatus.multiAccountImportMnemonic($mnemonicJson)
|
||||||
|
result = Json.decode(importResult, GeneratedAccount)
|
||||||
|
|
||||||
|
proc deriveAccounts*(accountId: string): MultiAccounts =
|
||||||
|
let deriveJson = %* {
|
||||||
|
"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)
|
||||||
|
|
|
@ -10,6 +10,10 @@ proc multiAccountGenerateAndDeriveAddresses*(paramsJSON: cstring): cstring {.imp
|
||||||
|
|
||||||
proc multiAccountStoreDerivedAccounts*(paramsJSON: cstring): cstring {.importc: "MultiAccountStoreDerivedAccounts".}
|
proc multiAccountStoreDerivedAccounts*(paramsJSON: cstring): cstring {.importc: "MultiAccountStoreDerivedAccounts".}
|
||||||
|
|
||||||
|
proc multiAccountImportMnemonic*(paramsJSON: cstring): cstring {.importc: "MultiAccountImportMnemonic".}
|
||||||
|
|
||||||
|
proc multiAccountDeriveAddresses*(paramsJSON: cstring): cstring {.importc: "MultiAccountDeriveAddresses".}
|
||||||
|
|
||||||
proc saveAccountAndLogin*(accountData: cstring, password: cstring, settingsJSON: cstring, configJSON: cstring, subaccountData: cstring): cstring {.importc: "SaveAccountAndLogin".}
|
proc saveAccountAndLogin*(accountData: cstring, password: cstring, settingsJSON: cstring, configJSON: cstring, subaccountData: cstring): cstring {.importc: "SaveAccountAndLogin".}
|
||||||
|
|
||||||
proc callRPC*(inputJSON: cstring): cstring {.importc: "CallRPC".}
|
proc callRPC*(inputJSON: cstring): cstring {.importc: "CallRPC".}
|
||||||
|
|
|
@ -73,4 +73,4 @@ type AccountArgs* = ref object of Args
|
||||||
account*: Account
|
account*: Account
|
||||||
|
|
||||||
type
|
type
|
||||||
LoginError* = object of Exception
|
StatusGoException* = object of Exception
|
||||||
|
|
|
@ -3,16 +3,230 @@ import QtQuick.Controls 2.4
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts 1.11
|
||||||
import QtQuick.Window 2.11
|
import QtQuick.Window 2.11
|
||||||
import QtQuick.Dialogs 1.3
|
import QtQuick.Dialogs 1.3
|
||||||
|
import "../shared"
|
||||||
|
import "../imports"
|
||||||
|
|
||||||
|
SwipeView {
|
||||||
|
id: swipeView
|
||||||
|
anchors.fill: parent
|
||||||
|
currentIndex: 0
|
||||||
|
|
||||||
|
onCurrentItemChanged: {
|
||||||
|
currentItem.txtPassword.textField.focus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: wizardStep1
|
||||||
|
property Item txtPassword: txtMnemonic
|
||||||
|
width: 620
|
||||||
|
height: 427
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: "Existing key flow [COMING SOON]"
|
id: title
|
||||||
font.pointSize: 36
|
text: "Enter mnemonic"
|
||||||
anchors.centerIn: parent
|
font.pointSize: 36
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 20
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
|
id: txtMnemonic
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.rightMargin: Theme.padding
|
||||||
|
anchors.leftMargin: Theme.padding
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
placeholderText: "Enter 12, 15, 21 or 24 words. Separate words by a single space."
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
btnImport.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledButton {
|
||||||
|
id: btnImport
|
||||||
|
label: "Next"
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: Theme.padding
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
onClicked: {
|
||||||
|
onboardingModel.importMnemonic(txtMnemonic.textField.text);
|
||||||
|
swipeView.incrementCurrentIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: wizardStep2
|
||||||
|
property Item txtPassword: txtPassword
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: step2Title
|
||||||
|
text: "Enter password"
|
||||||
|
font.pointSize: 36
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 20
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: step2Title.bottom
|
||||||
|
anchors.topMargin: 30
|
||||||
|
Column {
|
||||||
|
Image {
|
||||||
|
source: onboardingModel.importedAccount.identicon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Text {
|
||||||
|
text: onboardingModel.importedAccount.username
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: onboardingModel.importedAccount.address
|
||||||
|
width: 160
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
|
id: txtPassword
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.rightMargin: Theme.padding
|
||||||
|
anchors.leftMargin: Theme.padding
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
placeholderText: "Enter password"
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
this.textField.echoMode = TextInput.Password
|
||||||
|
}
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
btnNext.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledButton {
|
||||||
|
id: btnNext
|
||||||
|
label: "Next"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 20
|
||||||
|
onClicked: {
|
||||||
|
swipeView.incrementCurrentIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: wizardStep3
|
||||||
|
property Item txtPassword: txtConfirmPassword
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: step3Title
|
||||||
|
text: "Confirm password"
|
||||||
|
font.pointSize: 36
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 20
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: step3Title.bottom
|
||||||
|
anchors.topMargin: 30
|
||||||
|
Column {
|
||||||
|
Image {
|
||||||
|
source: onboardingModel.importedAccount.identicon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Text {
|
||||||
|
text: onboardingModel.importedAccount.username
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: onboardingModel.importedAccount.address
|
||||||
|
width: 160
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Input {
|
||||||
|
id: txtConfirmPassword
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.rightMargin: Theme.padding
|
||||||
|
anchors.leftMargin: Theme.padding
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
placeholderText: "Confirm entered password"
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
this.textField.echoMode = TextInput.Password
|
||||||
|
}
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
btnFinish.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDialog {
|
||||||
|
id: importError
|
||||||
|
title: "Error importing account"
|
||||||
|
text: "An error occurred while importing your account: "
|
||||||
|
icon: StandardIcon.Critical
|
||||||
|
standardButtons: StandardButton.Ok
|
||||||
|
onAccepted: {
|
||||||
|
swipeView.currentIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDialog {
|
||||||
|
id: importLoginError
|
||||||
|
title: "Login failed"
|
||||||
|
text: "Login failed. Please re-enter your password and try again."
|
||||||
|
icon: StandardIcon.Critical
|
||||||
|
standardButtons: StandardButton.Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: onboardingModel
|
||||||
|
ignoreUnknownSignals: true
|
||||||
|
onLoginResponseChanged: {
|
||||||
|
if(error){
|
||||||
|
importLoginError.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledButton {
|
||||||
|
id: btnFinish
|
||||||
|
label: "Finish"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 20
|
||||||
|
onClicked: {
|
||||||
|
if (txtConfirmPassword.textField.text != txtPassword.textField.text) {
|
||||||
|
return passwordsDontMatchError.open();
|
||||||
|
}
|
||||||
|
const result = onboardingModel.storeDerivedAndLogin(txtConfirmPassword.textField.text);
|
||||||
|
const error = JSON.parse(result).error;
|
||||||
|
if (error) {
|
||||||
|
importError.text += error;
|
||||||
|
importError.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*##^##
|
/*##^##
|
||||||
Designer {
|
Designer {
|
||||||
D{i:0;autoSize:true;height:480;width:640}
|
D{i:0;autoSize:true;height:480;width:640}
|
||||||
}
|
}
|
||||||
##^##*/
|
##^##*/
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls 2.4
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts 1.11
|
||||||
import QtQuick.Window 2.11
|
import QtQuick.Window 2.11
|
||||||
import QtQuick.Dialogs 1.3
|
import QtQuick.Dialogs 1.3
|
||||||
|
import "../imports"
|
||||||
import "../shared"
|
import "../shared"
|
||||||
|
|
||||||
SwipeView {
|
SwipeView {
|
||||||
|
@ -10,15 +11,17 @@ SwipeView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
|
|
||||||
|
property alias btnExistingKey: btnExistingKey
|
||||||
|
|
||||||
onCurrentItemChanged: {
|
onCurrentItemChanged: {
|
||||||
currentItem.txtPassword.focus = true;
|
currentItem.txtPassword.textField.focus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: wizardStep2
|
id: wizardStep1
|
||||||
property int selectedIndex: 0
|
property int selectedIndex: 0
|
||||||
width: 620
|
Layout.fillHeight: true
|
||||||
height: 427
|
Layout.fillWidth: true
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: title
|
id: title
|
||||||
|
@ -37,62 +40,79 @@ SwipeView {
|
||||||
anchors.topMargin: 20
|
anchors.topMargin: 20
|
||||||
|
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: accountGroup
|
id: accountGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: addressViewDelegate
|
id: addressViewDelegate
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
height: 56
|
height: 56
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 0
|
anchors.rightMargin: 0
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 0
|
anchors.leftMargin: 0
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
RadioButton {
|
RadioButton {
|
||||||
checked: index == 0 ? true : false
|
checked: index == 0 ? true : false
|
||||||
ButtonGroup.group: accountGroup
|
ButtonGroup.group: accountGroup
|
||||||
onClicked: {
|
onClicked: {
|
||||||
wizardStep2.selectedIndex = index
|
wizardStep1.selectedIndex = index
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Column {
|
}
|
||||||
Image {
|
Column {
|
||||||
source: identicon
|
Image {
|
||||||
}
|
source: identicon
|
||||||
}
|
}
|
||||||
Column {
|
}
|
||||||
Text {
|
Column {
|
||||||
text: username
|
Text {
|
||||||
}
|
text: username
|
||||||
Text {
|
}
|
||||||
text: key
|
Text {
|
||||||
width: 160
|
text: key
|
||||||
elide: Text.ElideMiddle
|
width: 160
|
||||||
}
|
elide: Text.ElideMiddle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: addressesView
|
id: addressesView
|
||||||
contentWidth: 200
|
contentWidth: 200
|
||||||
model: onboardingModel
|
model: onboardingModel
|
||||||
delegate: addressViewDelegate
|
delegate: addressViewDelegate
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: footer
|
||||||
|
width: btnExistingKey.width + selectBtn.width + Theme.padding
|
||||||
|
height: btnExistingKey.height
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: Theme.padding
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
StyledButton {
|
||||||
|
id: btnExistingKey
|
||||||
|
label: "Access existing key"
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledButton {
|
StyledButton {
|
||||||
label: "Select"
|
id: selectBtn
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.left: btnExistingKey.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.leftMargin: Theme.padding
|
||||||
anchors.bottomMargin: 20
|
label: "Select"
|
||||||
onClicked: {
|
|
||||||
swipeView.incrementCurrentIndex();
|
onClicked: {
|
||||||
|
swipeView.incrementCurrentIndex()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +120,7 @@ SwipeView {
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: wizardStep3
|
id: wizardStep2
|
||||||
property Item txtPassword: txtPassword
|
property Item txtPassword: txtPassword
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@ -111,23 +131,25 @@ SwipeView {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Input {
|
||||||
color: "#EEEEEE"
|
id: txtPassword
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.rightMargin: Theme.padding
|
||||||
|
anchors.leftMargin: Theme.padding
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.centerIn: parent
|
placeholderText: "Enter password"
|
||||||
height: 32
|
|
||||||
width: parent.width - 40
|
Component.onCompleted: {
|
||||||
TextInput {
|
this.textField.echoMode = TextInput.Password
|
||||||
id: txtPassword
|
}
|
||||||
anchors.fill: parent
|
Keys.onReturnPressed: {
|
||||||
focus: true
|
btnNext.clicked()
|
||||||
echoMode: TextInput.Password
|
|
||||||
selectByMouse: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledButton {
|
StyledButton {
|
||||||
|
id: btnNext
|
||||||
label: "Next"
|
label: "Next"
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
@ -139,7 +161,7 @@ SwipeView {
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: wizardStep4
|
id: wizardStep3
|
||||||
property Item txtPassword: txtConfirmPassword
|
property Item txtPassword: txtConfirmPassword
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@ -150,20 +172,20 @@ SwipeView {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Input {
|
||||||
color: "#EEEEEE"
|
id: txtConfirmPassword
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.rightMargin: Theme.padding
|
||||||
|
anchors.leftMargin: Theme.padding
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.centerIn: parent
|
placeholderText: "Confirm entered password"
|
||||||
height: 32
|
|
||||||
width: parent.width - 40
|
|
||||||
|
|
||||||
TextInput {
|
Component.onCompleted: {
|
||||||
id: txtConfirmPassword
|
this.textField.echoMode = TextInput.Password
|
||||||
anchors.fill: parent
|
}
|
||||||
focus: true
|
Keys.onReturnPressed: {
|
||||||
echoMode: TextInput.Password
|
btnFinish.clicked()
|
||||||
selectByMouse: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,26 +212,27 @@ SwipeView {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: onboardingModel
|
target: onboardingModel
|
||||||
|
ignoreUnknownSignals: true
|
||||||
onLoginResponseChanged: {
|
onLoginResponseChanged: {
|
||||||
const loginResponse = JSON.parse(response);
|
if(error){
|
||||||
if(loginResponse.error){
|
storeAccountAndLoginError.text += error;
|
||||||
storeAccountAndLoginError.text += loginResponse.error;
|
|
||||||
storeAccountAndLoginError.open()
|
storeAccountAndLoginError.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledButton {
|
StyledButton {
|
||||||
|
id: btnFinish
|
||||||
label: "Finish"
|
label: "Finish"
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 20
|
anchors.bottomMargin: 20
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (txtConfirmPassword.text != txtPassword.text) {
|
if (txtConfirmPassword.textField.text != txtPassword.textField.text) {
|
||||||
return passwordsDontMatchError.open();
|
return passwordsDontMatchError.open();
|
||||||
}
|
}
|
||||||
const selectedAccountIndex = wizardStep2.selectedIndex
|
const selectedAccountIndex = wizardStep1.selectedIndex
|
||||||
onboardingModel.storeAccountAndLogin(selectedAccountIndex, txtPassword.text)
|
onboardingModel.storeAccountAndLogin(selectedAccountIndex, txtPassword.textField.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,12 @@ SwipeView {
|
||||||
id: swipeView
|
id: swipeView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
|
interactive: false
|
||||||
|
|
||||||
onCurrentItemChanged: {
|
onCurrentItemChanged: {
|
||||||
currentItem.txtPassword.textField.focus = true
|
if(currentItem.txtPassword) {
|
||||||
|
currentItem.txtPassword.textField.focus = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -22,8 +25,6 @@ SwipeView {
|
||||||
property int selectedIndex: 0
|
property int selectedIndex: 0
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
// width: parent.width
|
|
||||||
// height: parent.height
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: title
|
id: title
|
||||||
|
@ -90,6 +91,10 @@ SwipeView {
|
||||||
delegate: addressViewDelegate
|
delegate: addressViewDelegate
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
focus: true
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
selectBtn.clicked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -137,6 +142,7 @@ SwipeView {
|
||||||
anchors.leftMargin: Theme.padding
|
anchors.leftMargin: Theme.padding
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
placeholderText: "Enter password"
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
this.textField.echoMode = TextInput.Password
|
this.textField.echoMode = TextInput.Password
|
||||||
|
@ -160,11 +166,11 @@ SwipeView {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: loginModel
|
target: loginModel
|
||||||
|
ignoreUnknownSignals: true
|
||||||
onLoginResponseChanged: {
|
onLoginResponseChanged: {
|
||||||
const loginResponse = JSON.parse(response)
|
if(error){
|
||||||
if (loginResponse.error) {
|
loginError.open()
|
||||||
loginError.open()
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,12 @@ Page {
|
||||||
id: existingKeyState
|
id: existingKeyState
|
||||||
onEntered: existingKey.visible = true
|
onEntered: existingKey.visible = true
|
||||||
onExited: existingKey.visible = false
|
onExited: existingKey.visible = false
|
||||||
|
|
||||||
|
DSM.SignalTransition {
|
||||||
|
targetState: appState
|
||||||
|
signal: onboardingModel.loginResponseChanged
|
||||||
|
guard: !error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DSM.State {
|
DSM.State {
|
||||||
|
@ -53,10 +59,12 @@ Page {
|
||||||
DSM.SignalTransition {
|
DSM.SignalTransition {
|
||||||
targetState: appState
|
targetState: appState
|
||||||
signal: onboardingModel.loginResponseChanged
|
signal: onboardingModel.loginResponseChanged
|
||||||
guard: {
|
guard: !error
|
||||||
const resp = JSON.parse(response);
|
}
|
||||||
return !resp.error
|
|
||||||
}
|
DSM.SignalTransition {
|
||||||
|
targetState: existingKeyState
|
||||||
|
signal: genKey.btnExistingKey.clicked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +76,7 @@ Page {
|
||||||
DSM.SignalTransition {
|
DSM.SignalTransition {
|
||||||
targetState: appState
|
targetState: appState
|
||||||
signal: loginModel.loginResponseChanged
|
signal: loginModel.loginResponseChanged
|
||||||
guard: {
|
guard: !error
|
||||||
const resp = JSON.parse(response);
|
|
||||||
return !resp.error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DSM.SignalTransition {
|
DSM.SignalTransition {
|
||||||
|
|
Loading…
Reference in New Issue