feat(@desktop/syncing): make a not operable account fully operable, part 1
- handles recovered keypairs Closes the first part of #11779
This commit is contained in:
parent
ec3231ef7e
commit
23fa2f5df3
|
@ -98,8 +98,5 @@ method getKeycardModule*(self: AccessInterface): QVariant {.base.} =
|
|||
method walletModuleDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getWalletAccountsModule*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getWalletNetworksModule*(self: AccessInterface): QVariant {.base.} =
|
||||
method getWalletModule*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -111,7 +111,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
|
|||
result.keycardModule = keycard_module.newModule(result, events, keycardService, settingsService, networkService,
|
||||
privacyService, accountsService, walletAccountService, keychainService)
|
||||
|
||||
result.walletModule = wallet_module.newModule(result, events, walletAccountService, settingsService, networkService)
|
||||
result.walletModule = wallet_module.newModule(result, events, accountsService, walletAccountService, settingsService, networkService)
|
||||
|
||||
singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant)
|
||||
|
||||
|
@ -276,8 +276,5 @@ method getKeycardModule*(self: Module): QVariant =
|
|||
method walletModuleDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method getWalletAccountsModule*(self: Module): QVariant =
|
||||
return self.walletModule.getAccountsModuleAsVariant()
|
||||
|
||||
method getWalletNetworksModule*(self: Module): QVariant =
|
||||
return self.walletModule.getNetworksModuleAsVariant()
|
||||
method getWalletModule*(self: Module): QVariant =
|
||||
return self.walletModule.getModuleAsVariant()
|
|
@ -81,12 +81,7 @@ QtObject:
|
|||
QtProperty[QVariant] keycardModule:
|
||||
read = getKeycardModule
|
||||
|
||||
proc getWalletAccountsModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getWalletAccountsModule()
|
||||
QtProperty[QVariant] walletAccountsModule:
|
||||
read = getWalletAccountsModule
|
||||
|
||||
proc getWalletNetworksModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getWalletNetworksModule()
|
||||
QtProperty[QVariant] walletNetworksModule:
|
||||
read = getWalletNetworksModule
|
||||
proc getWalletModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getWalletModule()
|
||||
QtProperty[QVariant] walletModule:
|
||||
read = getWalletModule
|
||||
|
|
|
@ -130,6 +130,10 @@ method load*(self: Module) =
|
|||
let areTestNetworksEnabled = self.controller.areTestNetworksEnabled()
|
||||
self.view.onUpdatedAccount(walletAccountToWalletAccountItem(args.account, keycardAccount, areTestNetworksEnabled))
|
||||
|
||||
self.events.on(SIGNAL_KEYPAIR_OPERABILITY_CHANGED) do(e:Args):
|
||||
let args = KeypairArgs(e)
|
||||
self.view.onUpdatedKeypairOperability(args.keypair.keyUid, AccountFullyOperable)
|
||||
|
||||
self.events.on(SIGNAL_NEW_KEYCARD_SET) do(e: Args):
|
||||
let args = KeycardArgs(e)
|
||||
if not args.success:
|
||||
|
|
|
@ -51,6 +51,9 @@ QtObject:
|
|||
self.accounts.onUpdatedAccount(account)
|
||||
self.keyPairModel.onUpdatedAccount(account.keyUid, account.address, account.name, account.colorId, account.emoji)
|
||||
|
||||
proc onUpdatedKeypairOperability*(self: View, keyUid, operability: string) =
|
||||
self.keyPairModel.onUpdatedKeypairOperability(keyUid, operability)
|
||||
|
||||
proc onPreferredSharingChainsUpdated*(self: View, keyUid, address, prodPreferredChainIds, testPreferredChainIds: string) =
|
||||
self.keyPairModel.onPreferredSharingChainsUpdated(keyUid, address, prodPreferredChainIds, testPreferredChainIds)
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import io_interface
|
||||
import app/core/eventemitter
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
import app_service/service/devices/service as devices_service
|
||||
|
||||
type
|
||||
Controller* = ref object of RootObj
|
||||
delegate: io_interface.AccessInterface
|
||||
events: EventEmitter
|
||||
walletAccountService: wallet_account_service.Service
|
||||
|
||||
proc newController*(
|
||||
delegate: io_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
walletAccountService: wallet_account_service.Service,
|
||||
): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.events = events
|
||||
result.walletAccountService = walletAccountService
|
||||
|
||||
proc delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
proc init*(self: Controller) =
|
||||
self.events.on(SIGNAL_LOCAL_PAIRING_STATUS_UPDATE) do(e:Args):
|
||||
let data = LocalPairingStatus(e)
|
||||
self.delegate.onLocalPairingStatusUpdate(data)
|
||||
|
||||
proc hasPairedDevices*(self: Controller): bool =
|
||||
return self.walletAccountService.hasPairedDevices()
|
|
@ -1,4 +1,6 @@
|
|||
import NimQml
|
||||
import app/modules/shared_modules/keypair_import/module as keypair_import_module
|
||||
import app_service/service/devices/service as devices_service
|
||||
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
@ -16,18 +18,36 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
|
|||
# View Delegate Interface
|
||||
# Delegate for the view must be declared here due to use of QtObject and multi
|
||||
# inheritance, which is not well supported in Nim.
|
||||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
# Methods called by submodules of this module
|
||||
method accountsModuleDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getAccountsModule*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method networksModuleDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getAccountsModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||
method getNetworksModule*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getNetworksModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||
method getKeypairImportModule*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onKeypairImportModuleLoaded*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method destroyKeypairImportPopup*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method runKeypairImportPopup*(self: AccessInterface, keyUid: string, importOption: ImportOption) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method hasPairedDevices*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onLocalPairingStatusUpdate*(self: AccessInterface, data: LocalPairingStatus) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -1,16 +1,20 @@
|
|||
import NimQml, chronicles
|
||||
|
||||
import ./io_interface as io_interface
|
||||
import ./controller, ./view
|
||||
import ../io_interface as delegate_interface
|
||||
|
||||
import ./accounts/module as accounts_module
|
||||
import ./networks/module as networks_module
|
||||
|
||||
import ../../../../global/global_singleton
|
||||
import ../../../../core/eventemitter
|
||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||
import ../../../../../app_service/service/network/service as network_service
|
||||
import ../../../../../app_service/service/settings/service as settings_service
|
||||
import app/global/global_singleton
|
||||
import app/core/eventemitter
|
||||
import app/modules/shared_modules/keypair_import/module as keypair_import_module
|
||||
import app_service/service/accounts/service as accounts_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
import app_service/service/network/service as network_service
|
||||
import app_service/service/settings/service as settings_service
|
||||
import app_service/service/devices/service as devices_service
|
||||
|
||||
logScope:
|
||||
topics = "profile-section-wallet-module"
|
||||
|
@ -21,43 +25,56 @@ export io_interface
|
|||
type
|
||||
Module* = ref object of io_interface.AccessInterface
|
||||
delegate: delegate_interface.AccessInterface
|
||||
controller: Controller
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
events: EventEmitter
|
||||
moduleLoaded: bool
|
||||
|
||||
accountsService: accounts_service.Service
|
||||
walletAccountService: wallet_account_service.Service
|
||||
accountsModule: accounts_module.AccessInterface
|
||||
networksModule: networks_module.AccessInterface
|
||||
keypairImportModule: keypair_import_module.AccessInterface
|
||||
|
||||
proc newModule*(
|
||||
delegate: delegate_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
accountsService: accounts_service.Service,
|
||||
walletAccountService: wallet_account_service.Service,
|
||||
settingsService: settings_service.Service,
|
||||
networkService: network_service.Service,
|
||||
): Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.controller = controller.newController(result, events, walletAccountService)
|
||||
result.view = newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.events = events
|
||||
result.moduleLoaded = false
|
||||
|
||||
result.accountsService = accountsService
|
||||
result.walletAccountService = walletAccountService
|
||||
result.accountsModule = accounts_module.newModule(result, events, walletAccountService, networkService)
|
||||
result.networksModule = networks_module.newModule(result, events, networkService, walletAccountService, settingsService)
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.controller.delete
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.accountsModule.delete
|
||||
self.networksModule.delete
|
||||
if not self.keypairImportModule.isNil:
|
||||
self.keypairImportModule.delete
|
||||
|
||||
method load*(self: Module) =
|
||||
self.controller.init()
|
||||
self.accountsModule.load()
|
||||
self.networksModule.load()
|
||||
|
||||
method isLoaded*(self: Module): bool =
|
||||
return self.moduleLoaded
|
||||
|
||||
method getAccountsModuleAsVariant*(self: Module): QVariant =
|
||||
return self.accountsModule.getModuleAsVariant()
|
||||
|
||||
method getNetworksModuleAsVariant*(self: Module): QVariant =
|
||||
return self.networksModule.getModuleAsVariant()
|
||||
method getModuleAsVariant*(self: Module): QVariant =
|
||||
return self.viewVariant
|
||||
|
||||
proc checkIfModuleDidLoad(self: Module) =
|
||||
if(not self.accountsModule.isLoaded()):
|
||||
|
@ -75,5 +92,37 @@ method viewDidLoad*(self: Module) =
|
|||
method accountsModuleDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method getAccountsModule*(self: Module): QVariant =
|
||||
return self.accountsModule.getModuleAsVariant()
|
||||
|
||||
method networksModuleDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method getNetworksModule*(self: Module): QVariant =
|
||||
return self.networksModule.getModuleAsVariant()
|
||||
|
||||
method destroyKeypairImportPopup*(self: Module) =
|
||||
if self.keypairImportModule.isNil:
|
||||
return
|
||||
self.view.emitDestroyKeypairImportPopup()
|
||||
self.keypairImportModule.delete
|
||||
self.keypairImportModule = nil
|
||||
|
||||
method runKeypairImportPopup*(self: Module, keyUid: string, importOption: ImportOption) =
|
||||
self.keypairImportModule = keypair_import_module.newModule(self, self.events, self.accountsService, self.walletAccountService)
|
||||
self.keypairImportModule.load(keyUid, importOption)
|
||||
|
||||
method getKeypairImportModule*(self: Module): QVariant =
|
||||
if self.keypairImportModule.isNil:
|
||||
return newQVariant()
|
||||
return self.keypairImportModule.getModuleAsVariant()
|
||||
|
||||
method onKeypairImportModuleLoaded*(self: Module) =
|
||||
self.view.emitDisplayKeypairImportPopup()
|
||||
|
||||
method hasPairedDevices*(self: Module): bool =
|
||||
return self.controller.hasPairedDevices()
|
||||
|
||||
method onLocalPairingStatusUpdate*(self: Module, data: LocalPairingStatus) =
|
||||
if data.state == LocalPairingState.Finished:
|
||||
self.view.emitHasPairedDevicesChangedSignal()
|
|
@ -0,0 +1,52 @@
|
|||
import NimQml
|
||||
|
||||
import ./io_interface
|
||||
from app/modules/shared_modules/keypair_import/module import ImportOption
|
||||
|
||||
QtObject:
|
||||
type
|
||||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.delegate = delegate
|
||||
|
||||
proc getAccountsModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getAccountsModule()
|
||||
QtProperty[QVariant] accountsModule:
|
||||
read = getAccountsModule
|
||||
|
||||
proc getNetworksModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getNetworksModule()
|
||||
QtProperty[QVariant] networksModule:
|
||||
read = getNetworksModule
|
||||
|
||||
proc runKeypairImportPopup*(self: View, keyUid: string, importOption: int) {.slot.} =
|
||||
self.delegate.runKeypairImportPopup(keyUid, ImportOption(importOption))
|
||||
|
||||
proc getKeypairImportModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getKeypairImportModule()
|
||||
QtProperty[QVariant] keypairImportModule:
|
||||
read = getKeypairImportModule
|
||||
|
||||
proc displayKeypairImportPopup*(self: View) {.signal.}
|
||||
proc emitDisplayKeypairImportPopup*(self: View) =
|
||||
self.displayKeypairImportPopup()
|
||||
|
||||
proc destroyKeypairImportPopup*(self: View) {.signal.}
|
||||
proc emitDestroyKeypairImportPopup*(self: View) =
|
||||
self.destroyKeypairImportPopup()
|
||||
|
||||
proc hasPairedDevicesChanged*(self: View) {.signal.}
|
||||
proc emitHasPairedDevicesChangedSignal*(self: View) =
|
||||
self.hasPairedDevicesChanged()
|
||||
proc getHasPairedDevices(self: View): bool {.slot.} =
|
||||
return self.delegate.hasPairedDevices()
|
||||
QtProperty[bool] hasPairedDevices:
|
||||
read = getHasPairedDevices
|
||||
notify = hasPairedDevicesChanged
|
|
@ -10,82 +10,62 @@ export keypair_item
|
|||
logScope:
|
||||
topics = "shared-keypairs"
|
||||
|
||||
proc buildKeyPairsList*(keypairs: seq[KeypairDto], excludeAlreadyMigratedPairs: bool,
|
||||
excludePrivateKeyKeypairs: bool, areTestNetworksEnabled: bool = false): seq[KeyPairItem] =
|
||||
var items: seq[KeyPairItem]
|
||||
for kp in keypairs:
|
||||
if kp.accounts.len == 0:
|
||||
proc buildKeypairItem*(keypair: KeypairDto, areTestNetworksEnabled: bool): KeyPairItem =
|
||||
if keypair.accounts.len == 0:
|
||||
## we should never be here
|
||||
error "there must not be any keypair without accounts", keyUid=kp.keyUid
|
||||
error "there must not be any keypair without accounts", keyUid=keypair.keyUid
|
||||
return
|
||||
let publicKey = kp.accounts[0].publicKey # in case of other but the profile keypair we take public key of first account as keypair's public key
|
||||
let kpMigrated = kp.keycards.len > 0
|
||||
if excludeAlreadyMigratedPairs and kpMigrated:
|
||||
continue
|
||||
if kp.keypairType == KeypairTypeProfile:
|
||||
var item = newKeyPairItem(keyUid = kp.keyUid,
|
||||
pubKey = singletonInstance.userProfile.getPubKey(),
|
||||
let publicKey = keypair.accounts[0].publicKey # in case of other but the profile keypair we take public key of first account as keypair's public key
|
||||
var item = newKeyPairItem(keyUid = keypair.keyUid,
|
||||
pubKey = publicKey,
|
||||
locked = false,
|
||||
name = singletonInstance.userProfile.getName(),
|
||||
image = singletonInstance.userProfile.getIcon(),
|
||||
name = keypair.name,
|
||||
image = "",
|
||||
icon = "",
|
||||
pairType = KeyPairType.Profile,
|
||||
derivedFrom = kp.derivedFrom,
|
||||
lastUsedDerivationIndex = kp.lastUsedDerivationIndex,
|
||||
migratedToKeycard = kpMigrated,
|
||||
syncedFrom = kp.syncedFrom)
|
||||
for acc in kp.accounts:
|
||||
pairType = KeyPairType.Unknown,
|
||||
derivedFrom = keypair.derivedFrom,
|
||||
lastUsedDerivationIndex = keypair.lastUsedDerivationIndex,
|
||||
migratedToKeycard = keypair.keycards.len > 0,
|
||||
syncedFrom = keypair.syncedFrom)
|
||||
|
||||
if keypair.keypairType == KeypairTypeProfile:
|
||||
item.setPubKey(singletonInstance.userProfile.getPubKey())
|
||||
item.setName(singletonInstance.userProfile.getName())
|
||||
item.setImage(singletonInstance.userProfile.getIcon())
|
||||
item.setPairType(KeyPairType.Profile.int)
|
||||
elif keypair.keypairType == KeypairTypeSeed:
|
||||
item.setIcon(if item.getMigratedToKeycard(): "keycard" else: "key_pair_seed_phrase")
|
||||
item.setPairType(KeyPairType.SeedImport.int)
|
||||
elif keypair.keypairType == KeypairTypeKey:
|
||||
item.setIcon(if item.getMigratedToKeycard(): "keycard" else: "objects")
|
||||
item.setPairType(KeyPairType.PrivateKeyImport.int)
|
||||
|
||||
for acc in keypair.accounts:
|
||||
if acc.isChat:
|
||||
continue
|
||||
var icon = ""
|
||||
if acc.emoji.len == 0:
|
||||
icon = "wallet"
|
||||
item.addAccount(newKeyPairAccountItem(acc.name, acc.path, acc.address, acc.publicKey, acc.emoji, acc.colorId,
|
||||
icon, newCurrencyAmount(), balanceFetched = true, operability = acc.operable, acc.isWallet, areTestNetworksEnabled, acc.prodPreferredChainIds, acc.testPreferredChainIds))
|
||||
icon, newCurrencyAmount(), balanceFetched = true, operability = acc.operable, acc.isWallet, areTestNetworksEnabled,
|
||||
acc.prodPreferredChainIds, acc.testPreferredChainIds))
|
||||
return item
|
||||
|
||||
proc buildKeyPairsList*(keypairs: seq[KeypairDto], excludeAlreadyMigratedPairs: bool,
|
||||
excludePrivateKeyKeypairs: bool, areTestNetworksEnabled: bool = false): seq[KeyPairItem] =
|
||||
var items: seq[KeyPairItem]
|
||||
for kp in keypairs:
|
||||
let item = buildKeypairItem(kp, areTestNetworksEnabled)
|
||||
if item.isNil:
|
||||
continue
|
||||
if excludeAlreadyMigratedPairs and item.getMigratedToKeycard():
|
||||
continue
|
||||
if item.getPairType() == KeypairType.Profile.int:
|
||||
items.insert(item, 0) # Status Account must be at first place
|
||||
continue
|
||||
if kp.keypairType == KeypairTypeSeed:
|
||||
var item = newKeyPairItem(keyUid = kp.keyUid,
|
||||
pubKey = publicKey,
|
||||
locked = false,
|
||||
name = kp.name,
|
||||
image = "",
|
||||
icon = if kpMigrated: "keycard" else: "key_pair_seed_phrase",
|
||||
pairType = KeyPairType.SeedImport,
|
||||
derivedFrom = kp.derivedFrom,
|
||||
lastUsedDerivationIndex = kp.lastUsedDerivationIndex,
|
||||
migratedToKeycard = kpMigrated,
|
||||
syncedFrom = kp.syncedFrom)
|
||||
for acc in kp.accounts:
|
||||
var icon = ""
|
||||
if acc.emoji.len == 0:
|
||||
icon = "wallet"
|
||||
item.addAccount(newKeyPairAccountItem(acc.name, acc.path, acc.address, acc.publicKey, acc.emoji, acc.colorId,
|
||||
icon, newCurrencyAmount(), balanceFetched = true, operability = acc.operable, acc.isWallet, areTestNetworksEnabled, acc.prodPreferredChainIds, acc.testPreferredChainIds))
|
||||
if item.getPairType() == KeypairType.PrivateKeyImport.int and excludePrivateKeyKeypairs:
|
||||
continue
|
||||
items.add(item)
|
||||
continue
|
||||
if kp.keypairType == KeypairTypeKey:
|
||||
if excludePrivateKeyKeypairs:
|
||||
continue
|
||||
var item = newKeyPairItem(keyUid = kp.keyUid,
|
||||
pubKey = publicKey,
|
||||
locked = false,
|
||||
name = kp.name,
|
||||
image = "",
|
||||
icon = if kpMigrated: "keycard" else: "objects",
|
||||
pairType = KeyPairType.PrivateKeyImport,
|
||||
derivedFrom = kp.derivedFrom,
|
||||
lastUsedDerivationIndex = kp.lastUsedDerivationIndex,
|
||||
migratedToKeycard = kpMigrated,
|
||||
syncedFrom = kp.syncedFrom)
|
||||
for acc in kp.accounts:
|
||||
var icon = ""
|
||||
if acc.emoji.len == 0:
|
||||
icon = "wallet"
|
||||
item.addAccount(newKeyPairAccountItem(acc.name, acc.path, acc.address, acc.publicKey, acc.emoji, acc.colorId,
|
||||
icon, newCurrencyAmount(), balanceFetched = true, operability = acc.operable, acc.isWallet, areTestNetworksEnabled, acc.prodPreferredChainIds, acc.testPreferredChainIds))
|
||||
items.add(item)
|
||||
continue
|
||||
if items.len == 0:
|
||||
debug "sm_there is no any key pair for the logged in user that is not already migrated to a keycard"
|
||||
return items
|
|
@ -125,9 +125,8 @@ QtObject:
|
|||
self.items[i].setEmoji(emoji)
|
||||
return
|
||||
|
||||
proc updateOperabilityForAddress*(self: KeyPairAccountModel, address: string, operability: string) =
|
||||
proc updateOperabilityForAllAddresses*(self: KeyPairAccountModel, operability: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if cmpIgnoreCase(self.items[i].getAddress(), address) == 0:
|
||||
self.items[i].setOperability(operability)
|
||||
|
||||
proc setBalanceForAddress*(self: KeyPairAccountModel, address: string, balance: CurrencyAmount) =
|
||||
|
|
|
@ -270,8 +270,8 @@ QtObject:
|
|||
self.accounts.updatePreferredSharingChainsForAddress(address, prodPreferredChainIds, testPreferredChainIds)
|
||||
proc setBalanceForAddress*(self: KeyPairItem, address: string, balance: CurrencyAmount) =
|
||||
self.accounts.setBalanceForAddress(address, balance)
|
||||
proc updateOperabilityForAccountWithAddress*(self: KeyPairItem, address: string, operability: string) =
|
||||
self.accounts.updateOperabilityForAddress(address, operability)
|
||||
proc updateOperabilityForAllAddresses*(self: KeyPairItem, operability: string) =
|
||||
self.accounts.updateOperabilityForAllAddresses(operability)
|
||||
self.operabilityChanged()
|
||||
|
||||
proc setItem*(self: KeyPairItem, item: KeyPairItem) =
|
||||
|
|
|
@ -82,6 +82,12 @@ QtObject:
|
|||
item.getAccountsModel().updateDetailsForAddressIfTheyAreSet(address, name, colorId, emoji)
|
||||
break
|
||||
|
||||
proc onUpdatedKeypairOperability*(self: KeyPairModel, keyUid, operability: string) =
|
||||
for item in self.items:
|
||||
if keyUid == item.getKeyUid():
|
||||
item.updateOperabilityForAllAddresses(operability)
|
||||
break
|
||||
|
||||
proc onPreferredSharingChainsUpdated*(self: KeyPairModel,keyUid, address, prodPreferredChainIds, testPreferredChainIds: string) =
|
||||
for item in self.items:
|
||||
if keyUid == item.getKeyUid():
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import NimQml, Tables, strutils, sequtils, sugar, chronicles
|
||||
|
||||
import io_interface
|
||||
import view, controller, derived_address_model
|
||||
import view, controller
|
||||
import internal/[state, state_factory]
|
||||
|
||||
import ../../../core/eventemitter
|
||||
|
@ -9,7 +9,7 @@ import ../../../core/eventemitter
|
|||
import ../../../global/global_singleton
|
||||
|
||||
import ../../shared/keypairs
|
||||
import ../../shared_models/[keypair_model]
|
||||
import ../../shared_models/[keypair_model, derived_address_model]
|
||||
import ../../shared_modules/keycard_popup/module as keycard_shared_module
|
||||
|
||||
import ../../../../app_service/common/account_constants
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import NimQml
|
||||
import io_interface
|
||||
import derived_address_model
|
||||
import internal/[state, state_wrapper]
|
||||
import ../../shared_models/[keypair_model, keypair_item]
|
||||
import ../../shared_models/[keypair_model, keypair_item, derived_address_model]
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
import times, chronicles
|
||||
import io_interface
|
||||
|
||||
import app/core/eventemitter
|
||||
import app_service/service/accounts/service as accounts_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
|
||||
import app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_module
|
||||
|
||||
logScope:
|
||||
topics = "wallet-keycard-import-controller"
|
||||
|
||||
const UNIQUE_WALLET_SECTION_KEYPAIR_IMPORT_MODULE_IDENTIFIER* = "WalletSection-KeypairImportModule"
|
||||
|
||||
type
|
||||
Controller* = ref object of RootObj
|
||||
delegate: io_interface.AccessInterface
|
||||
events: EventEmitter
|
||||
accountsService: accounts_service.Service
|
||||
walletAccountService: wallet_account_service.Service
|
||||
uniqueFetchingDetailsId: string
|
||||
tmpPrivateKey: string
|
||||
tmpSeedPhrase: string
|
||||
tmpGeneratedAccount: GeneratedAccountDto
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
accountsService: accounts_service.Service,
|
||||
walletAccountService: wallet_account_service.Service):
|
||||
Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.events = events
|
||||
result.accountsService = accountsService
|
||||
result.walletAccountService = walletAccountService
|
||||
|
||||
proc delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
proc init*(self: Controller) =
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
|
||||
let args = SharedKeycarModuleArgs(e)
|
||||
if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_KEYPAIR_IMPORT_MODULE_IDENTIFIER:
|
||||
return
|
||||
self.delegate.onUserAuthenticated(args.pin, args.password, args.keyUid)
|
||||
|
||||
self.events.on(SIGNAL_WALLET_ACCOUNT_ADDRESS_DETAILS_FETCHED) do(e:Args):
|
||||
var args = DerivedAddressesArgs(e)
|
||||
if args.uniqueId != self.uniqueFetchingDetailsId:
|
||||
return
|
||||
self.delegate.onAddressDetailsFetched(args.derivedAddresses, args.error)
|
||||
|
||||
proc closeKeypairImportPopup*(self: Controller) =
|
||||
self.delegate.closeKeypairImportPopup()
|
||||
|
||||
proc setPrivateKey*(self: Controller, value: string) =
|
||||
self.tmpPrivateKey = value
|
||||
|
||||
proc getPrivateKey*(self: Controller): string =
|
||||
return self.tmpPrivateKey
|
||||
|
||||
proc setSeedPhrase*(self: Controller, value: string) =
|
||||
self.tmpSeedPhrase = value
|
||||
|
||||
proc getSeedPhrase*(self: Controller): string =
|
||||
return self.tmpSeedPhrase
|
||||
|
||||
proc authenticateLoggedInUser*(self: Controller) =
|
||||
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_WALLET_SECTION_KEYPAIR_IMPORT_MODULE_IDENTIFIER)
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
|
||||
|
||||
proc getKeypairByKeyUid*(self: Controller, keyUid: string): KeypairDto =
|
||||
return self.walletAccountService.getKeypairByKeyUid(keyUid)
|
||||
|
||||
proc createAccountFromPrivateKey*(self: Controller, privateKey: string): GeneratedAccountDto =
|
||||
self.setPrivateKey(privateKey)
|
||||
self.tmpGeneratedAccount = self.accountsService.createAccountFromPrivateKey(privateKey)
|
||||
return self.tmpGeneratedAccount
|
||||
|
||||
proc createAccountFromSeedPhrase*(self: Controller, seedPhrase: string): GeneratedAccountDto =
|
||||
self.setSeedPhrase(seedPhrase)
|
||||
self.tmpGeneratedAccount = self.accountsService.createAccountFromMnemonic(seedPhrase)
|
||||
return self.tmpGeneratedAccount
|
||||
|
||||
proc getGeneratedAccount*(self: Controller): GeneratedAccountDto =
|
||||
return self.tmpGeneratedAccount
|
||||
|
||||
proc fetchDetailsForAddresses*(self: Controller, addresses: seq[string]) =
|
||||
self.uniqueFetchingDetailsId = $now().toTime().toUnix()
|
||||
self.walletAccountService.fetchDetailsForAddresses(self.uniqueFetchingDetailsId, addresses)
|
||||
|
||||
proc makePrivateKeyKeypairFullyOperable*(self: Controller, keyUid, privateKey, password: string, doPasswordHashing: bool): string =
|
||||
return self.walletAccountService.makePrivateKeyKeypairFullyOperable(keyUid, privateKey, password, doPasswordHashing)
|
||||
|
||||
proc makeSeedPhraseKeypairFullyOperable*(self: Controller, keyUid, mnemonic, password: string, doPasswordHashing: bool): string =
|
||||
return self.walletAccountService.makeSeedPhraseKeypairFullyOperable(keyUid, mnemonic, password, doPasswordHashing)
|
|
@ -0,0 +1,12 @@
|
|||
type
|
||||
ImportPrivateKeyState* = ref object of State
|
||||
|
||||
proc newImportPrivateKeyState*(backState: State): ImportPrivateKeyState =
|
||||
result = ImportPrivateKeyState()
|
||||
result.setup(StateType.ImportPrivateKey, backState)
|
||||
|
||||
proc delete*(self: ImportPrivateKeyState) =
|
||||
self.State.delete
|
||||
|
||||
method executePrePrimaryStateCommand*(self: ImportPrivateKeyState, controller: Controller) =
|
||||
controller.authenticateLoggedInUser()
|
|
@ -0,0 +1,12 @@
|
|||
type
|
||||
ImportSeedPhraseState* = ref object of State
|
||||
|
||||
proc newImportSeedPhraseState*(backState: State): ImportSeedPhraseState =
|
||||
result = ImportSeedPhraseState()
|
||||
result.setup(StateType.ImportSeedPhrase, backState)
|
||||
|
||||
proc delete*(self: ImportSeedPhraseState) =
|
||||
self.State.delete
|
||||
|
||||
method executePrePrimaryStateCommand*(self: ImportSeedPhraseState, controller: Controller) =
|
||||
controller.authenticateLoggedInUser()
|
|
@ -0,0 +1,81 @@
|
|||
import ../controller
|
||||
|
||||
type StateType* {.pure.} = enum
|
||||
NoState = "NoState"
|
||||
Main = "Main"
|
||||
ImportSeedPhrase = "ImportSeedPhrase"
|
||||
ImportPrivateKey = "ImportPrivateKey"
|
||||
|
||||
|
||||
## This is the base class for all states
|
||||
## We should not instance of this class (in c++ this will be an abstract class).
|
||||
type
|
||||
State* {.pure inheritable.} = ref object of RootObj
|
||||
stateType: StateType
|
||||
backState: State
|
||||
|
||||
proc setup*(self: State, stateType: StateType, backState: State) =
|
||||
self.stateType = stateType
|
||||
self.backState = backState
|
||||
|
||||
## `stateType` - detemines the state this instance describes
|
||||
## `backState` - the sate (instance) we're moving to if user clicks "back" button,
|
||||
## in case we should not display "back" button for this state, set it to `nil`
|
||||
proc newState*(self: State, stateType: StateType, backState: State): State =
|
||||
result = State()
|
||||
result.setup(stateType, backState)
|
||||
|
||||
proc delete*(self: State) =
|
||||
discard
|
||||
|
||||
## Returns state type
|
||||
method stateType*(self: State): StateType {.inline base.} =
|
||||
self.stateType
|
||||
|
||||
## Returns back state instance
|
||||
method getBackState*(self: State): State {.inline base.} =
|
||||
self.backState
|
||||
|
||||
## Returns true if we should display "back" button, otherwise false
|
||||
method displayBackButton*(self: State): bool {.inline base.} =
|
||||
return not self.backState.isNil
|
||||
|
||||
## Returns next state instance if "primary" action is triggered
|
||||
method getNextPrimaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||
return nil
|
||||
|
||||
## Returns next state instance if "secondary" action is triggered
|
||||
method getNextSecondaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||
return nil
|
||||
|
||||
## Returns next state instance in case the "tertiary" action is triggered
|
||||
method getNextTertiaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||
return nil
|
||||
|
||||
## Returns next state instance in case the "quaternary" action is triggered
|
||||
method getNextQuaternaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||
return nil
|
||||
|
||||
## This method is executed if "cancel" action is triggered (invalidates current flow)
|
||||
method executeCancelCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
controller.closeKeypairImportPopup()
|
||||
|
||||
## This method is executed before back state is set, if "back" action is triggered
|
||||
method executePreBackStateCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
discard
|
||||
|
||||
## This method is executed before primary state is set, if "primary" action is triggered
|
||||
method executePrePrimaryStateCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
discard
|
||||
|
||||
## This method is executed before secondary state is set, if "secondary" action is triggered
|
||||
method executePreSecondaryStateCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
discard
|
||||
|
||||
## This method is executed in case "tertiary" action is triggered
|
||||
method executePreTertiaryStateCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
discard
|
||||
|
||||
## This method is executed in case "quaternary" action is triggered
|
||||
method executePreQuaternaryStateCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
discard
|
|
@ -0,0 +1,21 @@
|
|||
import chronicles
|
||||
import ../controller
|
||||
|
||||
import state
|
||||
|
||||
logScope:
|
||||
topics = "keypair-import-module-state-factory"
|
||||
|
||||
# Forward declaration
|
||||
proc createState*(stateToBeCreated: StateType, backState: State): State
|
||||
|
||||
include import_private_key_state
|
||||
include import_seed_phrase_state
|
||||
|
||||
proc createState*(stateToBeCreated: StateType, backState: State): State =
|
||||
if stateToBeCreated == StateType.ImportPrivateKey:
|
||||
return newImportPrivateKeyState(backState)
|
||||
if stateToBeCreated == StateType.ImportSeedPhrase:
|
||||
return newImportSeedPhraseState(backState)
|
||||
|
||||
error "Keypair import - no implementation available for state", state=stateToBeCreated
|
|
@ -0,0 +1,62 @@
|
|||
import NimQml
|
||||
import state
|
||||
|
||||
QtObject:
|
||||
type StateWrapper* = ref object of QObject
|
||||
stateObj: State
|
||||
|
||||
proc delete*(self: StateWrapper) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newStateWrapper*(): StateWrapper =
|
||||
new(result, delete)
|
||||
result.QObject.setup()
|
||||
|
||||
proc stateWrapperChanged*(self:StateWrapper) {.signal.}
|
||||
|
||||
proc setStateObj*(self: StateWrapper, stateObj: State) =
|
||||
self.stateObj = stateObj
|
||||
self.stateWrapperChanged()
|
||||
|
||||
proc getStateObj*(self: StateWrapper): State =
|
||||
return self.stateObj
|
||||
|
||||
proc getStateType(self: StateWrapper): string {.slot.} =
|
||||
if(self.stateObj.isNil):
|
||||
return $StateType.NoState
|
||||
return $self.stateObj.stateType()
|
||||
QtProperty[string] stateType:
|
||||
read = getStateType
|
||||
notify = stateWrapperChanged
|
||||
|
||||
proc getDisplayBackButton(self: StateWrapper): bool {.slot.} =
|
||||
if(self.stateObj.isNil):
|
||||
return false
|
||||
return self.stateObj.displayBackButton()
|
||||
QtProperty[bool] displayBackButton:
|
||||
read = getDisplayBackButton
|
||||
notify = stateWrapperChanged
|
||||
|
||||
proc backActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doBackAction*(self: StateWrapper) {.slot.} =
|
||||
self.backActionClicked()
|
||||
|
||||
proc cancelActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doCancelAction*(self: StateWrapper) {.slot.} =
|
||||
self.cancelActionClicked()
|
||||
|
||||
proc primaryActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doPrimaryAction*(self: StateWrapper) {.slot.} =
|
||||
self.primaryActionClicked()
|
||||
|
||||
proc secondaryActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doSecondaryAction*(self: StateWrapper) {.slot.} =
|
||||
self.secondaryActionClicked()
|
||||
|
||||
proc tertiaryActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doTertiaryAction*(self: StateWrapper) {.slot.} =
|
||||
self.tertiaryActionClicked()
|
||||
|
||||
proc quaternaryActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doQuaternaryAction*(self: StateWrapper) {.slot.} =
|
||||
self.quaternaryActionClicked()
|
|
@ -0,0 +1,51 @@
|
|||
import Tables, NimQml
|
||||
|
||||
import app_service/service/wallet_account/dto/derived_address_dto
|
||||
|
||||
type ImportOption* {.pure.}= enum
|
||||
SeedPhrase = 1,
|
||||
PrivateKey = 2
|
||||
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
||||
method delete*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method load*(self: AccessInterface, keyUid: string, importOption: ImportOption) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method closeKeypairImportPopup*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onBackActionClicked*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onPrimaryActionClicked*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onCancelActionClicked*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onUserAuthenticated*(self: AccessInterface, pin: string, password: string, keyUid: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method changePrivateKey*(self: AccessInterface, privateKey: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method changeSeedPhrase*(self: AccessInterface, seedPhrase: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method validSeedPhrase*(self: AccessInterface, seedPhrase: string): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onAddressDetailsFetched*(self: AccessInterface, derivedAddresses: seq[DerivedAddressDto], error: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
type
|
||||
DelegateInterface* = concept c
|
||||
c.onKeypairImportModuleLoaded()
|
||||
c.destroyKeypairImportPopup()
|
|
@ -0,0 +1,188 @@
|
|||
import NimQml, strutils, chronicles
|
||||
|
||||
import io_interface
|
||||
import view, controller
|
||||
import internal/[state, state_factory]
|
||||
|
||||
import app/global/global_singleton
|
||||
import app/core/eventemitter
|
||||
import app/modules/shared/keypairs
|
||||
import app/modules/shared_models/[derived_address_model]
|
||||
import app_service/service/accounts/service as accounts_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
|
||||
export io_interface
|
||||
|
||||
logScope:
|
||||
topics = "wallet-keypair-import-module"
|
||||
|
||||
type
|
||||
Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
|
||||
delegate: T
|
||||
events: EventEmitter
|
||||
view: View
|
||||
viewVariant: QVariant
|
||||
controller: Controller
|
||||
|
||||
proc newModule*[T](delegate: T,
|
||||
events: EventEmitter,
|
||||
accountsService: accounts_service.Service,
|
||||
walletAccountService: wallet_account_service.Service):
|
||||
Module[T] =
|
||||
result = Module[T]()
|
||||
result.delegate = delegate
|
||||
result.view = newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, events, accountsService, walletAccountService)
|
||||
|
||||
method delete*[T](self: Module[T]) =
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
method closeKeypairImportPopup*[T](self: Module[T]) =
|
||||
self.delegate.destroyKeypairImportPopup()
|
||||
|
||||
method getModuleAsVariant*[T](self: Module[T]): QVariant =
|
||||
return self.viewVariant
|
||||
|
||||
method load*[T](self: Module[T], keyUid: string, importOption: ImportOption) =
|
||||
self.controller.init()
|
||||
let keypair = self.controller.getKeypairByKeyUid(keyUid)
|
||||
if keypair.isNil:
|
||||
error "trying to import an unknown keypair"
|
||||
self.closeKeypairImportPopup()
|
||||
return
|
||||
let keypairItem = buildKeypairItem(keypair, areTestNetworksEnabled = false) # testnetworks are irrelevant in this context
|
||||
if keypairItem.isNil:
|
||||
error "cannot generate keypair item for provided keypair"
|
||||
self.closeKeypairImportPopup()
|
||||
return
|
||||
self.view.setSelectedKeypair(keypairItem)
|
||||
if importOption == ImportOption.PrivateKey:
|
||||
self.view.setCurrentState(newImportPrivateKeyState(nil))
|
||||
elif importOption == ImportOption.SeedPhrase:
|
||||
self.view.setCurrentState(newImportSeedPhraseState(nil))
|
||||
self.delegate.onKeypairImportModuleLoaded()
|
||||
|
||||
method onBackActionClicked*[T](self: Module[T]) =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "ki_cannot resolve current state"
|
||||
return
|
||||
debug "ki_back_action", currState=currStateObj.stateType()
|
||||
currStateObj.executePreBackStateCommand(self.controller)
|
||||
let backState = currStateObj.getBackState()
|
||||
if backState.isNil:
|
||||
return
|
||||
self.view.setCurrentState(backState)
|
||||
debug "ki_back_action - set state", newCurrState=backState.stateType()
|
||||
|
||||
method onCancelActionClicked*[T](self: Module[T]) =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "ki_cannot resolve current state"
|
||||
return
|
||||
debug "ki_cancel_action", currState=currStateObj.stateType()
|
||||
currStateObj.executeCancelCommand(self.controller)
|
||||
|
||||
method onPrimaryActionClicked*[T](self: Module[T]) =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "ki_cannot resolve current state"
|
||||
return
|
||||
debug "ki_primary_action", currState=currStateObj.stateType()
|
||||
currStateObj.executePrePrimaryStateCommand(self.controller)
|
||||
let nextState = currStateObj.getNextPrimaryState(self.controller)
|
||||
if nextState.isNil:
|
||||
return
|
||||
self.view.setCurrentState(nextState)
|
||||
debug "ki_primary_action - set state", setCurrState=nextState.stateType()
|
||||
|
||||
proc authenticateLoggedInUser[T](self: Module[T]) =
|
||||
self.controller.authenticateLoggedInUser()
|
||||
|
||||
method changePrivateKey*[T](self: Module[T], privateKey: string) =
|
||||
self.view.setPrivateKeyAccAddress(newDerivedAddressItem())
|
||||
if privateKey.len == 0:
|
||||
return
|
||||
let genAccDto = self.controller.createAccountFromPrivateKey(privateKey)
|
||||
if genAccDto.address.len == 0:
|
||||
error "unable to resolve an address from the provided private key"
|
||||
return
|
||||
let kp = self.view.getSelectedKeypair()
|
||||
if kp.isNil:
|
||||
# should never be here
|
||||
return
|
||||
if kp.getKeyUid() != genAccDto.keyUid:
|
||||
self.view.setEnteredPrivateKeyMatchTheKeypair(false)
|
||||
error "entered private key doesn't refer to a keyapir being imported"
|
||||
return
|
||||
self.view.setEnteredPrivateKeyMatchTheKeypair(true)
|
||||
self.view.setPrivateKeyAccAddress(newDerivedAddressItem(order = 0, address = genAccDto.address, publicKey = genAccDto.publicKey))
|
||||
self.controller.fetchDetailsForAddresses(@[genAccDto.address])
|
||||
|
||||
method changeSeedPhrase*[T](self: Module[T], seedPhrase: string) =
|
||||
if seedPhrase.len == 0:
|
||||
return
|
||||
let genAccDto = self.controller.createAccountFromSeedPhrase(seedPhrase)
|
||||
if seedPhrase.len > 0 and genAccDto.address.len == 0:
|
||||
error "unable to create an account from the provided seed phrase"
|
||||
return
|
||||
|
||||
method validSeedPhrase*[T](self: Module[T], seedPhrase: string): bool =
|
||||
let genAccDto = self.controller.createAccountFromSeedPhrase(seedPhrase)
|
||||
let kp = self.view.getSelectedKeypair()
|
||||
if kp.isNil:
|
||||
# should never be here
|
||||
return false
|
||||
return kp.getKeyUid() == genAccDto.keyUid
|
||||
|
||||
method onAddressDetailsFetched*[T](self: Module[T], derivedAddresses: seq[DerivedAddressDto], error: string) =
|
||||
if error.len > 0:
|
||||
error "ki_fetching address details error", err=error
|
||||
return
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "ki_cannot resolve current state"
|
||||
return
|
||||
# we always receive responses one by one
|
||||
if derivedAddresses.len == 1:
|
||||
var addressDetailsItem = newDerivedAddressItem(order = 0,
|
||||
address = derivedAddresses[0].address,
|
||||
publicKey = derivedAddresses[0].publicKey,
|
||||
path = derivedAddresses[0].path,
|
||||
alreadyCreated = derivedAddresses[0].alreadyCreated,
|
||||
hasActivity = derivedAddresses[0].hasActivity,
|
||||
loaded = true)
|
||||
if currStateObj.stateType() == StateType.ImportPrivateKey:
|
||||
if cmpIgnoreCase(self.view.getPrivateKeyAccAddress().getAddress(), addressDetailsItem.getAddress()) == 0:
|
||||
self.view.setPrivateKeyAccAddress(addressDetailsItem)
|
||||
return
|
||||
error "ki_unknown error, since the length of the response is not expected", length=derivedAddresses.len
|
||||
|
||||
method onUserAuthenticated*[T](self: Module[T], pin: string, password: string, keyUid: string) =
|
||||
if password.len == 0:
|
||||
info "ki_unsuccessful authentication"
|
||||
return
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "ki_cannot resolve current state"
|
||||
return
|
||||
if currStateObj.stateType() == StateType.ImportPrivateKey:
|
||||
let res = self.controller.makePrivateKeyKeypairFullyOperable(self.controller.getGeneratedAccount().keyUid,
|
||||
self.controller.getPrivateKey(),
|
||||
password,
|
||||
doPasswordHashing = not singletonInstance.userProfile.getIsKeycardUser())
|
||||
if res.len > 0:
|
||||
error "ki_unable to make a keypair operable"
|
||||
return
|
||||
if currStateObj.stateType() == StateType.ImportSeedPhrase:
|
||||
let res = self.controller.makeSeedPhraseKeypairFullyOperable(self.controller.getGeneratedAccount().keyUid,
|
||||
self.controller.getSeedPhrase(),
|
||||
password,
|
||||
doPasswordHashing = not singletonInstance.userProfile.getIsKeycardUser())
|
||||
if res.len > 0:
|
||||
error "ki_unable to make a keypair operable"
|
||||
return
|
||||
self.closeKeypairImportPopup()
|
|
@ -0,0 +1,102 @@
|
|||
import NimQml
|
||||
import io_interface
|
||||
import internal/[state, state_wrapper]
|
||||
import app/modules/shared_models/[keypair_item, derived_address_model]
|
||||
|
||||
QtObject:
|
||||
type
|
||||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
currentState: StateWrapper
|
||||
currentStateVariant: QVariant
|
||||
selectedKeypair: KeyPairItem
|
||||
selectedKeypairVariant: QVariant
|
||||
privateKeyAccAddress: DerivedAddressItem
|
||||
privateKeyAccAddressVariant: QVariant
|
||||
enteredPrivateKeyMatchTheKeypair: bool
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.currentStateVariant.delete
|
||||
self.currentState.delete
|
||||
self.selectedKeypair.delete
|
||||
self.selectedKeypairVariant.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.delegate = delegate
|
||||
result.currentState = newStateWrapper()
|
||||
result.currentStateVariant = newQVariant(result.currentState)
|
||||
result.selectedKeypair = newKeyPairItem()
|
||||
result.selectedKeypairVariant = newQVariant(result.selectedKeypair)
|
||||
result.privateKeyAccAddress = newDerivedAddressItem()
|
||||
result.privateKeyAccAddressVariant = newQVariant(result.privateKeyAccAddress)
|
||||
result.enteredPrivateKeyMatchTheKeypair = false
|
||||
|
||||
signalConnect(result.currentState, "backActionClicked()", result, "onBackActionClicked()", 2)
|
||||
signalConnect(result.currentState, "cancelActionClicked()", result, "onCancelActionClicked()", 2)
|
||||
signalConnect(result.currentState, "primaryActionClicked()", result, "onPrimaryActionClicked()", 2)
|
||||
|
||||
proc currentStateObj*(self: View): State =
|
||||
return self.currentState.getStateObj()
|
||||
|
||||
proc setCurrentState*(self: View, state: State) =
|
||||
self.currentState.setStateObj(state)
|
||||
proc getCurrentState(self: View): QVariant {.slot.} =
|
||||
return self.currentStateVariant
|
||||
QtProperty[QVariant] currentState:
|
||||
read = getCurrentState
|
||||
|
||||
proc onBackActionClicked*(self: View) {.slot.} =
|
||||
self.delegate.onBackActionClicked()
|
||||
|
||||
proc onCancelActionClicked*(self: View) {.slot.} =
|
||||
self.delegate.onCancelActionClicked()
|
||||
|
||||
proc onPrimaryActionClicked*(self: View) {.slot.} =
|
||||
self.delegate.onPrimaryActionClicked()
|
||||
|
||||
proc getSelectedKeypair*(self: View): KeyPairItem =
|
||||
return self.selectedKeypair
|
||||
proc getSelectedKeypairAsVariant*(self: View): QVariant {.slot.} =
|
||||
return self.selectedKeypairVariant
|
||||
QtProperty[QVariant] selectedKeypair:
|
||||
read = getSelectedKeypairAsVariant
|
||||
|
||||
proc setSelectedKeypair*(self: View, item: KeyPairItem) =
|
||||
self.selectedKeypair.setItem(item)
|
||||
|
||||
proc getPrivateKeyAccAddress*(self: View): DerivedAddressItem =
|
||||
return self.privateKeyAccAddress
|
||||
|
||||
proc privateKeyAccAddressChanged*(self: View) {.signal.}
|
||||
proc getPrivateKeyAccAddressVariant*(self: View): QVariant {.slot.} =
|
||||
return self.privateKeyAccAddressVariant
|
||||
QtProperty[QVariant] privateKeyAccAddress:
|
||||
read = getPrivateKeyAccAddressVariant
|
||||
notify = privateKeyAccAddressChanged
|
||||
|
||||
proc setPrivateKeyAccAddress*(self: View, item: DerivedAddressItem) =
|
||||
self.privateKeyAccAddress.setItem(item)
|
||||
self.privateKeyAccAddressChanged()
|
||||
|
||||
proc changePrivateKey*(self: View, privateKey: string) {.slot.} =
|
||||
self.delegate.changePrivateKey(privateKey)
|
||||
|
||||
proc changeSeedPhrase*(self: View, seedPhrase: string) {.slot.} =
|
||||
self.delegate.changeSeedPhrase(seedPhrase)
|
||||
|
||||
proc validSeedPhrase*(self: View, seedPhrase: string): bool {.slot.} =
|
||||
return self.delegate.validSeedPhrase(seedPhrase)
|
||||
|
||||
proc enteredPrivateKeyMatchTheKeypairChanged(self: View) {.signal.}
|
||||
proc getEnteredPrivateKeyMatchTheKeypair*(self: View): bool {.slot.} =
|
||||
return self.enteredPrivateKeyMatchTheKeypair
|
||||
QtProperty[bool] enteredPrivateKeyMatchTheKeypair:
|
||||
read = getEnteredPrivateKeyMatchTheKeypair
|
||||
notify = enteredPrivateKeyMatchTheKeypairChanged
|
||||
|
||||
proc setEnteredPrivateKeyMatchTheKeypair*(self: View, value: bool) =
|
||||
self.enteredPrivateKeyMatchTheKeypair = value
|
||||
self.enteredPrivateKeyMatchTheKeypairChanged()
|
|
@ -215,6 +215,15 @@ proc removeAccountFromLocalStoreAndNotify(self: Service, address: string, notify
|
|||
if notify:
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountArgs(account: acc))
|
||||
|
||||
proc updateKeypairOperabilityInLocalStoreAndNotify(self: Service, keyUid: string) =
|
||||
let kp = self.getKeypairByKeyUid(keyUid)
|
||||
if kp.isNil:
|
||||
error "there is no known keypair", keyUid=keyUid, procName="updateKeypairOperabilityInLocalStoreAndNotify"
|
||||
return
|
||||
for acc in kp.accounts:
|
||||
acc.operable = AccountFullyOperable
|
||||
self.events.emit(SIGNAL_KEYPAIR_OPERABILITY_CHANGED, KeypairArgs(keypair: kp))
|
||||
|
||||
proc updateAccountsPositions(self: Service) =
|
||||
let dbAccounts = getAccountsFromDb()
|
||||
for dbAcc in dbAccounts:
|
||||
|
@ -305,6 +314,24 @@ proc addNewPrivateKeyKeypair*(self: Service, privateKey, password: string, doPas
|
|||
error "error: ", procName="addNewPrivateKeyKeypair", errName=e.name, errDesription=e.msg
|
||||
return e.msg
|
||||
|
||||
proc makePrivateKeyKeypairFullyOperable*(self: Service, keyUid, privateKey, password: string, doPasswordHashing: bool): string =
|
||||
if password.len == 0:
|
||||
error "for making a private key keypair fully operable, password must be provided"
|
||||
return
|
||||
var finalPassword = password
|
||||
if doPasswordHashing:
|
||||
finalPassword = utils.hashPassword(password)
|
||||
try:
|
||||
var response = status_go_accounts.makePrivateKeyKeypairFullyOperable(privateKey, finalPassword)
|
||||
if not response.error.isNil:
|
||||
error "status-go error", procName="makePrivateKeyKeypairFullyOperable", errCode=response.error.code, errDesription=response.error.message
|
||||
return response.error.message
|
||||
self.updateKeypairOperabilityInLocalStoreAndNotify(keyUid)
|
||||
return ""
|
||||
except Exception as e:
|
||||
error "error: ", procName="makePrivateKeyKeypairFullyOperable", errName=e.name, errDesription=e.msg
|
||||
return e.msg
|
||||
|
||||
## Mandatory fields for all accounts: `address`, `keyUid`, `walletType`, `path`, `publicKey`, `name`, `emoji`, `colorId`
|
||||
proc addNewSeedPhraseKeypair*(self: Service, seedPhrase, password: string, doPasswordHashing: bool,
|
||||
keyUid, keypairName, rootWalletMasterKey: string, accounts: seq[WalletAccountDto]): string =
|
||||
|
@ -328,6 +355,24 @@ proc addNewSeedPhraseKeypair*(self: Service, seedPhrase, password: string, doPas
|
|||
error "error: ", procName="addNewSeedPhraseKeypair", errName=e.name, errDesription=e.msg
|
||||
return e.msg
|
||||
|
||||
proc makeSeedPhraseKeypairFullyOperable*(self: Service, keyUid, mnemonic, password: string, doPasswordHashing: bool): string =
|
||||
if password.len == 0:
|
||||
error "for making a private key keypair fully operable, password must be provided"
|
||||
return
|
||||
var finalPassword = password
|
||||
if doPasswordHashing:
|
||||
finalPassword = utils.hashPassword(password)
|
||||
try:
|
||||
var response = status_go_accounts.makeSeedPhraseKeypairFullyOperable(mnemonic, finalPassword)
|
||||
if not response.error.isNil:
|
||||
error "status-go error", procName="makeSeedPhraseKeypairFullyOperable", errCode=response.error.code, errDesription=response.error.message
|
||||
return response.error.message
|
||||
self.updateKeypairOperabilityInLocalStoreAndNotify(keyUid)
|
||||
return ""
|
||||
except Exception as e:
|
||||
error "error: ", procName="makeSeedPhraseKeypairFullyOperable", errName=e.name, errDesription=e.msg
|
||||
return e.msg
|
||||
|
||||
proc getRandomMnemonic*(self: Service): string =
|
||||
try:
|
||||
let response = status_go_accounts.getRandomMnemonic()
|
||||
|
@ -591,3 +636,6 @@ proc getCurrencyFormat*(self: Service, symbol: string): CurrencyFormatDto =
|
|||
|
||||
proc areTestNetworksEnabled*(self: Service): bool =
|
||||
return self.settingsService.areTestNetworksEnabled()
|
||||
|
||||
proc hasPairedDevices*(self: Service): bool =
|
||||
return hasPairedDevices()
|
|
@ -19,6 +19,7 @@ const SIGNAL_WALLET_ACCOUNT_PREFERRED_SHARING_CHAINS_UPDATED* = "walletAccount/p
|
|||
const SIGNAL_KEYPAIR_SYNCED* = "keypairSynced"
|
||||
const SIGNAL_KEYPAIR_NAME_CHANGED* = "keypairNameChanged"
|
||||
const SIGNAL_KEYPAIR_DELETED* = "keypairDeleted"
|
||||
const SIGNAL_KEYPAIR_OPERABILITY_CHANGED* = "keypairOperabilityChanged"
|
||||
|
||||
const SIGNAL_NEW_KEYCARD_SET* = "newKeycardSet"
|
||||
const SIGNAL_KEYCARD_REBUILD* = "keycardRebuild"
|
||||
|
|
|
@ -238,6 +238,11 @@ proc importMnemonic*(mnemonic, password: string):
|
|||
let payload = %* [mnemonic, password]
|
||||
return core.callPrivateRPC("accounts_importMnemonic", payload)
|
||||
|
||||
proc makeSeedPhraseKeypairFullyOperable*(mnemonic, password: string):
|
||||
RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* [mnemonic, password]
|
||||
return core.callPrivateRPC("accounts_makeSeedPhraseKeypairFullyOperable", payload)
|
||||
|
||||
proc createAccountFromMnemonicAndDeriveAccountsForPaths*(mnemonic: string, paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* {
|
||||
"mnemonicPhrase": mnemonic,
|
||||
|
@ -258,6 +263,11 @@ proc importPrivateKey*(privateKey, password: string):
|
|||
let payload = %* [privateKey, password]
|
||||
return core.callPrivateRPC("accounts_importPrivateKey", payload)
|
||||
|
||||
proc makePrivateKeyKeypairFullyOperable*(privateKey, password: string):
|
||||
RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* [privateKey, password]
|
||||
return core.callPrivateRPC("accounts_makePrivateKeyKeypairFullyOperable", payload)
|
||||
|
||||
proc createAccountFromPrivateKey*(privateKey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* {"privateKey": privateKey}
|
||||
try:
|
||||
|
|
|
@ -21,6 +21,8 @@ Rectangle {
|
|||
|
||||
signal goToAccountView(var account)
|
||||
signal toggleIncludeWatchOnlyAccount()
|
||||
signal runImportViaSeedPhraseFlow()
|
||||
signal runImportViaPrivateKeyFlow()
|
||||
signal runRenameKeypairFlow()
|
||||
signal runRemoveKeypairFlow()
|
||||
|
||||
|
@ -80,6 +82,8 @@ Rectangle {
|
|||
menuLoader.active = false
|
||||
}
|
||||
keyPair: root.keyPair
|
||||
onRunImportViaSeedPhraseFlow: root.runImportViaSeedPhraseFlow()
|
||||
onRunImportViaPrivateKeyFlow: root.runImportViaPrivateKeyFlow()
|
||||
onRunRenameKeypairFlow: root.runRenameKeypairFlow()
|
||||
onRunRemoveKeypairFlow: root.runRemoveKeypairFlow()
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ StatusMenu {
|
|||
|
||||
property var keyPair
|
||||
|
||||
signal runImportViaSeedPhraseFlow()
|
||||
signal runImportViaPrivateKeyFlow()
|
||||
signal runRenameKeypairFlow()
|
||||
signal runRemoveKeypairFlow()
|
||||
|
||||
|
@ -56,15 +58,16 @@ StatusMenu {
|
|||
StatusAction {
|
||||
text: enabled? root.keyPair.pairType === Constants.keypair.type.privateKeyImport? qsTr("Import via entering private key") : qsTr("Import via entering seed phrase") : ""
|
||||
enabled: !!root.keyPair &&
|
||||
root.keyPair.operability === Constants.keypair.operability.nonOperable &&
|
||||
(root.keyPair.pairType === Constants.keypair.type.seedImport ||
|
||||
root.keyPair.pairType === Constants.keypair.type.privateKeyImport)
|
||||
icon.name: enabled? root.keyPair.pairType === Constants.keypair.type.privateKeyImport? "objects" : "key_pair_seed_phrase" : ""
|
||||
icon.color: Theme.palette.primaryColor1
|
||||
onTriggered: {
|
||||
if (root.keyPair.pairType === Constants.keypair.type.privateKeyImport)
|
||||
console.warn("TODO: run import via private key flow")
|
||||
root.runImportViaPrivateKeyFlow()
|
||||
else
|
||||
console.warn("TODO: run import via seed phrase flow")
|
||||
root.runImportViaSeedPhraseFlow()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,8 +56,7 @@ QtObject {
|
|||
}
|
||||
|
||||
property WalletStore walletStore: WalletStore {
|
||||
accountsModule: profileSectionModuleInst.walletAccountsModule
|
||||
networksModule: profileSectionModuleInst.walletNetworksModule
|
||||
walletModule: profileSectionModuleInst.walletModule
|
||||
}
|
||||
|
||||
property KeycardStore keycardStore: KeycardStore {
|
||||
|
|
|
@ -5,8 +5,9 @@ import utils 1.0
|
|||
QtObject {
|
||||
id: root
|
||||
|
||||
property var accountsModule
|
||||
property var networksModule
|
||||
property var walletModule
|
||||
property var accountsModule: root.walletModule.accountsModule
|
||||
property var networksModule: root.walletModule.networksModule
|
||||
|
||||
property var accountSensitiveSettings: Global.appIsReady? localAccountSensitiveSettings : null
|
||||
|
||||
|
@ -58,9 +59,18 @@ QtObject {
|
|||
}
|
||||
|
||||
function runAddAccountPopup() {
|
||||
// TODO:
|
||||
// - `runAddAccountPopup` should be part of `root.walletModule`
|
||||
// - `AddAccountPopup {}` should be moved from `MainView` to `WalletView`
|
||||
// - `Edit account` popup opened from the wallet settings should be the same as one opened from the wallet section
|
||||
// - `walletSection` should not be used in the context of wallet settings
|
||||
walletSection.runAddAccountPopup(false)
|
||||
}
|
||||
|
||||
function runKeypairImportPopup(keyUid, importOption) {
|
||||
root.walletModule.runKeypairImportPopup(keyUid, importOption)
|
||||
}
|
||||
|
||||
function evaluateRpcEndPoint(url) {
|
||||
return networksModule.fetchChainIdForUrl(url)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import utils 1.0
|
|||
import shared 1.0
|
||||
import shared.panels 1.0
|
||||
import shared.popups 1.0
|
||||
import shared.popups.keypairimport 1.0
|
||||
import shared.status 1.0
|
||||
|
||||
import "../controls"
|
||||
|
@ -252,5 +253,31 @@ SettingsContentBase {
|
|||
}
|
||||
onLoaded: removeKeypairPopup.item.open()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.walletStore.walletModule
|
||||
|
||||
function onDisplayKeypairImportPopup() {
|
||||
keypairImport.active = true
|
||||
}
|
||||
function onDestroyKeypairImportPopup() {
|
||||
keypairImport.active = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loader {
|
||||
id: keypairImport
|
||||
active: false
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: KeypairImportPopup {
|
||||
store.keypairImportModule: root.walletStore.walletModule.keypairImportModule
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
keypairImport.item.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import shared.status 1.0
|
|||
import shared.panels 1.0
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
import shared.popups 1.0
|
||||
|
@ -41,6 +42,10 @@ Column {
|
|||
}
|
||||
}
|
||||
|
||||
component Spacer: Item {
|
||||
height: 8
|
||||
}
|
||||
|
||||
|
||||
Loader {
|
||||
id: addAccount
|
||||
|
@ -91,9 +96,42 @@ Column {
|
|||
|
||||
Separator {}
|
||||
|
||||
Item {
|
||||
Spacer {
|
||||
visible: root.walletStore.walletModule.hasPairedDevices
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.walletStore.walletModule.hasPairedDevices
|
||||
height: 102
|
||||
width: parent.width
|
||||
color: Theme.palette.transparent
|
||||
radius: 8
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor5
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
padding: 16
|
||||
spacing: 8
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Import keypairs from this device to your other synced devices")
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
text: qsTr("Show encrypted QR of keypairs on device")
|
||||
icon.name: "qr"
|
||||
onClicked: {
|
||||
console.warn("TODO: run generate qr code flow...")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer {
|
||||
width: parent.width
|
||||
height: 8
|
||||
}
|
||||
|
||||
Column {
|
||||
|
@ -112,6 +150,12 @@ Column {
|
|||
onToggleIncludeWatchOnlyAccount: walletStore.toggleIncludeWatchOnlyAccount()
|
||||
onRunRenameKeypairFlow: root.runRenameKeypairFlow(model)
|
||||
onRunRemoveKeypairFlow: root.runRemoveKeypairFlow(model)
|
||||
onRunImportViaSeedPhraseFlow: {
|
||||
root.walletStore.runKeypairImportPopup(model.keyPair.keyUid, Constants.keypairImportPopup.importOption.seedPhrase)
|
||||
}
|
||||
onRunImportViaPrivateKeyFlow: {
|
||||
root.walletStore.runKeypairImportPopup(model.keyPair.keyUid, Constants.keypairImportPopup.importOption.privateKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ ColumnLayout {
|
|||
function pasteWords () {
|
||||
const clipboardText = globalUtils.getFromClipboard()
|
||||
// Split words separated by commas and or blank spaces (spaces, enters, tabs)
|
||||
const words = clipboardText.split(/[, \s]+/)
|
||||
const words = clipboardText.trim().split(/[, \s]+/)
|
||||
|
||||
let index = d.tabs.indexOf(words.length)
|
||||
if (index === -1) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import utils 1.0
|
|||
|
||||
import "./stores"
|
||||
import "./states"
|
||||
import "../common"
|
||||
|
||||
StatusModal {
|
||||
id: root
|
||||
|
@ -255,7 +256,7 @@ StatusModal {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
root.store.submitAddAccount(null)
|
||||
root.store.submitPopup(null)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -10,6 +10,7 @@ import StatusQ.Components 0.1
|
|||
import utils 1.0
|
||||
|
||||
import "../stores"
|
||||
import "../../common"
|
||||
|
||||
GridLayout {
|
||||
id: root
|
||||
|
@ -77,7 +78,7 @@ GridLayout {
|
|||
}
|
||||
|
||||
onEditingFinished: {
|
||||
root.store.submitAddAccount(null)
|
||||
root.store.submitPopup(null)
|
||||
}
|
||||
|
||||
input.rightComponent: StatusIcon {
|
||||
|
|
|
@ -9,6 +9,7 @@ import StatusQ.Controls.Validators 0.1
|
|||
import utils 1.0
|
||||
|
||||
import "../stores"
|
||||
import "../../common"
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
@ -53,7 +54,7 @@ Column {
|
|||
}
|
||||
|
||||
onKeyPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import utils 1.0
|
|||
|
||||
import "../stores"
|
||||
import "../panels"
|
||||
import "../../common"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
@ -140,7 +141,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
|
||||
onValidChanged: {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import QtQuick 2.13
|
||||
import utils 1.0
|
||||
|
||||
QtObject {
|
||||
import "../../common"
|
||||
|
||||
BasePopupStore {
|
||||
id: root
|
||||
|
||||
isAddAccountPopup: true
|
||||
required property var addAccountModule
|
||||
required property var emojiPopup
|
||||
|
||||
|
@ -19,13 +22,11 @@ QtObject {
|
|||
property var derivedAddressModel: root.addAccountModule.derivedAddressModel
|
||||
property var selectedDerivedAddress: root.addAccountModule.selectedDerivedAddress
|
||||
property var watchOnlyAccAddress: root.addAccountModule.watchOnlyAccAddress
|
||||
property var privateKeyAccAddress: root.addAccountModule.privateKeyAccAddress
|
||||
privateKeyAccAddress: root.addAccountModule.privateKeyAccAddress
|
||||
property bool editMode: root.addAccountModule.editMode
|
||||
property bool disablePopup: root.addAccountModule.disablePopup
|
||||
|
||||
property bool accountNameIsValid: false
|
||||
property bool enteredSeedPhraseIsValid: false
|
||||
property bool enteredPrivateKeyIsValid: false
|
||||
property bool addingNewMasterKeyConfirmed: false
|
||||
property bool seedPhraseRevealed: false
|
||||
property bool seedPhraseWord1Valid: false
|
||||
|
@ -82,7 +83,7 @@ QtObject {
|
|||
return root.addAccountModule.getStoredSelectedColorId()
|
||||
}
|
||||
|
||||
function submitAddAccount(event) {
|
||||
submitPopup: function(event) {
|
||||
if (!root.primaryPopupButtonEnabled) {
|
||||
return
|
||||
}
|
||||
|
@ -116,11 +117,11 @@ QtObject {
|
|||
root.addAccountModule.changeWatchOnlyAccountAddress("")
|
||||
}
|
||||
|
||||
readonly property var changePrivateKeyPostponed: Backpressure.debounce(root, 400, function (privateKey) {
|
||||
changePrivateKeyPostponed: Backpressure.debounce(root, 400, function (privateKey) {
|
||||
root.addAccountModule.changePrivateKey(privateKey)
|
||||
})
|
||||
|
||||
function cleanPrivateKey() {
|
||||
cleanPrivateKey: function() {
|
||||
root.enteredPrivateKeyIsValid = false
|
||||
root.addAccountModule.newKeyPairName = ""
|
||||
root.addAccountModule.changePrivateKey("")
|
||||
|
@ -152,11 +153,11 @@ QtObject {
|
|||
root.addAccountModule.startScanningForActivity()
|
||||
}
|
||||
|
||||
function validSeedPhrase(seedPhrase) {
|
||||
validSeedPhrase: function(seedPhrase) {
|
||||
return root.addAccountModule.validSeedPhrase(seedPhrase)
|
||||
}
|
||||
|
||||
function changeSeedPhrase(seedPhrase) {
|
||||
changeSeedPhrase: function(seedPhrase) {
|
||||
root.addAccountModule.changeSeedPhrase(seedPhrase)
|
||||
}
|
||||
|
||||
|
@ -186,10 +187,6 @@ QtObject {
|
|||
}
|
||||
}
|
||||
|
||||
function getFromClipboard() {
|
||||
return globalUtils.getFromClipboard()
|
||||
}
|
||||
|
||||
readonly property bool primaryPopupButtonEnabled: {
|
||||
if (!root.addAccountModule || !root.currentState || root.disablePopup) {
|
||||
return false
|
||||
|
|
|
@ -12,6 +12,7 @@ Row {
|
|||
property var addressDetailsItem
|
||||
property bool defaultMessageCondition: true
|
||||
property string defaultMessage: ""
|
||||
property bool alreadyCreatedAccountIsAnError: true
|
||||
|
||||
StatusIcon {
|
||||
id: icon
|
||||
|
@ -36,7 +37,7 @@ Row {
|
|||
if (!root.addressDetailsItem || !root.addressDetailsItem.loaded) {
|
||||
return qsTr("Scanning for activity...")
|
||||
}
|
||||
if (root.addressDetailsItem.alreadyCreated) {
|
||||
if (root.alreadyCreatedAccountIsAnError && root.addressDetailsItem.alreadyCreated) {
|
||||
return qsTr("Already added")
|
||||
}
|
||||
if (root.addressDetailsItem.hasActivity) {
|
||||
|
@ -48,7 +49,7 @@ Row {
|
|||
if (root.defaultMessageCondition || !root.addressDetailsItem || !root.addressDetailsItem.loaded) {
|
||||
return Theme.palette.baseColor1
|
||||
}
|
||||
if (root.addressDetailsItem.alreadyCreated) {
|
||||
if (root.alreadyCreatedAccountIsAnError && root.addressDetailsItem.alreadyCreated) {
|
||||
return Theme.palette.dangerColor1
|
||||
}
|
||||
if (root.addressDetailsItem.hasActivity) {
|
|
@ -17,6 +17,7 @@ Column {
|
|||
property bool addressResolved: true
|
||||
property bool displayDetails: true
|
||||
property bool displayCopyButton: true
|
||||
property bool alreadyCreatedAccountIsAnError: true
|
||||
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
|
@ -44,5 +45,6 @@ Column {
|
|||
addressDetailsItem: root.addressDetailsItem
|
||||
defaultMessage: ""
|
||||
defaultMessageCondition: !root.addressResolved
|
||||
alreadyCreatedAccountIsAnError: root.alreadyCreatedAccountIsAnError
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import QtQuick 2.13
|
||||
import utils 1.0
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
// store properties
|
||||
required property bool isAddAccountPopup
|
||||
property bool enteredPrivateKeyIsValid: false
|
||||
property bool enteredPrivateKeyMatchTheKeypair: true
|
||||
property bool enteredSeedPhraseIsValid: false
|
||||
|
||||
// backend properties
|
||||
required property var privateKeyAccAddress
|
||||
|
||||
// functions
|
||||
property var changePrivateKeyPostponed: function(){}
|
||||
property var cleanPrivateKey: function(){}
|
||||
property var submitPopup: function(){}
|
||||
property var changeSeedPhrase: function(){}
|
||||
property var validSeedPhrase: function(){}
|
||||
|
||||
function getFromClipboard() {
|
||||
return globalUtils.getFromClipboard()
|
||||
}
|
||||
}
|
|
@ -11,13 +11,10 @@ import StatusQ.Popups 0.1
|
|||
|
||||
import utils 1.0
|
||||
|
||||
import "../stores"
|
||||
import "../panels"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property AddAccountStore store
|
||||
property BasePopupStore store
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
@ -38,8 +35,10 @@ Item {
|
|||
spacing: Style.current.halfPadding
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Private key")
|
||||
width: parent.width
|
||||
text: root.store.isAddAccountPopup? qsTr("Private key") : qsTr("Private key for %1 keypair").arg(root.store.selectedKeypair.name)
|
||||
font.pixelSize: Constants.addAccountPopup.labelFontSize1
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
|
@ -68,7 +67,7 @@ Item {
|
|||
}
|
||||
|
||||
onPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
|
@ -97,11 +96,17 @@ Item {
|
|||
|
||||
StatusBaseText {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
visible: privKeyInput.text !== "" && !root.store.enteredPrivateKeyIsValid
|
||||
visible: privKeyInput.text !== "" && !(root.store.enteredPrivateKeyIsValid && root.store.enteredPrivateKeyMatchTheKeypair)
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 12
|
||||
color: Theme.palette.dangerColor1
|
||||
text: qsTr("Private key invalid")
|
||||
text: {
|
||||
if (!root.store.enteredPrivateKeyIsValid)
|
||||
return qsTr("Private key invalid")
|
||||
if (!root.store.enteredPrivateKeyMatchTheKeypair)
|
||||
return qsTr("This is not the correct private key")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,17 +141,18 @@ Item {
|
|||
addressDetailsItem: root.store.privateKeyAccAddress
|
||||
addressResolved: d.addressResolved
|
||||
displayCopyButton: false
|
||||
alreadyCreatedAccountIsAnError: root.store.isAddAccountPopup
|
||||
}
|
||||
|
||||
StatusModalDivider {
|
||||
width: parent.width
|
||||
visible: d.addressResolved
|
||||
visible: root.store.isAddAccountPopup && d.addressResolved
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Style.current.halfPadding
|
||||
visible: d.addressResolved
|
||||
visible: root.store.isAddAccountPopup && d.addressResolved
|
||||
|
||||
StatusInput {
|
||||
objectName: "AddAccountPopup-PrivateKeyName"
|
||||
|
@ -154,9 +160,12 @@ Item {
|
|||
label: qsTr("Key name")
|
||||
charLimit: Constants.addAccountPopup.keyPairNameMaxLength
|
||||
placeholderText: qsTr("Enter a name")
|
||||
text: root.store.addAccountModule.newKeyPairName
|
||||
text: root.store.isAddAccountPopup? root.store.addAccountModule.newKeyPairName : ""
|
||||
|
||||
onTextChanged: {
|
||||
if (!root.store.isAddAccountPopup) {
|
||||
return
|
||||
}
|
||||
if (text.trim() == "") {
|
||||
root.store.addAccountModule.newKeyPairName = ""
|
||||
return
|
||||
|
@ -165,7 +174,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,13 +12,10 @@ import StatusQ.Popups 0.1
|
|||
import utils 1.0
|
||||
import shared.panels 1.0 as SharedPanels
|
||||
|
||||
import "../stores"
|
||||
import "../panels"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property AddAccountStore store
|
||||
property BasePopupStore store
|
||||
|
||||
Column {
|
||||
anchors.top: parent.top
|
||||
|
@ -29,8 +26,10 @@ Item {
|
|||
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Enter seed phrase")
|
||||
width: parent.width
|
||||
text: root.store.isAddAccountPopup? qsTr("Enter seed phrase") : qsTr("Enter seed phrase for %1 keypair").arg(root.store.selectedKeypair.name)
|
||||
font.pixelSize: Constants.addAccountPopup.labelFontSize1
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
SharedPanels.EnterSeedPhrase {
|
||||
|
@ -47,24 +46,28 @@ Item {
|
|||
}
|
||||
root.store.enteredSeedPhraseIsValid = valid
|
||||
if (!enterSeedPhrase.isSeedPhraseValid(seedPhrase)) {
|
||||
enterSeedPhrase.setWrongSeedPhraseMessage(qsTr("The entered seed phrase is already added"))
|
||||
let err = qsTr("The entered seed phrase is already added")
|
||||
if (!root.store.isAddAccountPopup) {
|
||||
err = qsTr("This is not the correct seed phrase for %1 key").arg(root.store.selectedKeypair.name)
|
||||
}
|
||||
enterSeedPhrase.setWrongSeedPhraseMessage(err)
|
||||
}
|
||||
}
|
||||
|
||||
onSubmitSeedPhrase: {
|
||||
root.store.submitAddAccount()
|
||||
root.store.submitPopup()
|
||||
}
|
||||
}
|
||||
|
||||
StatusModalDivider {
|
||||
width: parent.width
|
||||
visible: root.store.enteredSeedPhraseIsValid
|
||||
visible: root.store.isAddAccountPopup && root.store.enteredSeedPhraseIsValid
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Style.current.halfPadding
|
||||
visible: root.store.enteredSeedPhraseIsValid
|
||||
visible: root.store.isAddAccountPopup && root.store.enteredSeedPhraseIsValid
|
||||
|
||||
StatusInput {
|
||||
objectName: "AddAccountPopup-ImportedSeedPhraseKeyName"
|
||||
|
@ -72,9 +75,12 @@ Item {
|
|||
label: qsTr("Key name")
|
||||
charLimit: Constants.addAccountPopup.keyPairNameMaxLength
|
||||
placeholderText: qsTr("Enter a name")
|
||||
text: root.store.addAccountModule.newKeyPairName
|
||||
text: root.store.isAddAccountPopup? root.store.addAccountModule.newKeyPairName : ""
|
||||
|
||||
onTextChanged: {
|
||||
if (!root.store.isAddAccountPopup) {
|
||||
return
|
||||
}
|
||||
if (text.trim() == "") {
|
||||
root.store.addAccountModule.newKeyPairName = ""
|
||||
return
|
||||
|
@ -83,7 +89,7 @@ Item {
|
|||
}
|
||||
|
||||
onKeyPressed: {
|
||||
root.store.submitAddAccount(event)
|
||||
root.store.submitPopup(event)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import "./stores"
|
||||
import "../common"
|
||||
|
||||
StatusModal {
|
||||
id: root
|
||||
|
||||
property KeypairImportStore store: KeypairImportStore { }
|
||||
|
||||
width: Constants.keypairImportPopup.popupWidth
|
||||
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
headerSettings.title: {
|
||||
return qsTr("Import %1 keypair").arg(root.store.selectedKeypair.name)
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
root.store.currentState.doCancelAction()
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
id: scrollView
|
||||
|
||||
anchors.fill: parent
|
||||
padding: 0
|
||||
contentWidth: availableWidth
|
||||
|
||||
Item {
|
||||
id: content
|
||||
|
||||
implicitWidth: loader.implicitWidth
|
||||
implicitHeight: loader.implicitHeight
|
||||
width: scrollView.availableWidth
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
width: parent.width
|
||||
sourceComponent: {
|
||||
switch (root.store.currentState.stateType) {
|
||||
case Constants.keypairImportPopup.state.importPrivateKey:
|
||||
return keypairImportPrivateKeyComponent
|
||||
case Constants.keypairImportPopup.state.importSeedPhrase:
|
||||
return keypairImportSeedPhraseComponent
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
content.height = Qt.binding(function(){return item.height})
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: keypairImportPrivateKeyComponent
|
||||
EnterPrivateKey {
|
||||
height: Constants.keypairImportPopup.contentHeight
|
||||
store: root.store
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: keypairImportSeedPhraseComponent
|
||||
EnterSeedPhrase {
|
||||
height: Constants.keypairImportPopup.contentHeight
|
||||
store: root.store
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leftButtons: [
|
||||
StatusBackButton {
|
||||
id: backButton
|
||||
visible: root.store.currentState.displayBackButton
|
||||
height: Constants.keypairImportPopup.footerButtonsHeight
|
||||
width: height
|
||||
onClicked: {
|
||||
root.store.currentState.doBackAction()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
rightButtons: [
|
||||
StatusButton {
|
||||
id: primaryButton
|
||||
height: Constants.keypairImportPopup.footerButtonsHeight
|
||||
text: {
|
||||
switch (root.store.currentState.stateType) {
|
||||
|
||||
case Constants.keypairImportPopup.state.importPrivateKey:
|
||||
case Constants.keypairImportPopup.state.importSeedPhrase:
|
||||
return qsTr("Import %1 keypair").arg(root.store.selectedKeypair.name)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
visible: text !== ""
|
||||
enabled: root.store.primaryPopupButtonEnabled
|
||||
|
||||
icon.name: {
|
||||
if (root.store.userProfileUsingBiometricLogin) {
|
||||
return "touch-id"
|
||||
}
|
||||
|
||||
if (root.store.userProfileIsKeycardUser) {
|
||||
return "keycard"
|
||||
}
|
||||
|
||||
return "password"
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.store.submitPopup(null)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
KeypairImportPopup 1.0 KeypairImportPopup.qml
|
|
@ -0,0 +1,68 @@
|
|||
import QtQuick 2.13
|
||||
import utils 1.0
|
||||
|
||||
import "../../common"
|
||||
|
||||
BasePopupStore {
|
||||
id: root
|
||||
|
||||
isAddAccountPopup: false
|
||||
required property var keypairImportModule
|
||||
|
||||
property bool userProfileIsKeycardUser: userProfile.isKeycardUser
|
||||
property bool userProfileUsingBiometricLogin: userProfile.usingBiometricLogin
|
||||
|
||||
// Module Properties
|
||||
property var currentState: root.keypairImportModule.currentState
|
||||
property var selectedKeypair: root.keypairImportModule.selectedKeypair
|
||||
enteredPrivateKeyMatchTheKeypair: root.keypairImportModule.enteredPrivateKeyMatchTheKeypair
|
||||
privateKeyAccAddress: root.keypairImportModule.privateKeyAccAddress
|
||||
|
||||
submitPopup: function(event) {
|
||||
if (!root.primaryPopupButtonEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if(!event) {
|
||||
root.currentState.doPrimaryAction()
|
||||
}
|
||||
else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
event.accepted = true
|
||||
root.currentState.doPrimaryAction()
|
||||
}
|
||||
}
|
||||
|
||||
changePrivateKeyPostponed: Backpressure.debounce(root, 400, function (privateKey) {
|
||||
root.keypairImportModule.changePrivateKey(privateKey)
|
||||
})
|
||||
|
||||
cleanPrivateKey: function() {
|
||||
root.enteredPrivateKeyIsValid = false
|
||||
root.keypairImportModule.changePrivateKey("")
|
||||
}
|
||||
|
||||
function validSeedPhrase(seedPhrase) {
|
||||
return root.keypairImportModule.validSeedPhrase(seedPhrase)
|
||||
}
|
||||
|
||||
function changeSeedPhrase(seedPhrase) {
|
||||
root.keypairImportModule.changeSeedPhrase(seedPhrase)
|
||||
}
|
||||
|
||||
readonly property bool primaryPopupButtonEnabled: {
|
||||
if (root.currentState.stateType === Constants.keypairImportPopup.state.importPrivateKey) {
|
||||
return root.enteredPrivateKeyIsValid &&
|
||||
root.enteredPrivateKeyMatchTheKeypair &&
|
||||
!!root.privateKeyAccAddress &&
|
||||
root.privateKeyAccAddress.loaded &&
|
||||
root.privateKeyAccAddress.alreadyCreated &&
|
||||
root.privateKeyAccAddress.address !== ""
|
||||
}
|
||||
|
||||
if (root.currentState.stateType === Constants.keypairImportPopup.state.importSeedPhrase) {
|
||||
return root.enteredSeedPhraseIsValid
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -739,6 +739,23 @@ QtObject {
|
|||
}
|
||||
}
|
||||
|
||||
readonly property QtObject keypairImportPopup: QtObject {
|
||||
readonly property int popupWidth: 480
|
||||
readonly property int contentHeight: 626
|
||||
readonly property int footerButtonsHeight: 44
|
||||
|
||||
readonly property QtObject importOption: QtObject {
|
||||
readonly property int seedPhrase: 1
|
||||
readonly property int privateKey: 2
|
||||
}
|
||||
|
||||
readonly property QtObject state: QtObject {
|
||||
readonly property string noState: "NoState"
|
||||
readonly property string importSeedPhrase: "ImportSeedPhrase"
|
||||
readonly property string importPrivateKey: "ImportPrivateKey"
|
||||
}
|
||||
}
|
||||
|
||||
readonly property QtObject localPairingAction: QtObject {
|
||||
readonly property int actionUnknown: 0
|
||||
readonly property int actionConnect: 1
|
||||
|
|
Loading…
Reference in New Issue