feat(@desktop/keycard): keycard settings -> migrate keypair flow
- Added flow which covers `Setup a new Keycard with an existing account` from the keycard settings part (though two sub-flows there are missing, `Unlock Keycard` and `Authentication` cause we don't have them yet). - Updated factory reset flow (part of shared module) that it can read and display metadata from a keycard if they are set, with this update this flow is almost complete, we are missing `Unlock Keycard` flow for it as well.
This commit is contained in:
parent
ec7710490d
commit
afa7928bae
|
@ -7,7 +7,7 @@ const LS_KEY_STORE_TO_KEYCHAIN* = "storeToKeychain"
|
||||||
const DEFAULT_STORE_TO_KEYCHAIN = "notNow"
|
const DEFAULT_STORE_TO_KEYCHAIN = "notNow"
|
||||||
# Local Account Settings values:
|
# Local Account Settings values:
|
||||||
const LS_VALUE_STORE* = "store"
|
const LS_VALUE_STORE* = "store"
|
||||||
const LS_VALUE_NOTNOW* = "notNow"
|
const LS_VALUE_NOT_NOW* = "notNow"
|
||||||
const LS_VALUE_NEVER* = "never"
|
const LS_VALUE_NEVER* = "never"
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
|
|
|
@ -4,6 +4,8 @@ import io_interface
|
||||||
|
|
||||||
import ../../../../core/eventemitter
|
import ../../../../core/eventemitter
|
||||||
|
|
||||||
|
import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "profile-section-keycard-module-controller"
|
topics = "profile-section-keycard-module-controller"
|
||||||
|
|
||||||
|
@ -23,4 +25,9 @@ proc delete*(self: Controller) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc init*(self: Controller) =
|
proc init*(self: Controller) =
|
||||||
discard
|
self.events.on(SignalSharedKeycarModuleFlowTerminated) do(e: Args):
|
||||||
|
let args = SharedKeycarModuleFlowTerminatedArgs(e)
|
||||||
|
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow)
|
||||||
|
|
||||||
|
self.events.on(SignalSharedKeycarModuleDisplayPopup) do(e: Args):
|
||||||
|
self.delegate.onDisplayKeycardSharedModuleFlow()
|
|
@ -16,6 +16,19 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
|
||||||
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getKeycardSharedModule*(self: AccessInterface): QVariant {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method onDisplayKeycardSharedModuleFlow*(self: AccessInterface) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method runSetupKeycardPopup*(self: AccessInterface) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
|
||||||
# View Delegate Interface
|
# View Delegate Interface
|
||||||
# Delegate for the view must be declared here due to use of QtObject and multi
|
# Delegate for the view must be declared here due to use of QtObject and multi
|
||||||
# inheritance, which is not well supported in Nim.
|
# inheritance, which is not well supported in Nim.
|
||||||
|
|
|
@ -6,8 +6,12 @@ import ../io_interface as delegate_interface
|
||||||
import ../../../../core/eventemitter
|
import ../../../../core/eventemitter
|
||||||
|
|
||||||
import ../../../../../app_service/service/keycard/service as keycard_service
|
import ../../../../../app_service/service/keycard/service as keycard_service
|
||||||
|
import ../../../../../app_service/service/privacy/service as privacy_service
|
||||||
|
import ../../../../../app_service/service/accounts/service as accounts_service
|
||||||
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||||
|
|
||||||
|
import ../../../shared_modules/keycard_popup/module as keycard_shared_module
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
|
@ -22,16 +26,23 @@ type
|
||||||
moduleLoaded: bool
|
moduleLoaded: bool
|
||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
keycardService: keycard_service.Service
|
keycardService: keycard_service.Service
|
||||||
|
privacyService: privacy_service.Service
|
||||||
|
accountsService: accounts_service.Service
|
||||||
walletAccountService: wallet_account_service.Service
|
walletAccountService: wallet_account_service.Service
|
||||||
|
keycardSharedModule: keycard_shared_module.AccessInterface
|
||||||
|
|
||||||
proc newModule*(delegate: delegate_interface.AccessInterface,
|
proc newModule*(delegate: delegate_interface.AccessInterface,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
keycardService: keycard_service.Service,
|
keycardService: keycard_service.Service,
|
||||||
|
privacyService: privacy_service.Service,
|
||||||
|
accountsService: accounts_service.Service,
|
||||||
walletAccountService: wallet_account_service.Service): Module =
|
walletAccountService: wallet_account_service.Service): Module =
|
||||||
result = Module()
|
result = Module()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.events = events
|
result.events = events
|
||||||
result.keycardService = keycardService
|
result.keycardService = keycardService
|
||||||
|
result.privacyService = privacyService
|
||||||
|
result.accountsService = accountsService
|
||||||
result.walletAccountService = walletAccountService
|
result.walletAccountService = walletAccountService
|
||||||
result.view = view.newView(result)
|
result.view = view.newView(result)
|
||||||
result.viewVariant = newQVariant(result.view)
|
result.viewVariant = newQVariant(result.view)
|
||||||
|
@ -42,6 +53,8 @@ method delete*(self: Module) =
|
||||||
self.view.delete
|
self.view.delete
|
||||||
self.viewVariant.delete
|
self.viewVariant.delete
|
||||||
self.controller.delete
|
self.controller.delete
|
||||||
|
if not self.keycardSharedModule.isNil:
|
||||||
|
self.keycardSharedModule.delete
|
||||||
|
|
||||||
method load*(self: Module) =
|
method load*(self: Module) =
|
||||||
self.controller.init()
|
self.controller.init()
|
||||||
|
@ -55,4 +68,29 @@ method viewDidLoad*(self: Module) =
|
||||||
self.delegate.profileModuleDidLoad()
|
self.delegate.profileModuleDidLoad()
|
||||||
|
|
||||||
method getModuleAsVariant*(self: Module): QVariant =
|
method getModuleAsVariant*(self: Module): QVariant =
|
||||||
return self.viewVariant
|
return self.viewVariant
|
||||||
|
|
||||||
|
method getKeycardSharedModule*(self: Module): QVariant =
|
||||||
|
return self.keycardSharedModule.getModuleAsVariant()
|
||||||
|
|
||||||
|
proc createSharedKeycardModule(self: Module) =
|
||||||
|
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, self.events, self.keycardService,
|
||||||
|
self.privacyService, self.accountsService, self.walletAccountService)
|
||||||
|
|
||||||
|
proc isSharedKeycardModuleFlowRunning(self: Module): bool =
|
||||||
|
return not self.keycardSharedModule.isNil
|
||||||
|
|
||||||
|
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) =
|
||||||
|
if self.isSharedKeycardModuleFlowRunning():
|
||||||
|
self.view.emitDestroyKeycardSharedModuleFlow()
|
||||||
|
self.keycardSharedModule.delete
|
||||||
|
self.keycardSharedModule = nil
|
||||||
|
|
||||||
|
method runSetupKeycardPopup*(self: Module) =
|
||||||
|
self.createSharedKeycardModule()
|
||||||
|
if self.keycardSharedModule.isNil:
|
||||||
|
return
|
||||||
|
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.SetupNewKeycard)
|
||||||
|
|
||||||
|
method onDisplayKeycardSharedModuleFlow*(self: Module) =
|
||||||
|
self.view.emitDisplayKeycardSharedModuleFlow()
|
|
@ -17,4 +17,19 @@ QtObject:
|
||||||
|
|
||||||
proc load*(self: View) =
|
proc load*(self: View) =
|
||||||
self.delegate.viewDidLoad()
|
self.delegate.viewDidLoad()
|
||||||
|
|
||||||
|
proc getKeycardSharedModule(self: View): QVariant {.slot.} =
|
||||||
|
return self.delegate.getKeycardSharedModule()
|
||||||
|
QtProperty[QVariant] keycardSharedModule:
|
||||||
|
read = getKeycardSharedModule
|
||||||
|
|
||||||
|
proc displayKeycardSharedModuleFlow*(self: View) {.signal.}
|
||||||
|
proc emitDisplayKeycardSharedModuleFlow*(self: View) =
|
||||||
|
self.displayKeycardSharedModuleFlow()
|
||||||
|
|
||||||
|
proc destroyKeycardSharedModuleFlow*(self: View) {.signal.}
|
||||||
|
proc emitDestroyKeycardSharedModuleFlow*(self: View) =
|
||||||
|
self.destroyKeycardSharedModuleFlow()
|
||||||
|
|
||||||
|
proc runSetupKeycardPopup*(self: View) {.slot.} =
|
||||||
|
self.delegate.runSetupKeycardPopup()
|
|
@ -99,7 +99,8 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
|
||||||
result, events, settingsService, ensService, walletAccountService, networkService
|
result, events, settingsService, ensService, walletAccountService, networkService
|
||||||
)
|
)
|
||||||
result.communitiesModule = communities_module.newModule(result, communityService)
|
result.communitiesModule = communities_module.newModule(result, communityService)
|
||||||
result.keycardModule = keycard_module.newModule(result, events, keycardService, walletAccountService)
|
result.keycardModule = keycard_module.newModule(result, events, keycardService, privacyService, accountsService,
|
||||||
|
walletAccountService)
|
||||||
|
|
||||||
singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant)
|
singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ import ../../../global/global_singleton
|
||||||
import ../../../core/signals/types
|
import ../../../core/signals/types
|
||||||
import ../../../core/eventemitter
|
import ../../../core/eventemitter
|
||||||
import ../../../../app_service/service/keycard/service as keycard_service
|
import ../../../../app_service/service/keycard/service as keycard_service
|
||||||
|
import ../../../../app_service/service/privacy/service as privacy_service
|
||||||
|
import ../../../../app_service/service/accounts/service as accounts_service
|
||||||
|
import ../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "keycard-popup-controller"
|
topics = "keycard-popup-controller"
|
||||||
|
@ -15,21 +18,46 @@ type
|
||||||
delegate: io_interface.AccessInterface
|
delegate: io_interface.AccessInterface
|
||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
keycardService: keycard_service.Service
|
keycardService: keycard_service.Service
|
||||||
|
privacyService: privacy_service.Service
|
||||||
|
accountsService: accounts_service.Service
|
||||||
|
walletAccountService: wallet_account_service.Service
|
||||||
connectionIds: seq[UUID]
|
connectionIds: seq[UUID]
|
||||||
tmpKeycardContainsMetadata: bool
|
tmpKeycardContainsMetadata: bool
|
||||||
|
tmpPin: string
|
||||||
|
tmpPinMatch: bool
|
||||||
|
tmpPassword: string
|
||||||
|
tmpKeyUid: string
|
||||||
|
tmpSelectedKeyPairIsProfile: bool
|
||||||
|
tmpSelectedKeyPairName: string
|
||||||
|
tmpSelectedKeyPairWalletPaths: seq[string]
|
||||||
|
tmpSeedPhrase: string
|
||||||
|
tmpSeedPhraseLength: int
|
||||||
|
|
||||||
proc newController*(delegate: io_interface.AccessInterface,
|
proc newController*(delegate: io_interface.AccessInterface,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
keycardService: keycard_service.Service):
|
keycardService: keycard_service.Service,
|
||||||
|
privacyService: privacy_service.Service,
|
||||||
|
accountsService: accounts_service.Service,
|
||||||
|
walletAccountService: wallet_account_service.Service):
|
||||||
Controller =
|
Controller =
|
||||||
result = Controller()
|
result = Controller()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.events = events
|
result.events = events
|
||||||
result.keycardService = keycardService
|
result.keycardService = keycardService
|
||||||
|
result.privacyService = privacyService
|
||||||
|
result.accountsService = accountsService
|
||||||
|
result.walletAccountService = walletAccountService
|
||||||
result.tmpKeycardContainsMetadata = false
|
result.tmpKeycardContainsMetadata = false
|
||||||
|
result.tmpPinMatch = false
|
||||||
|
result.tmpSeedPhraseLength = 0
|
||||||
|
result.tmpSelectedKeyPairIsProfile = false
|
||||||
|
|
||||||
|
proc disconnect*(self: Controller) =
|
||||||
|
for id in self.connectionIds:
|
||||||
|
self.events.disconnect(id)
|
||||||
|
|
||||||
proc delete*(self: Controller) =
|
proc delete*(self: Controller) =
|
||||||
discard
|
self.disconnect()
|
||||||
|
|
||||||
proc init*(self: Controller) =
|
proc init*(self: Controller) =
|
||||||
let handlerId = self.events.onWithUUID(SignalKeycardResponse) do(e: Args):
|
let handlerId = self.events.onWithUUID(SignalKeycardResponse) do(e: Args):
|
||||||
|
@ -37,9 +65,8 @@ proc init*(self: Controller) =
|
||||||
self.delegate.onKeycardResponse(args.flowType, args.flowEvent)
|
self.delegate.onKeycardResponse(args.flowType, args.flowEvent)
|
||||||
self.connectionIds.add(handlerId)
|
self.connectionIds.add(handlerId)
|
||||||
|
|
||||||
proc disconnect*(self: Controller) =
|
proc getKeycardData*(self: Controller): string =
|
||||||
for id in self.connectionIds:
|
return self.delegate.getKeycardData()
|
||||||
self.events.disconnect(id)
|
|
||||||
|
|
||||||
proc setKeycardData*(self: Controller, value: string) =
|
proc setKeycardData*(self: Controller, value: string) =
|
||||||
self.delegate.setKeycardData(value)
|
self.delegate.setKeycardData(value)
|
||||||
|
@ -50,6 +77,83 @@ proc containsMetadata*(self: Controller): bool =
|
||||||
proc setContainsMetadata*(self: Controller, value: bool) =
|
proc setContainsMetadata*(self: Controller, value: bool) =
|
||||||
self.tmpKeycardContainsMetadata = value
|
self.tmpKeycardContainsMetadata = value
|
||||||
|
|
||||||
|
proc setPin*(self: Controller, value: string) =
|
||||||
|
self.tmpPin = value
|
||||||
|
|
||||||
|
proc getPin*(self: Controller): string =
|
||||||
|
return self.tmpPin
|
||||||
|
|
||||||
|
proc setPinMatch*(self: Controller, value: bool) =
|
||||||
|
self.tmpPinMatch = value
|
||||||
|
|
||||||
|
proc getPinMatch*(self: Controller): bool =
|
||||||
|
return self.tmpPinMatch
|
||||||
|
|
||||||
|
proc setPassword*(self: Controller, value: string) =
|
||||||
|
self.tmpPassword = value
|
||||||
|
|
||||||
|
proc getPassword*(self: Controller): string =
|
||||||
|
return self.tmpPassword
|
||||||
|
|
||||||
|
proc setKeyUid*(self: Controller, value: string) =
|
||||||
|
self.tmpKeyUid = value
|
||||||
|
|
||||||
|
proc setSelectedKeyPairIsProfile*(self: Controller, value: bool) =
|
||||||
|
self.tmpSelectedKeyPairIsProfile = value
|
||||||
|
|
||||||
|
proc getSelectedKeyPairIsProfile*(self: Controller): bool =
|
||||||
|
return self.tmpSelectedKeyPairIsProfile
|
||||||
|
|
||||||
|
proc setSelectedKeyPairName*(self: Controller, value: string) =
|
||||||
|
self.tmpSelectedKeyPairName = value
|
||||||
|
|
||||||
|
proc getSelectedKeyPairName*(self: Controller): string =
|
||||||
|
return self.tmpSelectedKeyPairName
|
||||||
|
|
||||||
|
proc setSelectedKeyPairWalletPaths*(self: Controller, paths: seq[string]) =
|
||||||
|
self.tmpSelectedKeyPairWalletPaths = paths
|
||||||
|
|
||||||
|
proc getSelectedKeyPairWalletPaths*(self: Controller): seq[string] =
|
||||||
|
return self.tmpSelectedKeyPairWalletPaths
|
||||||
|
|
||||||
|
proc setSeedPhrase*(self: Controller, value: string) =
|
||||||
|
let words = value.split(" ")
|
||||||
|
self.tmpSeedPhrase = value
|
||||||
|
self.tmpSeedPhraseLength = words.len
|
||||||
|
|
||||||
|
proc getSeedPhrase*(self: Controller): string =
|
||||||
|
return self.tmpSeedPhrase
|
||||||
|
|
||||||
|
proc getSeedPhraseLength*(self: Controller): int =
|
||||||
|
return self.tmpSeedPhraseLength
|
||||||
|
|
||||||
|
proc validSeedPhrase*(self: Controller, seedPhrase: string): bool =
|
||||||
|
let err = self.accountsService.validateMnemonic(seedPhrase)
|
||||||
|
return err.len == 0
|
||||||
|
|
||||||
|
proc seedPhraseRefersToLoggedInUser*(self: Controller, seedPhrase: string): bool =
|
||||||
|
let acc = self.accountsService.createAccountFromMnemonic(seedPhrase)
|
||||||
|
return acc.keyUid == singletonInstance.userProfile.getAddress()
|
||||||
|
|
||||||
|
proc verifyPassword*(self: Controller, password: string): bool =
|
||||||
|
return self.accountsService.verifyPassword(password)
|
||||||
|
|
||||||
|
proc convertToKeycardAccount*(self: Controller, password: string): bool =
|
||||||
|
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
|
||||||
|
return self.accountsService.convertToKeycardAccount(self.tmpKeyUid, password)
|
||||||
|
|
||||||
|
proc getLoggedInAccount*(self: Controller): AccountDto =
|
||||||
|
return self.accountsService.getLoggedInAccount()
|
||||||
|
|
||||||
|
proc getCurrentKeycardServiceFlow*(self: Controller): keycard_service.KCSFlowType =
|
||||||
|
return self.keycardService.getCurrentFlow()
|
||||||
|
|
||||||
|
proc getLastReceivedKeycardData*(self: Controller): tuple[flowType: string, flowEvent: KeycardEvent] =
|
||||||
|
return self.keycardService.getLastReceivedKeycardData()
|
||||||
|
|
||||||
|
proc setMetadataFromKeycard*(self: Controller, cardMetadata: CardMetadata) =
|
||||||
|
self.delegate.setKeyPairStoredOnKeycard(cardMetadata)
|
||||||
|
|
||||||
proc cancelCurrentFlow(self: Controller) =
|
proc cancelCurrentFlow(self: Controller) =
|
||||||
self.keycardService.cancelCurrentFlow()
|
self.keycardService.cancelCurrentFlow()
|
||||||
# in most cases we're running another flow after canceling the current one,
|
# in most cases we're running another flow after canceling the current one,
|
||||||
|
@ -64,9 +168,76 @@ proc runGetMetadataFlow*(self: Controller) =
|
||||||
self.cancelCurrentFlow()
|
self.cancelCurrentFlow()
|
||||||
self.keycardService.startGetMetadataFlow()
|
self.keycardService.startGetMetadataFlow()
|
||||||
|
|
||||||
|
proc runStoreMetadataFlow*(self: Controller, cardName: string, pin: string, walletPaths: seq[string]) =
|
||||||
|
self.cancelCurrentFlow()
|
||||||
|
self.keycardService.startStoreMetadataFlow(cardName, pin, walletPaths)
|
||||||
|
|
||||||
|
proc runLoadAccountFlow*(self: Controller, factoryReset = false) =
|
||||||
|
self.cancelCurrentFlow()
|
||||||
|
self.keycardService.startLoadAccountFlow(factoryReset)
|
||||||
|
|
||||||
proc resumeCurrentFlowLater*(self: Controller) =
|
proc resumeCurrentFlowLater*(self: Controller) =
|
||||||
self.keycardService.resumeCurrentFlowLater()
|
self.keycardService.resumeCurrentFlowLater()
|
||||||
|
|
||||||
|
proc readyToDisplayPopup*(self: Controller) =
|
||||||
|
self.events.emit(SignalSharedKeycarModuleDisplayPopup, Args())
|
||||||
|
|
||||||
proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool) =
|
proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool) =
|
||||||
let data = SharedKeycarModuleFlowTerminatedArgs(lastStepInTheCurrentFlow: lastStepInTheCurrentFlow)
|
let data = SharedKeycarModuleFlowTerminatedArgs(lastStepInTheCurrentFlow: lastStepInTheCurrentFlow)
|
||||||
self.events.emit(SignalSharedKeycarModuleFlowTerminated, data)
|
self.events.emit(SignalSharedKeycarModuleFlowTerminated, data)
|
||||||
|
|
||||||
|
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
|
||||||
|
if self.walletAccountService.isNil:
|
||||||
|
debug "walletAccountService doesn't meant to be used from the context it's used, check the context shared popup module is used"
|
||||||
|
return
|
||||||
|
return self.walletAccountService.fetchAccounts()
|
||||||
|
|
||||||
|
proc getBalanceForAddress*(self: Controller, address: string): float64 =
|
||||||
|
if self.walletAccountService.isNil:
|
||||||
|
debug "walletAccountService doesn't meant to be used from the context it's used, check the context shared popup module is used"
|
||||||
|
return
|
||||||
|
return self.walletAccountService.fetchBalanceForAddress(address)
|
||||||
|
|
||||||
|
proc enterKeycardPin*(self: Controller, pin: string) =
|
||||||
|
self.keycardService.enterPin(pin)
|
||||||
|
|
||||||
|
proc storePinToKeycard*(self: Controller, pin: string, puk: string) =
|
||||||
|
self.keycardService.storePin(pin, puk)
|
||||||
|
|
||||||
|
proc storeSeedPhraseToKeycard*(self: Controller, seedPhraseLength: int, seedPhrase: string) =
|
||||||
|
self.keycardService.storeSeedPhrase(seedPhraseLength, seedPhrase)
|
||||||
|
|
||||||
|
proc generateRandomPUK*(self: Controller): string =
|
||||||
|
return self.keycardService.generateRandomPUK()
|
||||||
|
|
||||||
|
proc isMnemonicBackedUp*(self: Controller): bool =
|
||||||
|
if self.privacyService.isNil:
|
||||||
|
debug "privacyService doesn't meant to be used from the context it's used, check the context shared popup module is used"
|
||||||
|
return
|
||||||
|
return self.privacyService.isMnemonicBackedUp()
|
||||||
|
|
||||||
|
proc getMnemonic*(self: Controller): string =
|
||||||
|
if self.privacyService.isNil:
|
||||||
|
debug "privacyService doesn't meant to be used from the context it's used, check the context shared popup module is used"
|
||||||
|
return
|
||||||
|
return self.privacyService.getMnemonic()
|
||||||
|
|
||||||
|
proc removeMnemonic*(self: Controller) =
|
||||||
|
if self.privacyService.isNil:
|
||||||
|
debug "privacyService doesn't meant to be used from the context it's used, check the context shared popup module is used"
|
||||||
|
return
|
||||||
|
self.privacyService.removeMnemonic()
|
||||||
|
|
||||||
|
proc getMnemonicWordAtIndex*(self: Controller, index: int): string =
|
||||||
|
if self.privacyService.isNil:
|
||||||
|
debug "privacyService doesn't meant to be used from the context it's used, check the context shared popup module is used"
|
||||||
|
return
|
||||||
|
return self.privacyService.getMnemonicWordAtIndex(index)
|
||||||
|
|
||||||
|
proc loggedInUserUsesBiometricLogin*(self: Controller): bool =
|
||||||
|
if(not defined(macosx)):
|
||||||
|
return false
|
||||||
|
let value = singletonInstance.localAccountSettings.getStoreToKeychainValue()
|
||||||
|
if (value != LS_VALUE_STORE):
|
||||||
|
return false
|
||||||
|
return true
|
|
@ -0,0 +1,23 @@
|
||||||
|
type
|
||||||
|
CreatePinState* = ref object of State
|
||||||
|
|
||||||
|
proc newCreatePinState*(flowType: FlowType, backState: State): CreatePinState =
|
||||||
|
result = CreatePinState()
|
||||||
|
result.setup(flowType, StateType.CreatePin, backState)
|
||||||
|
|
||||||
|
proc delete*(self: CreatePinState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executeBackCommand*(self: CreatePinState, controller: Controller) =
|
||||||
|
controller.setPin("")
|
||||||
|
controller.setPinMatch(false)
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: CreatePinState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method getNextTertiaryState*(self: CreatePinState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if controller.getPin().len == PINLengthForStatusApp:
|
||||||
|
return createState(StateType.RepeatPin, self.flowType, self)
|
||||||
|
return nil
|
|
@ -7,3 +7,62 @@ proc newEnterPinState*(flowType: FlowType, backState: State): EnterPinState =
|
||||||
|
|
||||||
proc delete*(self: EnterPinState) =
|
proc delete*(self: EnterPinState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: EnterPinState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: EnterPinState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method executeTertiaryCommand*(self: EnterPinState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard or
|
||||||
|
self.flowType == FlowType.FactoryReset:
|
||||||
|
if controller.getPin().len == PINLengthForStatusApp:
|
||||||
|
controller.enterKeycardPin(controller.getPin())
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.FactoryReset:
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == RequestParamPIN:
|
||||||
|
controller.setKeycardData($keycardEvent.pinRetries)
|
||||||
|
if keycardEvent.pinRetries > 0:
|
||||||
|
return createState(StateType.WrongPin, self.flowType, nil)
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||||
|
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
|
||||||
|
return createState(StateType.PinVerified, self.flowType, nil)
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == RequestParamPIN:
|
||||||
|
controller.setKeycardData($keycardEvent.pinRetries)
|
||||||
|
if keycardEvent.pinRetries > 0:
|
||||||
|
return createState(StateType.WrongPin, self.flowType, nil)
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||||
|
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
|
||||||
|
return createState(StateType.PinVerified, self.flowType, nil)
|
|
@ -0,0 +1,42 @@
|
||||||
|
type
|
||||||
|
EnterSeedPhraseState* = ref object of State
|
||||||
|
verifiedSeedPhrase: bool
|
||||||
|
|
||||||
|
proc newEnterSeedPhraseState*(flowType: FlowType, backState: State): EnterSeedPhraseState =
|
||||||
|
result = EnterSeedPhraseState()
|
||||||
|
result.setup(flowType, StateType.EnterSeedPhrase, backState)
|
||||||
|
result.verifiedSeedPhrase = false
|
||||||
|
|
||||||
|
proc delete*(self: EnterSeedPhraseState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: EnterSeedPhraseState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
self.verifiedSeedPhrase = controller.validSeedPhrase(controller.getSeedPhrase()) and
|
||||||
|
(not controller.getSelectedKeyPairIsProfile() or
|
||||||
|
controller.getSelectedKeyPairIsProfile() and
|
||||||
|
controller.seedPhraseRefersToLoggedInUser(controller.getSeedPhrase()))
|
||||||
|
if self.verifiedSeedPhrase:
|
||||||
|
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase())
|
||||||
|
else:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: EnterSeedPhraseState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: EnterSeedPhraseState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if not self.verifiedSeedPhrase:
|
||||||
|
return createState(StateType.WrongSeedPhrase, self.flowType, nil)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: EnterSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.keyUid.len > 0:
|
||||||
|
controller.setKeyUid(keycardEvent.keyUid)
|
||||||
|
return createState(StateType.MigratingKeyPair, self.flowType, nil)
|
|
@ -0,0 +1,25 @@
|
||||||
|
type
|
||||||
|
FactoryResetConfirmationDisplayMetadataState* = ref object of State
|
||||||
|
|
||||||
|
proc newFactoryResetConfirmationDisplayMetadataState*(flowType: FlowType, backState: State): FactoryResetConfirmationDisplayMetadataState =
|
||||||
|
result = FactoryResetConfirmationDisplayMetadataState()
|
||||||
|
result.setup(flowType, StateType.FactoryResetConfirmationDisplayMetadata, backState)
|
||||||
|
|
||||||
|
proc delete*(self: FactoryResetConfirmationDisplayMetadataState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: FactoryResetConfirmationDisplayMetadataState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset:
|
||||||
|
controller.runGetAppInfoFlow(factoryReset = true)
|
||||||
|
elif self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true))
|
||||||
|
controller.runGetAppInfoFlow(factoryReset = true)
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: FactoryResetConfirmationDisplayMetadataState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: FactoryResetConfirmationDisplayMetadataState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -11,10 +11,15 @@ proc delete*(self: FactoryResetConfirmationState) =
|
||||||
method executePrimaryCommand*(self: FactoryResetConfirmationState, controller: Controller) =
|
method executePrimaryCommand*(self: FactoryResetConfirmationState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset:
|
||||||
controller.runGetAppInfoFlow(factoryReset = true)
|
controller.runGetAppInfoFlow(factoryReset = true)
|
||||||
|
elif self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true))
|
||||||
|
controller.runGetAppInfoFlow(factoryReset = true)
|
||||||
|
|
||||||
method executeSecondaryCommand*(self: FactoryResetConfirmationState, controller: Controller) =
|
method executeSecondaryCommand*(self: FactoryResetConfirmationState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
method getNextPrimaryState*(self: FactoryResetConfirmationState, controller: Controller): State =
|
method resolveKeycardNextState*(self: FactoryResetConfirmationState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
return createState(StateType.PluginReader, self.flowType, nil)
|
controller: Controller): State =
|
||||||
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -11,3 +11,13 @@ proc delete*(self: FactoryResetSuccessState) =
|
||||||
method executePrimaryCommand*(self: FactoryResetSuccessState, controller: Controller) =
|
method executePrimaryCommand*(self: FactoryResetSuccessState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||||
|
elif self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.runLoadAccountFlow()
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: FactoryResetSuccessState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: FactoryResetSuccessState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -9,17 +9,23 @@ proc delete*(self: InsertKeycardState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
method executePrimaryCommand*(self: InsertKeycardState, controller: Controller) =
|
method executePrimaryCommand*(self: InsertKeycardState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
controller: Controller): State =
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
if keycardFlowType == ResponseTypeValueInsertCard and
|
if keycardFlowType == ResponseTypeValueInsertCard and
|
||||||
keycardEvent.error.len > 0 and
|
keycardEvent.error.len > 0 and
|
||||||
keycardEvent.error == ErrorConnection:
|
keycardEvent.error == ErrorConnection:
|
||||||
controller.setKeycardData(ResponseTypeValueInsertCard)
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = true))
|
||||||
return nil
|
return nil
|
||||||
if keycardFlowType == ResponseTypeValueCardInserted:
|
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||||
controller.setKeycardData("")
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||||
return createState(StateType.ReadingKeycard, self.flowType, nil)
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.KeycardInserted, self.flowType, self.getBackState)
|
||||||
|
return createState(StateType.KeycardInserted, self.flowType, nil)
|
||||||
return nil
|
return nil
|
|
@ -0,0 +1,13 @@
|
||||||
|
type
|
||||||
|
KeyPairMigrateFailureState* = ref object of State
|
||||||
|
|
||||||
|
proc newKeyPairMigrateFailureState*(flowType: FlowType, backState: State): KeyPairMigrateFailureState =
|
||||||
|
result = KeyPairMigrateFailureState()
|
||||||
|
result.setup(flowType, StateType.KeyPairMigrateFailure, backState)
|
||||||
|
|
||||||
|
proc delete*(self: KeyPairMigrateFailureState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
|
@ -0,0 +1,16 @@
|
||||||
|
type
|
||||||
|
KeyPairMigrateSuccessState* = ref object of State
|
||||||
|
|
||||||
|
proc newKeyPairMigrateSuccessState*(flowType: FlowType, backState: State): KeyPairMigrateSuccessState =
|
||||||
|
result = KeyPairMigrateSuccessState()
|
||||||
|
result.setup(flowType, StateType.KeyPairMigrateSuccess, backState)
|
||||||
|
|
||||||
|
proc delete*(self: KeyPairMigrateSuccessState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: KeyPairMigrateSuccessState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||||
|
if controller.getSelectedKeyPairIsProfile():
|
||||||
|
info "restart the app because of successfully migrated profile keypair"
|
||||||
|
quit() # quit the app
|
|
@ -0,0 +1,20 @@
|
||||||
|
type
|
||||||
|
KeycardEmptyMetadataState* = ref object of State
|
||||||
|
|
||||||
|
proc newKeycardEmptyMetadataState*(flowType: FlowType, backState: State): KeycardEmptyMetadataState =
|
||||||
|
result = KeycardEmptyMetadataState()
|
||||||
|
result.setup(flowType, StateType.KeycardEmptyMetadata, backState)
|
||||||
|
|
||||||
|
proc delete*(self: KeycardEmptyMetadataState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: KeycardEmptyMetadataState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: KeycardEmptyMetadataState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||||
|
return nil
|
|
@ -9,5 +9,6 @@ proc delete*(self: KeycardEmptyState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
method executePrimaryCommand*(self: KeycardEmptyState, controller: Controller) =
|
method executePrimaryCommand*(self: KeycardEmptyState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -0,0 +1,19 @@
|
||||||
|
type
|
||||||
|
KeycardInsertedState* = ref object of State
|
||||||
|
|
||||||
|
proc newKeycardInsertedState*(flowType: FlowType, backState: State): KeycardInsertedState =
|
||||||
|
result = KeycardInsertedState()
|
||||||
|
result.setup(flowType, StateType.KeycardInserted, backState)
|
||||||
|
|
||||||
|
proc delete*(self: KeycardInsertedState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextSecondaryState*(self: KeycardInsertedState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.ReadingKeycard, self.flowType, self.getBackState)
|
||||||
|
return createState(StateType.ReadingKeycard, self.flowType, nil)
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: KeycardInsertedState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -0,0 +1,20 @@
|
||||||
|
type
|
||||||
|
KeycardMetadataDisplayState* = ref object of State
|
||||||
|
|
||||||
|
proc newKeycardMetadataDisplayState*(flowType: FlowType, backState: State): KeycardMetadataDisplayState =
|
||||||
|
result = KeycardMetadataDisplayState()
|
||||||
|
result.setup(flowType, StateType.KeycardMetadataDisplay, backState)
|
||||||
|
|
||||||
|
proc delete*(self: KeycardMetadataDisplayState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: KeycardMetadataDisplayState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.FactoryResetConfirmationDisplayMetadata, self.flowType, self)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: KeycardMetadataDisplayState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -0,0 +1,22 @@
|
||||||
|
type
|
||||||
|
KeycardNotEmptyState* = ref object of State
|
||||||
|
|
||||||
|
proc newKeycardNotEmptyState*(flowType: FlowType, backState: State): KeycardNotEmptyState =
|
||||||
|
result = KeycardNotEmptyState()
|
||||||
|
result.setup(flowType, StateType.KeycardNotEmpty, backState)
|
||||||
|
|
||||||
|
proc delete*(self: KeycardNotEmptyState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: KeycardNotEmptyState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true))
|
||||||
|
controller.runGetMetadataFlow()
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: KeycardNotEmptyState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: KeycardNotEmptyState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -0,0 +1,20 @@
|
||||||
|
type
|
||||||
|
MaxPinRetriesReachedState* = ref object of State
|
||||||
|
|
||||||
|
proc newMaxPinRetriesReachedState*(flowType: FlowType, backState: State): MaxPinRetriesReachedState =
|
||||||
|
result = MaxPinRetriesReachedState()
|
||||||
|
result.setup(flowType, StateType.MaxPinRetriesReached, backState)
|
||||||
|
|
||||||
|
proc delete*(self: MaxPinRetriesReachedState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: MaxPinRetriesReachedState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -0,0 +1,38 @@
|
||||||
|
type
|
||||||
|
MigratingKeyPairState* = ref object of State
|
||||||
|
migrationSuccess: bool
|
||||||
|
|
||||||
|
proc newMigratingKeyPairState*(flowType: FlowType, backState: State): MigratingKeyPairState =
|
||||||
|
result = MigratingKeyPairState()
|
||||||
|
result.setup(flowType, StateType.MigratingKeyPair, backState)
|
||||||
|
result.migrationSuccess = false
|
||||||
|
|
||||||
|
proc delete*(self: MigratingKeyPairState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: MigratingKeyPairState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
# Ran authentication popup and get pass from there...
|
||||||
|
let password = controller.getPassword()
|
||||||
|
self.migrationSuccess = controller.verifyPassword(password)
|
||||||
|
if controller.getSelectedKeyPairIsProfile():
|
||||||
|
self.migrationSuccess = self.migrationSuccess and controller.convertToKeycardAccount(password)
|
||||||
|
if not self.migrationSuccess:
|
||||||
|
return
|
||||||
|
controller.runStoreMetadataFlow(controller.getSelectedKeyPairName(), controller.getPin(),
|
||||||
|
controller.getSelectedKeyPairWalletPaths())
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: MigratingKeyPairState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if not self.migrationSuccess:
|
||||||
|
return createState(StateType.KeyPairMigrateFailure, self.flowType, nil)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: MigratingKeyPairState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
return createState(StateType.KeyPairMigrateSuccess, self.flowType, nil)
|
|
@ -9,5 +9,6 @@ proc delete*(self: NotKeycardState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
method executePrimaryCommand*(self: NotKeycardState, controller: Controller) =
|
method executePrimaryCommand*(self: NotKeycardState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -0,0 +1,21 @@
|
||||||
|
type
|
||||||
|
PinSetState* = ref object of State
|
||||||
|
|
||||||
|
proc newPinSetState*(flowType: FlowType, backState: State): PinSetState =
|
||||||
|
result = PinSetState()
|
||||||
|
result.setup(flowType, StateType.PinSet, backState)
|
||||||
|
|
||||||
|
proc delete*(self: PinSetState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: PinSetState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if controller.isMnemonicBackedUp() or not controller.getSelectedKeyPairIsProfile():
|
||||||
|
return createState(StateType.EnterSeedPhrase, self.flowType, nil)
|
||||||
|
else:
|
||||||
|
return createState(StateType.SeedPhraseDisplay, self.flowType, nil)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: PinSetState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -0,0 +1,20 @@
|
||||||
|
type
|
||||||
|
PinVerifiedState* = ref object of State
|
||||||
|
|
||||||
|
proc newPinVerifiedState*(flowType: FlowType, backState: State): PinVerifiedState =
|
||||||
|
result = PinVerifiedState()
|
||||||
|
result.setup(flowType, StateType.PinVerified, backState)
|
||||||
|
|
||||||
|
proc delete*(self: PinVerifiedState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: PinVerifiedState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.KeycardMetadataDisplay, self.flowType, nil)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: PinVerifiedState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
|
@ -9,15 +9,10 @@ proc delete*(self: PluginReaderState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
method executePrimaryCommand*(self: PluginReaderState, controller: Controller) =
|
method executePrimaryCommand*(self: PluginReaderState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
controller: Controller): State =
|
controller: Controller): State =
|
||||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
||||||
keycardEvent.error.len > 0 and
|
|
||||||
keycardEvent.error == ErrorConnection:
|
|
||||||
controller.resumeCurrentFlowLater()
|
|
||||||
return nil
|
|
||||||
if keycardFlowType == ResponseTypeValueInsertCard:
|
|
||||||
return createState(StateType.InsertKeycard, self.flowType, nil)
|
|
|
@ -9,21 +9,16 @@ proc delete*(self: ReadingKeycardState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
method executePrimaryCommand*(self: ReadingKeycardState, controller: Controller) =
|
method executePrimaryCommand*(self: ReadingKeycardState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method getNextSecondaryState*(self: ReadingKeycardState, controller: Controller): State =
|
||||||
|
let (flowType, flowEvent) = controller.getLastReceivedKeycardData()
|
||||||
|
# this is used in case a keycard is not inserted in the moment when flow is run (we're animating an insertion)
|
||||||
|
return ensureReaderAndCardPresenceAndResolveNextState(self, flowType, flowEvent, controller)
|
||||||
|
|
||||||
method resolveKeycardNextState*(self: ReadingKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
method resolveKeycardNextState*(self: ReadingKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
controller: Controller): State =
|
controller: Controller): State =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
# this is used in case a keycard is inserted and we jump to the first meaningful screen
|
||||||
if keycardFlowType == ResponseTypeValueSwapCard and
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
||||||
keycardEvent.error.len > 0 and
|
|
||||||
keycardEvent.error == ErrorNotAKeycard:
|
|
||||||
return createState(StateType.NotKeycard, self.flowType, nil)
|
|
||||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
|
||||||
keycardEvent.error.len > 0:
|
|
||||||
if keycardEvent.error == ErrorOk:
|
|
||||||
return createState(StateType.FactoryResetSuccess, self.flowType, nil)
|
|
||||||
if keycardEvent.error == ErrorNoKeys:
|
|
||||||
return createState(StateType.KeycardEmpty, self.flowType, nil)
|
|
||||||
controller.setContainsMetadata(keycardEvent.error != ErrorNoData)
|
|
||||||
return createState(StateType.RecognizedKeycard, self.flowType, nil)
|
|
|
@ -9,11 +9,15 @@ proc delete*(self: RecognizedKeycardState) =
|
||||||
self.State.delete
|
self.State.delete
|
||||||
|
|
||||||
method executePrimaryCommand*(self: RecognizedKeycardState, controller: Controller) =
|
method executePrimaryCommand*(self: RecognizedKeycardState, controller: Controller) =
|
||||||
if self.flowType == FlowType.FactoryReset:
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controller): State =
|
method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controller): State =
|
||||||
if controller.containsMetadata():
|
if self.flowType == FlowType.FactoryReset:
|
||||||
discard # from here we will jump to enter pin view once we add that in keycard settings
|
if controller.containsMetadata():
|
||||||
else:
|
return createState(StateType.EnterPin, self.flowType, nil)
|
||||||
return createState(StateType.FactoryResetConfirmation, self.flowType, nil)
|
else:
|
||||||
|
return createState(StateType.FactoryResetConfirmation, self.flowType, nil)
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.CreatePin, self.flowType, self.getBackState)
|
|
@ -0,0 +1,34 @@
|
||||||
|
type
|
||||||
|
RepeatPinState* = ref object of State
|
||||||
|
|
||||||
|
proc newRepeatPinState*(flowType: FlowType, backState: State): RepeatPinState =
|
||||||
|
result = RepeatPinState()
|
||||||
|
result.setup(flowType, StateType.RepeatPin, backState)
|
||||||
|
|
||||||
|
proc delete*(self: RepeatPinState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executeBackCommand*(self: RepeatPinState, controller: Controller) =
|
||||||
|
controller.setPin("")
|
||||||
|
controller.setPinMatch(false)
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: RepeatPinState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method executeTertiaryCommand*(self: RepeatPinState, controller: Controller) =
|
||||||
|
if not controller.getPinMatch():
|
||||||
|
return
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.storePinToKeycard(controller.getPin(), controller.generateRandomPUK())
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: RepeatPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterMnemonic and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorLoadingKeys:
|
||||||
|
return createState(StateType.PinSet, self.flowType, nil)
|
|
@ -0,0 +1,16 @@
|
||||||
|
type
|
||||||
|
SeedPhraseDisplayState* = ref object of State
|
||||||
|
|
||||||
|
proc newSeedPhraseDisplayState*(flowType: FlowType, backState: State): SeedPhraseDisplayState =
|
||||||
|
result = SeedPhraseDisplayState()
|
||||||
|
result.setup(flowType, StateType.SeedPhraseDisplay, backState)
|
||||||
|
|
||||||
|
proc delete*(self: SeedPhraseDisplayState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: SeedPhraseDisplayState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: SeedPhraseDisplayState, controller: Controller): State =
|
||||||
|
return createState(StateType.SeedPhraseEnterWords, self.flowType, self)
|
|
@ -0,0 +1,31 @@
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
type
|
||||||
|
SeedPhraseEnterWordsState* = ref object of State
|
||||||
|
|
||||||
|
proc newSeedPhraseEnterWordsState*(flowType: FlowType, backState: State): SeedPhraseEnterWordsState =
|
||||||
|
result = SeedPhraseEnterWordsState()
|
||||||
|
result.setup(flowType, StateType.SeedPhraseEnterWords, backState)
|
||||||
|
|
||||||
|
proc delete*(self: SeedPhraseEnterWordsState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: SeedPhraseEnterWordsState, controller: Controller) =
|
||||||
|
let mnemonic = controller.getMnemonic()
|
||||||
|
controller.storeSeedPhraseToKeycard(mnemonic.split(" ").len, mnemonic)
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: SeedPhraseEnterWordsState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: SeedPhraseEnterWordsState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.keyUid.len > 0:
|
||||||
|
controller.setKeyUid(keycardEvent.keyUid)
|
||||||
|
controller.removeMnemonic()
|
||||||
|
return createState(StateType.MigratingKeyPair, self.flowType, nil)
|
|
@ -0,0 +1,21 @@
|
||||||
|
type
|
||||||
|
SelectExistingKeyPairState* = ref object of State
|
||||||
|
|
||||||
|
proc newSelectExistingKeyPairState*(flowType: FlowType, backState: State): SelectExistingKeyPairState =
|
||||||
|
result = SelectExistingKeyPairState()
|
||||||
|
result.setup(flowType, StateType.SelectExistingKeyPair, backState)
|
||||||
|
|
||||||
|
proc delete*(self: SelectExistingKeyPairState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: SelectExistingKeyPairState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.runLoadAccountFlow()
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: SelectExistingKeyPairState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: SelectExistingKeyPairState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -1,24 +1,39 @@
|
||||||
import ../controller
|
import ../controller
|
||||||
from ../../../../../app_service/service/keycard/service import KeycardEvent, KeyDetails
|
from ../../../../../app_service/service/keycard/service import KeycardEvent, KeyDetails
|
||||||
|
from ../io_interface import FlowType
|
||||||
|
|
||||||
export KeycardEvent, KeyDetails
|
export FlowType, KeycardEvent, KeyDetails
|
||||||
|
|
||||||
type FlowType* {.pure.} = enum
|
|
||||||
General = "General"
|
|
||||||
FactoryReset = "FactoryReset"
|
|
||||||
|
|
||||||
|
|
||||||
type StateType* {.pure.} = enum
|
type StateType* {.pure.} = enum
|
||||||
NoState = "NoState"
|
NoState = "NoState"
|
||||||
PluginReader = "PluginReader"
|
PluginReader = "PluginReader"
|
||||||
ReadingKeycard = "ReadingKeycard"
|
ReadingKeycard = "ReadingKeycard"
|
||||||
InsertKeycard = "InsertKeycard"
|
InsertKeycard = "InsertKeycard"
|
||||||
|
KeycardInserted = "KeycardInserted"
|
||||||
|
CreatePin = "CreatePin"
|
||||||
|
RepeatPin = "RepeatPin"
|
||||||
|
PinSet = "PinSet"
|
||||||
|
PinVerified = "PinVerified"
|
||||||
EnterPin = "EnterPin"
|
EnterPin = "EnterPin"
|
||||||
|
WrongPin = "WrongPin"
|
||||||
|
MaxPinRetriesReached = "MaxPinRetriesReached"
|
||||||
FactoryResetConfirmation = "FactoryResetConfirmation"
|
FactoryResetConfirmation = "FactoryResetConfirmation"
|
||||||
|
FactoryResetConfirmationDisplayMetadata = "FactoryResetConfirmationDisplayMetadata"
|
||||||
FactoryResetSuccess = "FactoryResetSuccess"
|
FactoryResetSuccess = "FactoryResetSuccess"
|
||||||
|
KeycardEmptyMetadata = "KeycardEmptyMetadata"
|
||||||
|
KeycardMetadataDisplay = "KeycardMetadataDisplay"
|
||||||
KeycardEmpty = "KeycardEmpty"
|
KeycardEmpty = "KeycardEmpty"
|
||||||
|
KeycardNotEmpty = "KeycardNotEmpty"
|
||||||
NotKeycard = "NotKeycard"
|
NotKeycard = "NotKeycard"
|
||||||
RecognizedKeycard = "RecognizedKeycard"
|
RecognizedKeycard = "RecognizedKeycard"
|
||||||
|
SelectExistingKeyPair = "SelectExistingKeyPair"
|
||||||
|
EnterSeedPhrase = "EnterSeedPhrase"
|
||||||
|
WrongSeedPhrase = "WrongSeedPhrase"
|
||||||
|
SeedPhraseDisplay = "SeedPhraseDisplay"
|
||||||
|
SeedPhraseEnterWords = "SeedPhraseEnterWords"
|
||||||
|
KeyPairMigrateSuccess = "KeyPairMigrateSuccess"
|
||||||
|
KeyPairMigrateFailure = "KeyPairMigrateFailure"
|
||||||
|
MigratingKeyPair = "MigratingKeyPair"
|
||||||
|
|
||||||
|
|
||||||
## This is the base class for all state we may have in onboarding/login flow.
|
## This is the base class for all state we may have in onboarding/login flow.
|
||||||
|
@ -70,6 +85,10 @@ method getNextPrimaryState*(self: State, controller: Controller): State {.inlin
|
||||||
method getNextSecondaryState*(self: State, controller: Controller): State {.inline base.} =
|
method getNextSecondaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
## Returns next state instance in case the "tertiary" action is triggered
|
||||||
|
method getNextTertiaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||||
|
return nil
|
||||||
|
|
||||||
## This method is executed in case "back" button is clicked
|
## This method is executed in case "back" button is clicked
|
||||||
method executeBackCommand*(self: State, controller: Controller) {.inline base.} =
|
method executeBackCommand*(self: State, controller: Controller) {.inline base.} =
|
||||||
discard
|
discard
|
||||||
|
@ -82,6 +101,10 @@ method executePrimaryCommand*(self: State, controller: Controller) {.inline base
|
||||||
method executeSecondaryCommand*(self: State, controller: Controller) {.inline base.} =
|
method executeSecondaryCommand*(self: State, controller: Controller) {.inline base.} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
## This method is executed in case "tertiary" action is triggered
|
||||||
|
method executeTertiaryCommand*(self: State, controller: Controller) {.inline base.} =
|
||||||
|
discard
|
||||||
|
|
||||||
## This method is used for handling aync responses for keycard related states
|
## This method is used for handling aync responses for keycard related states
|
||||||
method resolveKeycardNextState*(self: State, keycardFlowType: string, keycardEvent: KeycardEvent,
|
method resolveKeycardNextState*(self: State, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
controller: Controller): State {.inline base.} =
|
controller: Controller): State {.inline base.} =
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import chronicles
|
import parseutils, chronicles
|
||||||
import ../../../../../app_service/service/keycard/constants
|
import ../../../../../app_service/service/keycard/constants
|
||||||
import ../controller
|
import ../controller
|
||||||
|
from ../../../../../app_service/service/keycard/service import KCSFlowType
|
||||||
from ../../../../../app_service/service/keycard/service import PINLengthForStatusApp
|
from ../../../../../app_service/service/keycard/service import PINLengthForStatusApp
|
||||||
from ../../../../../app_service/service/keycard/service import PUKLengthForStatusApp
|
from ../../../../../app_service/service/keycard/service import PUKLengthForStatusApp
|
||||||
import state
|
import state
|
||||||
|
@ -8,37 +9,217 @@ import state
|
||||||
logScope:
|
logScope:
|
||||||
topics = "startup-module-state-factory"
|
topics = "startup-module-state-factory"
|
||||||
|
|
||||||
|
# The following constants will be used in bitwise operation
|
||||||
|
type PredefinedKeycardData* {.pure.} = enum
|
||||||
|
WronglyInsertedCard = 1
|
||||||
|
HideKeyPair = 2
|
||||||
|
WrongSeedPhrase = 4
|
||||||
|
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State
|
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State
|
||||||
|
proc getPredefinedKeycardData*(currValue: string, value: PredefinedKeycardData, add: bool): string
|
||||||
|
proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State
|
||||||
|
proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State
|
||||||
|
|
||||||
include enter_pin_state
|
include create_pin_state
|
||||||
|
include enter_pin_state
|
||||||
|
include enter_seed_phrase_state
|
||||||
|
include factory_reset_confirmation_displayed_metadata_state
|
||||||
include factory_reset_confirmation_state
|
include factory_reset_confirmation_state
|
||||||
include factory_reset_success_state
|
include factory_reset_success_state
|
||||||
include insert_keycard_state
|
include insert_keycard_state
|
||||||
|
include key_pair_migrate_failure_state
|
||||||
|
include key_pair_migrate_success_state
|
||||||
|
include keycard_empty_metadata_state
|
||||||
include keycard_empty_state
|
include keycard_empty_state
|
||||||
|
include keycard_inserted_state
|
||||||
|
include keycard_metadata_display_state
|
||||||
|
include keycard_not_empty_state
|
||||||
|
include max_pin_retries_reached_state
|
||||||
|
include migrating_key_pair_state
|
||||||
include not_keycard_state
|
include not_keycard_state
|
||||||
|
include pin_set_state
|
||||||
|
include pin_verified_state
|
||||||
include plugin_reader_state
|
include plugin_reader_state
|
||||||
include reading_keycard_state
|
include reading_keycard_state
|
||||||
include recognized_keycard_state
|
include recognized_keycard_state
|
||||||
|
include repeat_pin_state
|
||||||
|
include seed_phrase_display_state
|
||||||
|
include seed_phrase_enter_words_state
|
||||||
|
include select_existing_key_pair_state
|
||||||
|
include wrong_pin_state
|
||||||
|
include wrong_seed_phrase_state
|
||||||
|
|
||||||
|
proc getPredefinedKeycardData*(currValue: string, value: PredefinedKeycardData, add: bool): string =
|
||||||
|
var currNum: int
|
||||||
|
try:
|
||||||
|
if add:
|
||||||
|
if parseInt(currValue, currNum) == 0:
|
||||||
|
return $(value.int)
|
||||||
|
else:
|
||||||
|
return $(currNum or value.int)
|
||||||
|
else:
|
||||||
|
if parseInt(currValue, currNum) == 0:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return $(currNum and (not value.int))
|
||||||
|
except:
|
||||||
|
return if add: $(value.int) else: ""
|
||||||
|
|
||||||
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State =
|
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State =
|
||||||
|
if stateToBeCreated == StateType.CreatePin:
|
||||||
|
return newCreatePinState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.EnterPin:
|
if stateToBeCreated == StateType.EnterPin:
|
||||||
return newEnterPinState(flowType, backState)
|
return newEnterPinState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.EnterSeedPhrase:
|
||||||
|
return newEnterSeedPhraseState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.FactoryResetConfirmationDisplayMetadata:
|
||||||
|
return newFactoryResetConfirmationDisplayMetadataState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.FactoryResetConfirmation:
|
if stateToBeCreated == StateType.FactoryResetConfirmation:
|
||||||
return newFactoryResetConfirmationState(flowType, backState)
|
return newFactoryResetConfirmationState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.FactoryResetSuccess:
|
if stateToBeCreated == StateType.FactoryResetSuccess:
|
||||||
return newFactoryResetSuccessState(flowType, backState)
|
return newFactoryResetSuccessState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.InsertKeycard:
|
if stateToBeCreated == StateType.InsertKeycard:
|
||||||
return newInsertKeycardState(flowType, backState)
|
return newInsertKeycardState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.KeyPairMigrateFailure:
|
||||||
|
return newKeyPairMigrateFailureState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.KeyPairMigrateSuccess:
|
||||||
|
return newKeyPairMigrateSuccessState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.KeycardInserted:
|
||||||
|
return newKeycardInsertedState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.KeycardEmptyMetadata:
|
||||||
|
return newKeycardEmptyMetadataState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.KeycardEmpty:
|
if stateToBeCreated == StateType.KeycardEmpty:
|
||||||
return newKeycardEmptyState(flowType, backState)
|
return newKeycardEmptyState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.KeycardMetadataDisplay:
|
||||||
|
return newKeycardMetadataDisplayState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.KeycardNotEmpty:
|
||||||
|
return newKeycardNotEmptyState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.MaxPinRetriesReached:
|
||||||
|
return newMaxPinRetriesReachedState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.MigratingKeyPair:
|
||||||
|
return newMigratingKeyPairState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.NotKeycard:
|
if stateToBeCreated == StateType.NotKeycard:
|
||||||
return newNotKeycardState(flowType, backState)
|
return newNotKeycardState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.PinSet:
|
||||||
|
return newPinSetState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.PinVerified:
|
||||||
|
return newPinVerifiedState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.PluginReader:
|
if stateToBeCreated == StateType.PluginReader:
|
||||||
return newPluginReaderState(flowType, backState)
|
return newPluginReaderState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.ReadingKeycard:
|
if stateToBeCreated == StateType.ReadingKeycard:
|
||||||
return newReadingKeycardState(flowType, backState)
|
return newReadingKeycardState(flowType, backState)
|
||||||
if stateToBeCreated == StateType.RecognizedKeycard:
|
if stateToBeCreated == StateType.RecognizedKeycard:
|
||||||
return newRecognizedKeycardState(flowType, backState)
|
return newRecognizedKeycardState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.RepeatPin:
|
||||||
|
return newRepeatPinState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.SeedPhraseDisplay:
|
||||||
|
return newSeedPhraseDisplayState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.SeedPhraseEnterWords:
|
||||||
|
return newSeedPhraseEnterWordsState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.SelectExistingKeyPair:
|
||||||
|
return newSelectExistingKeyPairState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.WrongPin:
|
||||||
|
return newWrongPinState(flowType, backState)
|
||||||
|
if stateToBeCreated == StateType.WrongSeedPhrase:
|
||||||
|
return newWrongSeedPhraseState(flowType, backState)
|
||||||
|
|
||||||
error "No implementation available for state ", state=stateToBeCreated
|
error "No implementation available for state ", state=stateToBeCreated
|
||||||
|
|
||||||
|
proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State =
|
||||||
|
## Handling factory reset flow
|
||||||
|
if state.flowType == FlowType.FactoryReset:
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorConnection:
|
||||||
|
controller.resumeCurrentFlowLater()
|
||||||
|
if state.stateType == StateType.PluginReader:
|
||||||
|
return nil
|
||||||
|
return createState(StateType.PluginReader, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueInsertCard and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorConnection:
|
||||||
|
if state.stateType == StateType.InsertKeycard:
|
||||||
|
return nil
|
||||||
|
return createState(StateType.InsertKeycard, state.flowType, state)
|
||||||
|
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||||
|
return createState(StateType.KeycardInserted, state.flowType, nil)
|
||||||
|
|
||||||
|
## Handling setup new keycard flow
|
||||||
|
if state.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorConnection:
|
||||||
|
controller.resumeCurrentFlowLater()
|
||||||
|
if state.stateType == StateType.PluginReader:
|
||||||
|
return nil
|
||||||
|
return createState(StateType.PluginReader, state.flowType, state)
|
||||||
|
if keycardFlowType == ResponseTypeValueInsertCard and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorConnection:
|
||||||
|
if state.stateType == StateType.InsertKeycard:
|
||||||
|
return nil
|
||||||
|
return createState(StateType.InsertKeycard, state.flowType, state)
|
||||||
|
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||||
|
return createState(StateType.KeycardInserted, state.flowType, state.getBackState)
|
||||||
|
|
||||||
|
proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State =
|
||||||
|
let ensureState = ensureReaderAndCardPresence(state, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not ensureState.isNil:
|
||||||
|
return ensureState
|
||||||
|
## Handling factory reset flow
|
||||||
|
if state.flowType == FlowType.FactoryReset:
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN:
|
||||||
|
return createState(StateType.EnterPin, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorNotAKeycard:
|
||||||
|
return createState(StateType.NotKeycard, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||||
|
if keycardEvent.error.len > 0:
|
||||||
|
if keycardEvent.error == ErrorOk:
|
||||||
|
return createState(StateType.FactoryResetSuccess, state.flowType, nil)
|
||||||
|
if keycardEvent.error == ErrorNoKeys:
|
||||||
|
return createState(StateType.KeycardEmpty, state.flowType, nil)
|
||||||
|
if keycardEvent.error == ErrorNoData:
|
||||||
|
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
|
||||||
|
if keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.cardMetadata.name.len > 0 and keycardEvent.cardMetadata.walletAccounts.len > 0:
|
||||||
|
controller.setContainsMetadata(true)
|
||||||
|
return createState(StateType.RecognizedKeycard, state.flowType, nil)
|
||||||
|
|
||||||
|
## Handling setup new keycard flow
|
||||||
|
if state.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||||
|
keycardEvent.error.len > 0:
|
||||||
|
if keycardEvent.error == ErrorNotAKeycard:
|
||||||
|
return createState(StateType.NotKeycard, state.flowType, nil)
|
||||||
|
if keycardEvent.error == ErrorHasKeys:
|
||||||
|
return createState(StateType.KeycardNotEmpty, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN:
|
||||||
|
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
|
||||||
|
return createState(StateType.EnterPin, state.flowType, nil)
|
||||||
|
return createState(StateType.KeycardNotEmpty, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.error.len > 0:
|
||||||
|
controller.setKeycardData("")
|
||||||
|
if keycardEvent.error == ErrorOk:
|
||||||
|
return createState(StateType.FactoryResetSuccess, state.flowType, nil)
|
||||||
|
if keycardEvent.error == ErrorNoData:
|
||||||
|
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
|
||||||
|
if keycardEvent.error == ErrorNoKeys:
|
||||||
|
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterNewPIN and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == ErrorRequireInit:
|
||||||
|
return createState(StateType.RecognizedKeycard, state.flowType, state.getBackState)
|
|
@ -55,4 +55,8 @@ QtObject:
|
||||||
|
|
||||||
proc secondaryActionClicked*(self: StateWrapper) {.signal.}
|
proc secondaryActionClicked*(self: StateWrapper) {.signal.}
|
||||||
proc doSecondaryAction*(self: StateWrapper) {.slot.} =
|
proc doSecondaryAction*(self: StateWrapper) {.slot.} =
|
||||||
self.secondaryActionClicked()
|
self.secondaryActionClicked()
|
||||||
|
|
||||||
|
proc tertiaryActionClicked*(self: StateWrapper) {.signal.}
|
||||||
|
proc doTertiaryAction*(self: StateWrapper) {.slot.} =
|
||||||
|
self.tertiaryActionClicked()
|
|
@ -0,0 +1,62 @@
|
||||||
|
type
|
||||||
|
WrongPinState* = ref object of State
|
||||||
|
|
||||||
|
proc newWrongPinState*(flowType: FlowType, backState: State): WrongPinState =
|
||||||
|
result = WrongPinState()
|
||||||
|
result.setup(flowType, StateType.WrongPin, backState)
|
||||||
|
|
||||||
|
proc delete*(self: WrongPinState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method getNextPrimaryState*(self: WrongPinState, controller: Controller): State =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: WrongPinState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method executeTertiaryCommand*(self: WrongPinState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.FactoryReset or
|
||||||
|
self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if controller.getPin().len == PINLengthForStatusApp:
|
||||||
|
controller.enterKeycardPin(controller.getPin())
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.FactoryReset:
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == RequestParamPIN:
|
||||||
|
controller.setKeycardData($keycardEvent.pinRetries)
|
||||||
|
if keycardEvent.pinRetries > 0:
|
||||||
|
return self
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||||
|
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
|
||||||
|
return createState(StateType.PinVerified, self.flowType, nil)
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||||
|
keycardEvent.error.len > 0 and
|
||||||
|
keycardEvent.error == RequestParamPIN:
|
||||||
|
controller.setKeycardData($keycardEvent.pinRetries)
|
||||||
|
if keycardEvent.pinRetries > 0:
|
||||||
|
return self
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||||
|
keycardEvent.error.len == 0:
|
||||||
|
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||||
|
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||||
|
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
|
||||||
|
return createState(StateType.PinVerified, self.flowType, nil)
|
|
@ -0,0 +1,40 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
type
|
||||||
|
WrongSeedPhraseState* = ref object of State
|
||||||
|
verifiedSeedPhrase: bool
|
||||||
|
|
||||||
|
proc newWrongSeedPhraseState*(flowType: FlowType, backState: State): WrongSeedPhraseState =
|
||||||
|
result = WrongSeedPhraseState()
|
||||||
|
result.setup(flowType, StateType.WrongSeedPhrase, backState)
|
||||||
|
result.verifiedSeedPhrase = false
|
||||||
|
|
||||||
|
proc delete*(self: WrongSeedPhraseState) =
|
||||||
|
self.State.delete
|
||||||
|
|
||||||
|
method executePrimaryCommand*(self: WrongSeedPhraseState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
|
||||||
|
sleep(500) # just to shortly remove text on the UI side
|
||||||
|
self.verifiedSeedPhrase = controller.validSeedPhrase(controller.getSeedPhrase()) and
|
||||||
|
controller.seedPhraseRefersToLoggedInUser(controller.getSeedPhrase())
|
||||||
|
if self.verifiedSeedPhrase:
|
||||||
|
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase())
|
||||||
|
else:
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
|
||||||
|
|
||||||
|
method executeSecondaryCommand*(self: WrongSeedPhraseState, controller: Controller) =
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
|
||||||
|
method resolveKeycardNextState*(self: WrongSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||||
|
controller: Controller): State =
|
||||||
|
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||||
|
if not state.isNil:
|
||||||
|
return state
|
||||||
|
if self.flowType == FlowType.SetupNewKeycard:
|
||||||
|
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||||
|
keycardEvent.keyUid.len > 0:
|
||||||
|
controller.setKeyUid(keycardEvent.keyUid)
|
||||||
|
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
|
||||||
|
return createState(StateType.MigratingKeyPair, self.flowType, nil)
|
|
@ -1,13 +1,20 @@
|
||||||
import NimQml
|
import NimQml
|
||||||
import ../../../../app/core/eventemitter
|
import ../../../../app/core/eventemitter
|
||||||
from ../../../../app_service/service/keycard/service import KeycardEvent, KeyDetails
|
from ../../../../app_service/service/keycard/service import KeycardEvent, CardMetadata, KeyDetails
|
||||||
|
import models/key_pair_item
|
||||||
|
|
||||||
|
const SignalSharedKeycarModuleDisplayPopup* = "SignalSharedKeycarModuleDisplayPopup"
|
||||||
const SignalSharedKeycarModuleFlowTerminated* = "sharedKeycarModuleFlowTerminated"
|
const SignalSharedKeycarModuleFlowTerminated* = "sharedKeycarModuleFlowTerminated"
|
||||||
|
|
||||||
type
|
type
|
||||||
SharedKeycarModuleFlowTerminatedArgs* = ref object of Args
|
SharedKeycarModuleFlowTerminatedArgs* = ref object of Args
|
||||||
lastStepInTheCurrentFlow*: bool
|
lastStepInTheCurrentFlow*: bool
|
||||||
|
|
||||||
|
type FlowType* {.pure.} = enum
|
||||||
|
General = "General"
|
||||||
|
FactoryReset = "FactoryReset"
|
||||||
|
SetupNewKeycard = "SetupNewKeycard"
|
||||||
|
|
||||||
type
|
type
|
||||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||||
|
|
||||||
|
@ -17,6 +24,9 @@ method delete*(self: AccessInterface) {.base.} =
|
||||||
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getKeycardData*(self: AccessInterface): string {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method setKeycardData*(self: AccessInterface, value: string) {.base.} =
|
method setKeycardData*(self: AccessInterface, value: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
@ -29,13 +39,51 @@ method onPrimaryActionClicked*(self: AccessInterface) {.base.} =
|
||||||
method onSecondaryActionClicked*(self: AccessInterface) {.base.} =
|
method onSecondaryActionClicked*(self: AccessInterface) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method onTertiaryActionClicked*(self: AccessInterface) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method onKeycardResponse*(self: AccessInterface, keycardFlowType: string, keycardEvent: KeycardEvent) {.base.} =
|
method onKeycardResponse*(self: AccessInterface, keycardFlowType: string, keycardEvent: KeycardEvent) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method runFactoryResetFlow*(self: AccessInterface) {.base.} =
|
method runFlow*(self: AccessInterface, flowToRun: FlowType) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method setPin*(self: AccessInterface, value: string) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method setPassword*(self: AccessInterface, value: string) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method checkRepeatedKeycardPinWhileTyping*(self: AccessInterface, pin: string): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getMnemonic*(self: AccessInterface): string {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method setSeedPhrase*(self: AccessInterface, value: string) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getSeedPhrase*(self: AccessInterface): string {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method validSeedPhrase*(self: AccessInterface, value: string): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method setSelectedKeyPair*(self: AccessInterface, item: KeyPairItem) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method setKeyPairStoredOnKeycard*(self: AccessInterface, cardMetadata: CardMetadata) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method loggedInUserUsesBiometricLogin*(self: AccessInterface): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method migratingProfileKeyPair*(self: AccessInterface): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method isProfileKeyPairMigrated*(self: AccessInterface): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
DelegateInterface* = concept c
|
DelegateInterface* = concept c
|
||||||
#c.startupDidLoad()
|
|
||||||
#c.userLoggedIn()
|
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import strformat, marshal
|
||||||
|
|
||||||
|
type
|
||||||
|
KeyPairType* {.pure.} = enum
|
||||||
|
Unknown = -1
|
||||||
|
Profile
|
||||||
|
SeedImport
|
||||||
|
PrivateKeyImport
|
||||||
|
|
||||||
|
type
|
||||||
|
WalletAccountDetails = tuple
|
||||||
|
name: string
|
||||||
|
path: string
|
||||||
|
address: string
|
||||||
|
emoji: string
|
||||||
|
color: string
|
||||||
|
icon: string
|
||||||
|
balance: float64
|
||||||
|
|
||||||
|
type
|
||||||
|
KeyPairItem* = ref object of RootObj
|
||||||
|
pubKey: string
|
||||||
|
name: string
|
||||||
|
image: string
|
||||||
|
icon: string
|
||||||
|
derivedFrom: string
|
||||||
|
pairType: KeyPairType
|
||||||
|
accounts: seq[WalletAccountDetails]
|
||||||
|
|
||||||
|
proc initKeyPairItem*(
|
||||||
|
pubKey: string,
|
||||||
|
name: string,
|
||||||
|
image: string,
|
||||||
|
icon: string,
|
||||||
|
pairType: KeyPairType,
|
||||||
|
derivedFrom: string
|
||||||
|
): KeyPairItem =
|
||||||
|
result = KeyPairItem()
|
||||||
|
result.pubKey = pubKey
|
||||||
|
result.name = name
|
||||||
|
result.image = image
|
||||||
|
result.icon = icon
|
||||||
|
result.pairType = pairType
|
||||||
|
result.derivedFrom = derivedFrom
|
||||||
|
|
||||||
|
proc `$`*(self: KeyPairItem): string =
|
||||||
|
result = fmt"""KeyPairItem[
|
||||||
|
pubKey: {self.pubkey},
|
||||||
|
name: {self.name},
|
||||||
|
image: {self.image},
|
||||||
|
icon: {self.icon},
|
||||||
|
pairType: {$self.pairType},
|
||||||
|
derivedFrom: {self.derivedFrom},
|
||||||
|
accounts: {$self.accounts}
|
||||||
|
]"""
|
||||||
|
|
||||||
|
proc pubKey*(self: KeyPairItem): string {.inline.} =
|
||||||
|
self.pubKey
|
||||||
|
|
||||||
|
proc name*(self: KeyPairItem): string {.inline.} =
|
||||||
|
self.name
|
||||||
|
|
||||||
|
proc image*(self: KeyPairItem): string {.inline.} =
|
||||||
|
self.image
|
||||||
|
|
||||||
|
proc icon*(self: KeyPairItem): string {.inline.} =
|
||||||
|
self.icon
|
||||||
|
|
||||||
|
proc pairType*(self: KeyPairItem): KeyPairType {.inline.} =
|
||||||
|
self.pairType
|
||||||
|
|
||||||
|
proc derivedFrom*(self: KeyPairItem): string {.inline.} =
|
||||||
|
self.derivedFrom
|
||||||
|
|
||||||
|
proc addAccount*(self: KeyPairItem, name, path, address, emoji, color, icon: string, balance: float64) {.inline.} =
|
||||||
|
self.accounts.add((name: name, path: path, address: address, emoji: emoji, color: color, icon: icon, balance: balance))
|
||||||
|
|
||||||
|
proc accounts*(self: KeyPairItem): string {.inline.} =
|
||||||
|
return $$self.accounts
|
||||||
|
|
||||||
|
proc accountsAsArr*(self: KeyPairItem): seq[WalletAccountDetails] {.inline.} =
|
||||||
|
return self.accounts
|
|
@ -0,0 +1,90 @@
|
||||||
|
import NimQml, Tables, strformat
|
||||||
|
import key_pair_item
|
||||||
|
|
||||||
|
type
|
||||||
|
ModelRole {.pure.} = enum
|
||||||
|
PubKey = UserRole + 1
|
||||||
|
Name
|
||||||
|
Image
|
||||||
|
Icon
|
||||||
|
PairType
|
||||||
|
Accounts
|
||||||
|
DerivedFrom
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type
|
||||||
|
KeyPairModel* = ref object of QAbstractListModel
|
||||||
|
items: seq[KeyPairItem]
|
||||||
|
|
||||||
|
proc delete(self: KeyPairModel) =
|
||||||
|
self.items = @[]
|
||||||
|
self.QAbstractListModel.delete
|
||||||
|
|
||||||
|
proc setup(self: KeyPairModel) =
|
||||||
|
self.QAbstractListModel.setup
|
||||||
|
|
||||||
|
proc newKeyPairModel*(): KeyPairModel =
|
||||||
|
new(result, delete)
|
||||||
|
result.setup
|
||||||
|
|
||||||
|
proc countChanged(self: KeyPairModel) {.signal.}
|
||||||
|
proc getCount*(self: KeyPairModel): int {.slot.} =
|
||||||
|
self.items.len
|
||||||
|
QtProperty[int]count:
|
||||||
|
read = getCount
|
||||||
|
notify = countChanged
|
||||||
|
|
||||||
|
proc setItems*(self: KeyPairModel, items: seq[KeyPairItem]) =
|
||||||
|
self.beginResetModel()
|
||||||
|
self.items = items
|
||||||
|
self.endResetModel()
|
||||||
|
self.countChanged()
|
||||||
|
|
||||||
|
proc `$`*(self: KeyPairModel): string =
|
||||||
|
for i in 0 ..< self.items.len:
|
||||||
|
result &= fmt"""KeyPairModel:
|
||||||
|
[{i}]:({$self.items[i]})
|
||||||
|
"""
|
||||||
|
|
||||||
|
method rowCount(self: KeyPairModel, index: QModelIndex = nil): int =
|
||||||
|
return self.items.len
|
||||||
|
|
||||||
|
method roleNames(self: KeyPairModel): Table[int, string] =
|
||||||
|
{
|
||||||
|
ModelRole.PubKey.int: "pubKey",
|
||||||
|
ModelRole.Name.int: "name",
|
||||||
|
ModelRole.Image.int: "image",
|
||||||
|
ModelRole.Icon.int: "icon",
|
||||||
|
ModelRole.PairType.int: "pairType",
|
||||||
|
ModelRole.Accounts.int: "accounts",
|
||||||
|
ModelRole.DerivedFrom.int: "derivedFrom"
|
||||||
|
}.toTable
|
||||||
|
|
||||||
|
method data(self: KeyPairModel, index: QModelIndex, role: int): QVariant =
|
||||||
|
if (not index.isValid):
|
||||||
|
return
|
||||||
|
if (index.row < 0 or index.row >= self.items.len):
|
||||||
|
return
|
||||||
|
let item = self.items[index.row]
|
||||||
|
let enumRole = role.ModelRole
|
||||||
|
case enumRole:
|
||||||
|
of ModelRole.PubKey:
|
||||||
|
result = newQVariant(item.pubKey)
|
||||||
|
of ModelRole.Name:
|
||||||
|
result = newQVariant(item.name)
|
||||||
|
of ModelRole.Image:
|
||||||
|
result = newQVariant(item.image)
|
||||||
|
of ModelRole.Icon:
|
||||||
|
result = newQVariant(item.icon)
|
||||||
|
of ModelRole.PairType:
|
||||||
|
result = newQVariant(item.pairType.int)
|
||||||
|
of ModelRole.Accounts:
|
||||||
|
result = newQVariant(item.accounts)
|
||||||
|
of ModelRole.DerivedFrom:
|
||||||
|
result = newQVariant(item.derivedFrom)
|
||||||
|
|
||||||
|
proc findItemByDerivedFromAddress*(self: KeyPairModel, address: string): KeyPairItem =
|
||||||
|
for i in 0 ..< self.items.len:
|
||||||
|
if(self.items[i].derivedFrom == address):
|
||||||
|
return self.items[i]
|
||||||
|
return nil
|
|
@ -0,0 +1,75 @@
|
||||||
|
import NimQml
|
||||||
|
import key_pair_item
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type KeyPairSelectedItem* = ref object of QObject
|
||||||
|
item: KeyPairItem
|
||||||
|
|
||||||
|
proc delete*(self: KeyPairSelectedItem) =
|
||||||
|
self.QObject.delete
|
||||||
|
|
||||||
|
proc newKeyPairSelectedItem*(): KeyPairSelectedItem =
|
||||||
|
new(result, delete)
|
||||||
|
result.QObject.setup
|
||||||
|
|
||||||
|
proc keyPairSelectedItemChanged*(self: KeyPairSelectedItem) {.signal.}
|
||||||
|
|
||||||
|
proc setItem*(self: KeyPairSelectedItem, item: KeyPairItem) =
|
||||||
|
self.item = item
|
||||||
|
self.keyPairSelectedItemChanged()
|
||||||
|
|
||||||
|
proc getPubKey*(self: KeyPairSelectedItem): string {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return ""
|
||||||
|
return self.item.pubKey()
|
||||||
|
QtProperty[string] pubKey:
|
||||||
|
read = getPubKey
|
||||||
|
notify = keyPairSelectedItemChanged
|
||||||
|
|
||||||
|
proc getName*(self: KeyPairSelectedItem): string {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return ""
|
||||||
|
return self.item.name()
|
||||||
|
QtProperty[string] name:
|
||||||
|
read = getName
|
||||||
|
notify = keyPairSelectedItemChanged
|
||||||
|
|
||||||
|
proc getImage*(self: KeyPairSelectedItem): string {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return ""
|
||||||
|
return self.item.image()
|
||||||
|
QtProperty[string] image:
|
||||||
|
read = getImage
|
||||||
|
notify = keyPairSelectedItemChanged
|
||||||
|
|
||||||
|
proc getIcon*(self: KeyPairSelectedItem): string {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return ""
|
||||||
|
return self.item.icon()
|
||||||
|
QtProperty[string] icon:
|
||||||
|
read = getIcon
|
||||||
|
notify = keyPairSelectedItemChanged
|
||||||
|
|
||||||
|
proc getPairType*(self: KeyPairSelectedItem): int {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return KeyPairType.Profile.int
|
||||||
|
return self.item.pairType().int
|
||||||
|
QtProperty[int] pairType:
|
||||||
|
read = getPairType
|
||||||
|
notify = keyPairSelectedItemChanged
|
||||||
|
|
||||||
|
proc getDerivedFrom*(self: KeyPairSelectedItem): string {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return ""
|
||||||
|
return self.item.derivedFrom()
|
||||||
|
QtProperty[string] derivedFrom:
|
||||||
|
read = getDerivedFrom
|
||||||
|
notify = keyPairSelectedItemChanged
|
||||||
|
|
||||||
|
proc getAccounts*(self: KeyPairSelectedItem): string {.slot.} =
|
||||||
|
if(self.item.isNil):
|
||||||
|
return ""
|
||||||
|
return self.item.accounts()
|
||||||
|
QtProperty[string] accounts:
|
||||||
|
read = getAccounts
|
||||||
|
notify = keyPairSelectedItemChanged
|
|
@ -1,11 +1,16 @@
|
||||||
import NimQml, chronicles
|
import NimQml, random, strutils, marshal, chronicles
|
||||||
|
|
||||||
import io_interface
|
import io_interface
|
||||||
import view, controller
|
import view, controller
|
||||||
import internal/[state, state_factory]
|
import internal/[state, state_factory]
|
||||||
|
import models/[key_pair_model, key_pair_item]
|
||||||
|
import ../../../global/global_singleton
|
||||||
import ../../../core/eventemitter
|
import ../../../core/eventemitter
|
||||||
|
|
||||||
import ../../../../app_service/service/keycard/service as keycard_service
|
import ../../../../app_service/service/keycard/service as keycard_service
|
||||||
|
import ../../../../app_service/service/privacy/service as privacy_service
|
||||||
|
import ../../../../app_service/service/accounts/service as accounts_service
|
||||||
|
import ../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
|
@ -19,20 +24,24 @@ type
|
||||||
viewVariant: QVariant
|
viewVariant: QVariant
|
||||||
controller: Controller
|
controller: Controller
|
||||||
initialized: bool
|
initialized: bool
|
||||||
|
tmpLocalState: State # used when flow is run, until response arrives to determine next state appropriatelly
|
||||||
|
|
||||||
proc newModule*[T](delegate: T,
|
proc newModule*[T](delegate: T,
|
||||||
events: EventEmitter,
|
events: EventEmitter,
|
||||||
keycardService: keycard_service.Service):
|
keycardService: keycard_service.Service,
|
||||||
|
privacyService: privacy_service.Service,
|
||||||
|
accountsService: accounts_service.Service,
|
||||||
|
walletAccountService: wallet_account_service.Service):
|
||||||
Module[T] =
|
Module[T] =
|
||||||
result = Module[T]()
|
result = Module[T]()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.view = view.newView(result)
|
result.view = view.newView(result)
|
||||||
result.viewVariant = newQVariant(result.view)
|
result.viewVariant = newQVariant(result.view)
|
||||||
result.controller = controller.newController(result, events, keycardService)
|
result.controller = controller.newController(result, events, keycardService, privacyService, accountsService,
|
||||||
|
walletAccountService)
|
||||||
result.initialized = false
|
result.initialized = false
|
||||||
|
|
||||||
method delete*[T](self: Module[T]) =
|
method delete*[T](self: Module[T]) =
|
||||||
self.controller.disconnect()
|
|
||||||
self.view.delete
|
self.view.delete
|
||||||
self.viewVariant.delete
|
self.viewVariant.delete
|
||||||
self.controller.delete
|
self.controller.delete
|
||||||
|
@ -40,9 +49,54 @@ method delete*[T](self: Module[T]) =
|
||||||
method getModuleAsVariant*[T](self: Module[T]): QVariant =
|
method getModuleAsVariant*[T](self: Module[T]): QVariant =
|
||||||
return self.viewVariant
|
return self.viewVariant
|
||||||
|
|
||||||
|
method getKeycardData*[T](self: Module[T]): string =
|
||||||
|
return self.view.getKeycardData()
|
||||||
|
|
||||||
method setKeycardData*[T](self: Module[T], value: string) =
|
method setKeycardData*[T](self: Module[T], value: string) =
|
||||||
self.view.setKeycardData(value)
|
self.view.setKeycardData(value)
|
||||||
|
|
||||||
|
method setPin*[T](self: Module[T], value: string) =
|
||||||
|
self.controller.setPin(value)
|
||||||
|
|
||||||
|
method setPassword*[T](self: Module[T], value: string) =
|
||||||
|
self.controller.setPassword(value)
|
||||||
|
|
||||||
|
method checkRepeatedKeycardPinWhileTyping*[T](self: Module[T], pin: string): bool =
|
||||||
|
self.controller.setPinMatch(false)
|
||||||
|
let storedPin = self.controller.getPin()
|
||||||
|
if pin.len > storedPin.len:
|
||||||
|
return false
|
||||||
|
elif pin.len < storedPin.len:
|
||||||
|
for i in 0 ..< pin.len:
|
||||||
|
if pin[i] != storedPin[i]:
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
let match = pin == storedPin
|
||||||
|
self.controller.setPinMatch(match)
|
||||||
|
return match
|
||||||
|
|
||||||
|
method getMnemonic*[T](self: Module[T]): string =
|
||||||
|
return self.controller.getMnemonic()
|
||||||
|
|
||||||
|
method setSeedPhrase*[T](self: Module[T], value: string) =
|
||||||
|
self.controller.setSeedPhrase(value)
|
||||||
|
|
||||||
|
method getSeedPhrase*[T](self: Module[T]): string =
|
||||||
|
return self.controller.getSeedPhrase()
|
||||||
|
|
||||||
|
method validSeedPhrase*[T](self: Module[T], value: string): bool =
|
||||||
|
return self.controller.validSeedPhrase(value)
|
||||||
|
|
||||||
|
method loggedInUserUsesBiometricLogin*[T](self: Module[T]): bool =
|
||||||
|
return self.controller.loggedInUserUsesBiometricLogin()
|
||||||
|
|
||||||
|
method migratingProfileKeyPair*[T](self: Module[T]): bool =
|
||||||
|
return self.controller.getSelectedKeyPairIsProfile()
|
||||||
|
|
||||||
|
method isProfileKeyPairMigrated*[T](self: Module[T]): bool =
|
||||||
|
return self.controller.getLoggedInAccount().keycardPairing.len > 0
|
||||||
|
|
||||||
method onBackActionClicked*[T](self: Module[T]) =
|
method onBackActionClicked*[T](self: Module[T]) =
|
||||||
let currStateObj = self.view.currentStateObj()
|
let currStateObj = self.view.currentStateObj()
|
||||||
if currStateObj.isNil:
|
if currStateObj.isNil:
|
||||||
|
@ -81,11 +135,32 @@ method onSecondaryActionClicked*[T](self: Module[T]) =
|
||||||
self.view.setCurrentState(nextState)
|
self.view.setCurrentState(nextState)
|
||||||
debug "sm_secondary_action - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
|
debug "sm_secondary_action - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
|
||||||
|
|
||||||
method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEvent: KeycardEvent) =
|
method onTertiaryActionClicked*[T](self: Module[T]) =
|
||||||
let currStateObj = self.view.currentStateObj()
|
let currStateObj = self.view.currentStateObj()
|
||||||
if currStateObj.isNil:
|
if currStateObj.isNil:
|
||||||
error "sm_cannot resolve current state"
|
error "sm_cannot resolve current state"
|
||||||
return
|
return
|
||||||
|
debug "sm_tertiary_action", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
||||||
|
currStateObj.executeTertiaryCommand(self.controller)
|
||||||
|
let nextState = currStateObj.getNextTertiaryState(self.controller)
|
||||||
|
if nextState.isNil:
|
||||||
|
return
|
||||||
|
self.view.setCurrentState(nextState)
|
||||||
|
debug "sm_tertiary_action - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
|
||||||
|
|
||||||
|
method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEvent: KeycardEvent) =
|
||||||
|
let currStateObj = self.view.currentStateObj()
|
||||||
|
if currStateObj.isNil:
|
||||||
|
if self.tmpLocalState.isNil:
|
||||||
|
error "sm_cannot resolve current state"
|
||||||
|
return
|
||||||
|
let nextState = self.tmpLocalState.resolveKeycardNextState(keycardFlowType, keycardEvent, self.controller)
|
||||||
|
if nextState.isNil:
|
||||||
|
return
|
||||||
|
self.view.setCurrentState(nextState)
|
||||||
|
self.controller.readyToDisplayPopup()
|
||||||
|
debug "sm_on_keycard_response - from_local - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
|
||||||
|
return
|
||||||
debug "sm_on_keycard_response", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
debug "sm_on_keycard_response", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
||||||
let nextState = currStateObj.resolveKeycardNextState(keycardFlowType, keycardEvent, self.controller)
|
let nextState = currStateObj.resolveKeycardNextState(keycardFlowType, keycardEvent, self.controller)
|
||||||
if nextState.isNil:
|
if nextState.isNil:
|
||||||
|
@ -93,8 +168,131 @@ method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEv
|
||||||
self.view.setCurrentState(nextState)
|
self.view.setCurrentState(nextState)
|
||||||
debug "sm_on_keycard_response - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
|
debug "sm_on_keycard_response - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
|
||||||
|
|
||||||
method runFactoryResetFlow*[T](self: Module[T]) =
|
proc prepareKeyPairsModel[T](self: Module[T]) =
|
||||||
|
let findItemByDerivedFromAddress = proc(items: seq[KeyPairItem], address: string): KeyPairItem =
|
||||||
|
if address.len == 0:
|
||||||
|
return nil
|
||||||
|
for i in 0 ..< items.len:
|
||||||
|
if(items[i].derivedFrom == address):
|
||||||
|
return items[i]
|
||||||
|
return nil
|
||||||
|
|
||||||
|
let countOfKeyPairsForType = proc(items: seq[KeyPairItem], keyPairType: KeyPairType): int =
|
||||||
|
result = 0
|
||||||
|
for i in 0 ..< items.len:
|
||||||
|
if(items[i].pairType == keyPairType):
|
||||||
|
result.inc
|
||||||
|
|
||||||
|
let accounts = self.controller.getWalletAccounts()
|
||||||
|
var items: seq[KeyPairItem]
|
||||||
|
for a in accounts:
|
||||||
|
if a.isChat or a.walletType == WalletTypeWatch:
|
||||||
|
continue
|
||||||
|
var item = findItemByDerivedFromAddress(items, a.derivedfrom)
|
||||||
|
if a.walletType == WalletTypeDefaultStatusAccount or a.walletType == WalletTypeGenerated:
|
||||||
|
if self.isProfileKeyPairMigrated():
|
||||||
|
continue
|
||||||
|
if item.isNil:
|
||||||
|
item = initKeyPairItem(pubKey = singletonInstance.userProfile.getPubKey(),
|
||||||
|
name = singletonInstance.userProfile.getName(),
|
||||||
|
image = singletonInstance.userProfile.getIcon(),
|
||||||
|
icon = "",
|
||||||
|
pairType = KeyPairType.Profile,
|
||||||
|
derivedFrom = a.derivedfrom)
|
||||||
|
items.insert(item, 0) # Status Account must be at first place
|
||||||
|
var icon = ""
|
||||||
|
if a.walletType == WalletTypeDefaultStatusAccount:
|
||||||
|
icon = "wallet"
|
||||||
|
items[0].addAccount(a.name, a.path, a.address, a.emoji, a.color, icon, balance = 0.0)
|
||||||
|
continue
|
||||||
|
if a.walletType == WalletTypeSeed:
|
||||||
|
let diffImports = countOfKeyPairsForType(items, KeyPairType.SeedImport)
|
||||||
|
if item.isNil:
|
||||||
|
item = initKeyPairItem(pubKey = "",
|
||||||
|
name = "Seed Phrase " & $(diffImports + 1), # string created here should be transalted, but so far it's like it is
|
||||||
|
image = "",
|
||||||
|
icon = "key_pair_seed_phrase",
|
||||||
|
pairType = KeyPairType.SeedImport,
|
||||||
|
derivedFrom = a.derivedfrom)
|
||||||
|
items.add(item)
|
||||||
|
item.addAccount(a.name, a.path, a.address, a.emoji, a.color, icon = "", balance = 0.0)
|
||||||
|
continue
|
||||||
|
if a.walletType == WalletTypeKey:
|
||||||
|
let diffImports = countOfKeyPairsForType(items, KeyPairType.PrivateKeyImport)
|
||||||
|
if item.isNil:
|
||||||
|
item = initKeyPairItem(pubKey = "",
|
||||||
|
name = "Key " & $(diffImports + 1), # string created here should be transalted, but so far it's like it is
|
||||||
|
image = "",
|
||||||
|
icon = "key_pair_private_key",
|
||||||
|
pairType = KeyPairType.SeedImport,
|
||||||
|
derivedFrom = a.derivedfrom)
|
||||||
|
items.add(item)
|
||||||
|
item.addAccount(a.name, a.path, a.address, a.emoji, a.color, icon = "", balance = 0.0)
|
||||||
|
continue
|
||||||
|
self.view.createKeyPairModel(items)
|
||||||
|
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
|
||||||
|
self.view.setSelectedKeyPairByTheAddressItIsDerivedFrom(items[0].derivedFrom())
|
||||||
|
|
||||||
|
method runFlow*[T](self: Module[T], flowToRun: FlowType) =
|
||||||
|
if flowToRun == FlowType.General:
|
||||||
|
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||||
|
error "sm_cannot run an general flow"
|
||||||
|
return
|
||||||
if not self.initialized:
|
if not self.initialized:
|
||||||
self.controller.init()
|
self.controller.init()
|
||||||
self.view.setCurrentState(newPluginReaderState(FlowType.FactoryReset, nil))
|
if flowToRun == FlowType.FactoryReset:
|
||||||
self.controller.runGetMetadataFlow()
|
self.prepareKeyPairsModel()
|
||||||
|
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
|
||||||
|
self.controller.runGetMetadataFlow()
|
||||||
|
return
|
||||||
|
if flowToRun == FlowType.SetupNewKeycard:
|
||||||
|
self.prepareKeyPairsModel()
|
||||||
|
self.view.setCurrentState(newSelectExistingKeyPairState(flowToRun, nil))
|
||||||
|
self.controller.readyToDisplayPopup()
|
||||||
|
return
|
||||||
|
|
||||||
|
method setSelectedKeyPair*[T](self: Module[T], item: KeyPairItem) =
|
||||||
|
var paths: seq[string]
|
||||||
|
for a in item.accountsAsArr():
|
||||||
|
paths.add(a.path)
|
||||||
|
self.controller.setSelectedKeyPairIsProfile(item.pairType == KeyPairType.Profile)
|
||||||
|
self.controller.setSelectedKeyPairName(item.name)
|
||||||
|
self.controller.setSelectedKeyPairWalletPaths(paths)
|
||||||
|
|
||||||
|
proc generateRandomColor[T](self: Module[T]): string =
|
||||||
|
let r = rand(0 .. 255)
|
||||||
|
let g = rand(0 .. 255)
|
||||||
|
let b = rand(0 .. 255)
|
||||||
|
return "#" & r.toHex(2) & g.toHex(2) & b.toHex(2)
|
||||||
|
|
||||||
|
proc updateKeyPairItemIfDataAreKnown[T](self: Module[T], address: string, item: var KeyPairItem): bool =
|
||||||
|
let accounts = self.controller.getWalletAccounts()
|
||||||
|
for a in accounts:
|
||||||
|
if a.isChat or a.walletType == WalletTypeWatch or cmpIgnoreCase(a.address, address) != 0:
|
||||||
|
continue
|
||||||
|
var icon = ""
|
||||||
|
if a.walletType == WalletTypeDefaultStatusAccount:
|
||||||
|
icon = "wallet"
|
||||||
|
item.addAccount(a.name, a.path, a.address, a.emoji, a.color, icon, balance = 0.0)
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
method setKeyPairStoredOnKeycard*[T](self: Module[T], cardMetadata: CardMetadata) =
|
||||||
|
var item = initKeyPairItem(pubKey = "",
|
||||||
|
name = cardMetadata.name,
|
||||||
|
image = "",
|
||||||
|
icon = "keycard",
|
||||||
|
pairType = KeyPairType.Unknown,
|
||||||
|
derivedFrom = "")
|
||||||
|
var knownKeyPair = true
|
||||||
|
for wa in cardMetadata.walletAccounts:
|
||||||
|
if self.updateKeyPairItemIfDataAreKnown(wa.address, item):
|
||||||
|
continue
|
||||||
|
let balance = self.controller.getBalanceForAddress(wa.address)
|
||||||
|
knownKeyPair = false
|
||||||
|
item.addAccount(name = "", wa.path, wa.address, emoji = "", color = self.generateRandomColor(), icon = "wallet", balance)
|
||||||
|
self.view.setKeyPairStoredOnKeycardIsKnown(knownKeyPair)
|
||||||
|
self.view.setKeyPairStoredOnKeycard(item)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import NimQml
|
import NimQml
|
||||||
import io_interface
|
import io_interface
|
||||||
import internal/[state, state_wrapper]
|
import internal/[state, state_wrapper]
|
||||||
|
import models/[key_pair_model, key_pair_item, key_pair_selected_item]
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -8,11 +9,30 @@ QtObject:
|
||||||
delegate: io_interface.AccessInterface
|
delegate: io_interface.AccessInterface
|
||||||
currentState: StateWrapper
|
currentState: StateWrapper
|
||||||
currentStateVariant: QVariant
|
currentStateVariant: QVariant
|
||||||
|
keyPairModel: KeyPairModel
|
||||||
|
keyPairModelVariant: QVariant
|
||||||
|
selectedKeyPairItem: KeyPairSelectedItem
|
||||||
|
selectedKeyPairItemVariant: QVariant
|
||||||
|
keyPairStoredOnKeycardIsKnown: bool
|
||||||
|
keyPairStoredOnKeycard: KeyPairSelectedItem
|
||||||
|
keyPairStoredOnKeycardVariant: QVariant
|
||||||
keycardData: string # used to temporary store the data coming from keycard, depends on current state different data may be stored
|
keycardData: string # used to temporary store the data coming from keycard, depends on current state different data may be stored
|
||||||
|
|
||||||
proc delete*(self: View) =
|
proc delete*(self: View) =
|
||||||
self.currentStateVariant.delete
|
self.currentStateVariant.delete
|
||||||
self.currentState.delete
|
self.currentState.delete
|
||||||
|
if not self.keyPairModel.isNil:
|
||||||
|
self.keyPairModel.delete
|
||||||
|
if not self.keyPairModelVariant.isNil:
|
||||||
|
self.keyPairModelVariant.delete
|
||||||
|
if not self.selectedKeyPairItem.isNil:
|
||||||
|
self.selectedKeyPairItem.delete
|
||||||
|
if not self.selectedKeyPairItemVariant.isNil:
|
||||||
|
self.selectedKeyPairItemVariant.delete
|
||||||
|
if not self.keyPairStoredOnKeycard.isNil:
|
||||||
|
self.keyPairStoredOnKeycard.delete
|
||||||
|
if not self.keyPairStoredOnKeycardVariant.isNil:
|
||||||
|
self.keyPairStoredOnKeycardVariant.delete
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||||
|
@ -25,6 +45,7 @@ QtObject:
|
||||||
signalConnect(result.currentState, "backActionClicked()", result, "onBackActionClicked()", 2)
|
signalConnect(result.currentState, "backActionClicked()", result, "onBackActionClicked()", 2)
|
||||||
signalConnect(result.currentState, "primaryActionClicked()", result, "onPrimaryActionClicked()", 2)
|
signalConnect(result.currentState, "primaryActionClicked()", result, "onPrimaryActionClicked()", 2)
|
||||||
signalConnect(result.currentState, "secondaryActionClicked()", result, "onSecondaryActionClicked()", 2)
|
signalConnect(result.currentState, "secondaryActionClicked()", result, "onSecondaryActionClicked()", 2)
|
||||||
|
signalConnect(result.currentState, "tertiaryActionClicked()", result, "onTertiaryActionClicked()", 2)
|
||||||
|
|
||||||
proc currentStateObj*(self: View): State =
|
proc currentStateObj*(self: View): State =
|
||||||
return self.currentState.getStateObj()
|
return self.currentState.getStateObj()
|
||||||
|
@ -57,5 +78,84 @@ QtObject:
|
||||||
proc onSecondaryActionClicked*(self: View) {.slot.} =
|
proc onSecondaryActionClicked*(self: View) {.slot.} =
|
||||||
self.delegate.onSecondaryActionClicked()
|
self.delegate.onSecondaryActionClicked()
|
||||||
|
|
||||||
proc runFactoryResetFlow*(self: View) {.slot.} =
|
proc onTertiaryActionClicked*(self: View) {.slot.} =
|
||||||
self.delegate.runFactoryResetFlow()
|
self.delegate.onTertiaryActionClicked()
|
||||||
|
|
||||||
|
proc keyPairModel*(self: View): KeyPairModel =
|
||||||
|
return self.keyPairModel
|
||||||
|
|
||||||
|
proc keyPairModelChanged(self: View) {.signal.}
|
||||||
|
proc getKeyPairModel(self: View): QVariant {.slot.} =
|
||||||
|
return self.keyPairModelVariant
|
||||||
|
QtProperty[QVariant] keyPairModel:
|
||||||
|
read = getKeyPairModel
|
||||||
|
notify = keyPairModelChanged
|
||||||
|
|
||||||
|
proc createKeyPairModel*(self: View, items: seq[KeyPairItem]) =
|
||||||
|
if self.keyPairModel.isNil:
|
||||||
|
self.keyPairModel = newKeyPairModel()
|
||||||
|
if self.keyPairModelVariant.isNil:
|
||||||
|
self.keyPairModelVariant = newQVariant(self.keyPairModel)
|
||||||
|
if self.selectedKeyPairItem.isNil:
|
||||||
|
self.selectedKeyPairItem = newKeyPairSelectedItem()
|
||||||
|
if self.selectedKeyPairItemVariant.isNil:
|
||||||
|
self.selectedKeyPairItemVariant = newQVariant(self.selectedKeyPairItem)
|
||||||
|
if self.keyPairStoredOnKeycard.isNil:
|
||||||
|
self.keyPairStoredOnKeycard = newKeyPairSelectedItem()
|
||||||
|
if self.keyPairStoredOnKeycardVariant.isNil:
|
||||||
|
self.keyPairStoredOnKeycardVariant = newQVariant(self.keyPairStoredOnKeycard)
|
||||||
|
self.keyPairModel.setItems(items)
|
||||||
|
self.keyPairModelChanged()
|
||||||
|
|
||||||
|
proc getSelectedKeyPairItem*(self: View): QVariant {.slot.} =
|
||||||
|
return self.selectedKeyPairItemVariant
|
||||||
|
QtProperty[QVariant] selectedKeyPairItem:
|
||||||
|
read = getSelectedKeyPairItem
|
||||||
|
proc setSelectedKeyPairByTheAddressItIsDerivedFrom*(self: View, address: string) {.slot.} =
|
||||||
|
let item = self.keyPairModel.findItemByDerivedFromAddress(address)
|
||||||
|
self.delegate.setSelectedKeyPair(item)
|
||||||
|
self.selectedKeyPairItem.setItem(item)
|
||||||
|
|
||||||
|
proc getKeyPairStoredOnKeycardIsKnown*(self: View): bool {.slot.} =
|
||||||
|
return self.keyPairStoredOnKeycardIsKnown
|
||||||
|
QtProperty[bool] keyPairStoredOnKeycardIsKnown:
|
||||||
|
read = getKeyPairStoredOnKeycardIsKnown
|
||||||
|
proc setKeyPairStoredOnKeycardIsKnown*(self: View, value: bool) =
|
||||||
|
self.keyPairStoredOnKeycardIsKnown = value
|
||||||
|
|
||||||
|
proc getKeyPairStoredOnKeycard*(self: View): QVariant {.slot.} =
|
||||||
|
return self.keyPairStoredOnKeycardVariant
|
||||||
|
QtProperty[QVariant] keyPairStoredOnKeycard:
|
||||||
|
read = getKeyPairStoredOnKeycard
|
||||||
|
proc setKeyPairStoredOnKeycard*(self: View, item: KeyPairItem) =
|
||||||
|
self.keyPairStoredOnKeycard.setItem(item)
|
||||||
|
|
||||||
|
proc setPin*(self: View, value: string) {.slot.} =
|
||||||
|
self.delegate.setPin(value)
|
||||||
|
|
||||||
|
proc setPassword*(self: View, value: string) {.slot.} =
|
||||||
|
self.delegate.setPassword(value)
|
||||||
|
|
||||||
|
proc checkRepeatedKeycardPinWhileTyping*(self: View, pin: string): bool {.slot.} =
|
||||||
|
return self.delegate.checkRepeatedKeycardPinWhileTyping(pin)
|
||||||
|
|
||||||
|
proc getMnemonic*(self: View): string {.slot.} =
|
||||||
|
return self.delegate.getMnemonic()
|
||||||
|
|
||||||
|
proc setSeedPhrase*(self: View, value: string) {.slot.} =
|
||||||
|
self.delegate.setSeedPhrase(value)
|
||||||
|
|
||||||
|
proc getSeedPhrase*(self: View): string {.slot.} =
|
||||||
|
return self.delegate.getSeedPhrase()
|
||||||
|
|
||||||
|
proc validSeedPhrase*(self: View, value: string): bool {.slot.} =
|
||||||
|
return self.delegate.validSeedPhrase(value)
|
||||||
|
|
||||||
|
proc loggedInUserUsesBiometricLogin*(self: View): bool {.slot.} =
|
||||||
|
return self.delegate.loggedInUserUsesBiometricLogin()
|
||||||
|
|
||||||
|
proc migratingProfileKeyPair*(self: View): bool {.slot.} =
|
||||||
|
return self.delegate.migratingProfileKeyPair()
|
||||||
|
|
||||||
|
proc isProfileKeyPairMigrated*(self: View): bool {.slot.} =
|
||||||
|
return self.delegate.isProfileKeyPairMigrated()
|
|
@ -2,6 +2,12 @@ import tables, json, sequtils, sugar, strutils
|
||||||
|
|
||||||
include ../../common/json_utils
|
include ../../common/json_utils
|
||||||
|
|
||||||
|
const WalletTypeDefaultStatusAccount* = ""
|
||||||
|
const WalletTypeGenerated* = "generated"
|
||||||
|
const WalletTypeSeed* = "seed"
|
||||||
|
const WalletTypeWatch* = "watch"
|
||||||
|
const WalletTypeKey* = "key"
|
||||||
|
|
||||||
type BalanceDto* = object
|
type BalanceDto* = object
|
||||||
balance*: float64
|
balance*: float64
|
||||||
currencyBalance*: float64
|
currencyBalance*: float64
|
||||||
|
|
|
@ -253,8 +253,8 @@ StatusSectionLayout {
|
||||||
implicitWidth: parent.width
|
implicitWidth: parent.width
|
||||||
implicitHeight: parent.height
|
implicitHeight: parent.height
|
||||||
|
|
||||||
keycardStore: profileView.store.keycardStore
|
keycardStore: root.store.keycardStore
|
||||||
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.keycard)
|
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.keycard)
|
||||||
contentWidth: d.contentWidth
|
contentWidth: d.contentWidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,7 @@ QtObject {
|
||||||
|
|
||||||
property var keycardModule
|
property var keycardModule
|
||||||
|
|
||||||
|
function runSetupKeycardPopup() {
|
||||||
|
root.keycardModule.runSetupKeycardPopup()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,12 @@ import utils 1.0
|
||||||
import shared.panels 1.0
|
import shared.panels 1.0
|
||||||
import shared.controls 1.0
|
import shared.controls 1.0
|
||||||
import shared.status 1.0
|
import shared.status 1.0
|
||||||
|
import shared.popups.keycard 1.0
|
||||||
|
|
||||||
import "../stores"
|
import "../stores"
|
||||||
import "../controls"
|
import "../controls"
|
||||||
import "../panels"
|
import "../panels"
|
||||||
|
import "../popups"
|
||||||
|
|
||||||
SettingsContentBase {
|
SettingsContentBase {
|
||||||
id: root
|
id: root
|
||||||
|
@ -33,6 +35,29 @@ SettingsContentBase {
|
||||||
id: contentColumn
|
id: contentColumn
|
||||||
spacing: Constants.settingsSection.itemSpacing
|
spacing: Constants.settingsSection.itemSpacing
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.keycardStore.keycardModule
|
||||||
|
|
||||||
|
onDisplayKeycardSharedModuleFlow: {
|
||||||
|
keycardPopup.active = true
|
||||||
|
}
|
||||||
|
onDestroyKeycardSharedModuleFlow: {
|
||||||
|
keycardPopup.active = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: keycardPopup
|
||||||
|
active: false
|
||||||
|
sourceComponent: KeycardPopup {
|
||||||
|
sharedKeycardModule: root.keycardStore.keycardModule.keycardSharedModule
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
keycardPopup.item.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
Layout.preferredHeight: sourceSize.height
|
Layout.preferredHeight: sourceSize.height
|
||||||
|
@ -70,8 +95,8 @@ SettingsContentBase {
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
sensor.onClicked: {
|
onClicked: {
|
||||||
console.warn("TODO: Run Set up Keycard flow...")
|
root.keycardStore.runSetupKeycardPopup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +117,7 @@ SettingsContentBase {
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
sensor.onClicked: {
|
onClicked: {
|
||||||
console.warn("TODO: Generate a seed phrase...")
|
console.warn("TODO: Generate a seed phrase...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +132,7 @@ SettingsContentBase {
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
sensor.onClicked: {
|
onClicked: {
|
||||||
console.warn("TODO: Import or restore via a seed phrase...")
|
console.warn("TODO: Import or restore via a seed phrase...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +147,7 @@ SettingsContentBase {
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
sensor.onClicked: {
|
onClicked: {
|
||||||
console.warn("TODO: Import from Keycard to Status Desktop...")
|
console.warn("TODO: Import from Keycard to Status Desktop...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +169,7 @@ SettingsContentBase {
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
sensor.onClicked: {
|
onClicked: {
|
||||||
console.warn("TODO: Check what’s on a Keycard...")
|
console.warn("TODO: Check what’s on a Keycard...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +184,7 @@ SettingsContentBase {
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
sensor.onClicked: {
|
onClicked: {
|
||||||
console.warn("TODO: Factory reset a Keycard...")
|
console.warn("TODO: Factory reset a Keycard...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,30 +15,91 @@ StatusModal {
|
||||||
|
|
||||||
property var sharedKeycardModule
|
property var sharedKeycardModule
|
||||||
|
|
||||||
width: 640
|
width: Constants.keycard.general.popupWidth
|
||||||
height: 640
|
height: {
|
||||||
margins: 8
|
if (!root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return Constants.keycard.general.popupBiggerHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return Constants.keycard.general.popupBiggerHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Constants.keycard.general.popupHeight
|
||||||
|
}
|
||||||
|
margins: Style.current.halfPadding
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
closePolicy: d.resetInProgress? Popup.NoAutoClose : Popup.CloseOnEscape
|
closePolicy: d.disablePopupClose? Popup.NoAutoClose : Popup.CloseOnEscape
|
||||||
|
|
||||||
header.title: qsTr("Factory reset a Keycard")
|
header.title: {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
return qsTr("Set up a new Keycard with an existing account")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
return qsTr("Factory reset a Keycard")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
property bool factoryResetConfirmed: false
|
property bool primaryButtonEnabled: false
|
||||||
property bool resetInProgress: d.factoryResetConfirmed && root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard
|
property bool seedPhraseRevealed: false
|
||||||
|
property bool disablePopupClose: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess &&
|
||||||
|
root.sharedKeycardModule.migratingProfileKeyPair())
|
||||||
|
|
||||||
onResetInProgressChanged: {
|
onDisablePopupCloseChanged: {
|
||||||
hasCloseButton = !resetInProgress
|
hasCloseButton = !disablePopupClose
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosed: {
|
onClosed: {
|
||||||
// for all states but the `factoryResetConfirmation` cancel the flow is primary action
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair ||
|
||||||
{
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardNotEmpty ||
|
||||||
root.sharedKeycardModule.currentState.doSecondaryAction()
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
return
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseEnterWords ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongSeedPhrase)
|
||||||
|
{
|
||||||
|
root.sharedKeycardModule.currentState.doSecondaryAction()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||||
|
{
|
||||||
|
root.sharedKeycardModule.currentState.doSecondaryAction()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
root.sharedKeycardModule.currentState.doPrimaryAction()
|
root.sharedKeycardModule.currentState.doPrimaryAction()
|
||||||
}
|
}
|
||||||
|
@ -50,19 +111,53 @@ StatusModal {
|
||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard ||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess ||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty ||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardNotEmpty ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard)
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay)
|
||||||
{
|
{
|
||||||
return initComponent
|
return initComponent
|
||||||
}
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata)
|
||||||
{
|
{
|
||||||
return confirmationComponent
|
return confirmationComponent
|
||||||
}
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair)
|
||||||
|
{
|
||||||
|
return selectKeyPairComponent
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified)
|
||||||
|
{
|
||||||
|
return keycardPinComponent
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongSeedPhrase)
|
||||||
|
{
|
||||||
|
return enterSeedPhraseComponent
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseDisplay)
|
||||||
|
{
|
||||||
|
return seedPhraseComponent
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseEnterWords)
|
||||||
|
{
|
||||||
|
return enterSeedPhraseWordsComponent
|
||||||
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -80,8 +175,72 @@ StatusModal {
|
||||||
KeycardConfirmation {
|
KeycardConfirmation {
|
||||||
sharedKeycardModule: root.sharedKeycardModule
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
d.primaryButtonEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
onConfirmationUpdated: {
|
onConfirmationUpdated: {
|
||||||
d.factoryResetConfirmed = value
|
d.primaryButtonEnabled = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: selectKeyPairComponent
|
||||||
|
SelectKeyPair {
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: keycardPinComponent
|
||||||
|
KeycardPin {
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: enterSeedPhraseComponent
|
||||||
|
EnterSeedPhrase {
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
d.primaryButtonEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onValidation: {
|
||||||
|
d.primaryButtonEnabled = result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: seedPhraseComponent
|
||||||
|
SeedPhrase {
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
hideSeed = !d.seedPhraseRevealed
|
||||||
|
d.primaryButtonEnabled = Qt.binding(function(){ return d.seedPhraseRevealed })
|
||||||
|
}
|
||||||
|
|
||||||
|
onSeedPhraseRevealed: {
|
||||||
|
d.seedPhraseRevealed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: enterSeedPhraseWordsComponent
|
||||||
|
EnterSeedPhraseWords {
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
d.primaryButtonEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onValidation: {
|
||||||
|
d.primaryButtonEnabled = result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +250,8 @@ StatusModal {
|
||||||
StatusBackButton {
|
StatusBackButton {
|
||||||
id: backButton
|
id: backButton
|
||||||
visible: root.sharedKeycardModule.currentState.displayBackButton
|
visible: root.sharedKeycardModule.currentState.displayBackButton
|
||||||
|
height: primaryButton.height
|
||||||
|
width: primaryButton.height
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.sharedKeycardModule.currentState.backAction()
|
root.sharedKeycardModule.currentState.backAction()
|
||||||
}
|
}
|
||||||
|
@ -101,13 +262,62 @@ StatusModal {
|
||||||
StatusButton {
|
StatusButton {
|
||||||
id: secondaryButton
|
id: secondaryButton
|
||||||
text: {
|
text: {
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
return qsTr("Cancel")
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardNotEmpty ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
return qsTr("Cancel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||||
|
return qsTr("Cancel")
|
||||||
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
visible: {
|
visible: {
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
return true
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardNotEmpty ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
highlighted: focus
|
highlighted: focus
|
||||||
|
@ -119,20 +329,130 @@ StatusModal {
|
||||||
StatusButton {
|
StatusButton {
|
||||||
id: primaryButton
|
id: primaryButton
|
||||||
text: {
|
text: {
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
return qsTr("Factory reset this Keycard")
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
|
||||||
if (d.resetInProgress ||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess)
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard ||
|
||||||
return qsTr("Done")
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||||
return qsTr("Cancel")
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet) {
|
||||||
|
return qsTr("Input seed phrase")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseEnterWords) {
|
||||||
|
return qsTr("Yes, migrate key pair to this Keycard")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase) {
|
||||||
|
return qsTr("Yes, migrate key pair to Keycard")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongSeedPhrase) {
|
||||||
|
return qsTr("Try entering seed phrase again")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardNotEmpty) {
|
||||||
|
return qsTr("Check what is stored on this Keycard")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin) {
|
||||||
|
return qsTr("I don’t know the pin")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return qsTr("Factory reset this Keycard")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
return qsTr("Next")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached) {
|
||||||
|
return qsTr("Tmp-Next")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure) {
|
||||||
|
return qsTr("Done")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess &&
|
||||||
|
root.sharedKeycardModule.migratingProfileKeyPair()) {
|
||||||
|
return qsTr("Restart app & sign in using your new Keycard")
|
||||||
|
}
|
||||||
|
return qsTr("Cancel")
|
||||||
|
}
|
||||||
|
else if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin) {
|
||||||
|
return qsTr("I don’t know the pin")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return qsTr("Factory reset this Keycard")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata) {
|
||||||
|
return qsTr("Next")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached) {
|
||||||
|
return qsTr("Tmp-Next")
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess) {
|
||||||
|
return qsTr("Done")
|
||||||
|
}
|
||||||
|
return qsTr("Cancel")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
enabled: {
|
enabled: {
|
||||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||||
return d.factoryResetConfirmed
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair) {
|
||||||
if (d.resetInProgress)
|
if (d.disablePopupClose) {
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseDisplay ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseEnterWords ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase) {
|
||||||
|
return d.primaryButtonEnabled
|
||||||
|
}
|
||||||
|
if ((root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.selectExistingKeyPair &&
|
||||||
|
root.sharedKeycardModule.keyPairModel.count === 0) ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return d.primaryButtonEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
icon.name: {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseEnterWords ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase) {
|
||||||
|
if (root.sharedKeycardModule.migratingProfileKeyPair()) {
|
||||||
|
if (root.sharedKeycardModule.loggedInUserUsesBiometricLogin())
|
||||||
|
return "touch-id"
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
highlighted: focus
|
highlighted: focus
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQml.Models 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
StatusListItem {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
property ButtonGroup buttonGroup
|
||||||
|
property bool usedAsSelectOption: false
|
||||||
|
|
||||||
|
property string keyPairPubKey: ""
|
||||||
|
property string keyPairName: ""
|
||||||
|
property string keyPairIcon: ""
|
||||||
|
property string keyPairImage: ""
|
||||||
|
property string keyPairDerivedFrom: ""
|
||||||
|
property string keyPairAccounts: ""
|
||||||
|
|
||||||
|
color: Style.current.grey
|
||||||
|
title: root.keyPairName
|
||||||
|
titleAsideText: Utils.getElidedCompressedPk(root.keyPairPubKey)
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 40
|
||||||
|
height: 40
|
||||||
|
source: root.keyPairImage
|
||||||
|
}
|
||||||
|
|
||||||
|
icon {
|
||||||
|
width: root.keyPairIcon? 24 : 40
|
||||||
|
height: root.keyPairIcon? 24 : 40
|
||||||
|
name: root.keyPairIcon
|
||||||
|
color: Utils.colorForPubkey(root.keyPairPubKey)
|
||||||
|
letterSize: Math.max(4, this.image.width / 2.4)
|
||||||
|
charactersLen: 2
|
||||||
|
isLetterIdenticon: !root.keyPairIcon && !this.image.source.toString()
|
||||||
|
background.color: Theme.palette.primaryColor3
|
||||||
|
}
|
||||||
|
|
||||||
|
ringSettings {
|
||||||
|
ringSpecModel: Utils.getColorHashAsJson(root.keyPairPubKey)
|
||||||
|
ringPxSize: Math.max(this.icon.width / 24.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
tagsModel: ListModel{}
|
||||||
|
|
||||||
|
tagsDelegate: StatusListItemTag {
|
||||||
|
color: model.color
|
||||||
|
height: Style.current.bigPadding
|
||||||
|
radius: 6
|
||||||
|
closeButtonVisible: false
|
||||||
|
icon {
|
||||||
|
emoji: model.emoji
|
||||||
|
emojiSize: Emoji.size.verySmall
|
||||||
|
isLetterIdenticon: !!model.emoji
|
||||||
|
name: model.icon
|
||||||
|
color: Theme.palette.indirectColor1
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
}
|
||||||
|
title: model.name
|
||||||
|
titleText.font.pixelSize: 12
|
||||||
|
titleText.color: Theme.palette.indirectColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
components: [
|
||||||
|
StatusRadioButton {
|
||||||
|
visible: root.usedAsSelectOption
|
||||||
|
ButtonGroup.group: root.buttonGroup
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (!root.usedAsSelectOption)
|
||||||
|
return
|
||||||
|
let checkCondition = root.sharedKeycardModule.selectedKeyPairItem.derivedFrom === root.keyPairDerivedFrom
|
||||||
|
if (checked && checked != checkCondition) {
|
||||||
|
root.sharedKeycardModule.setSelectedKeyPairByTheAddressItIsDerivedFrom(root.keyPairDerivedFrom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (!root.usedAsSelectOption)
|
||||||
|
return
|
||||||
|
checked = Qt.binding(function() {
|
||||||
|
return root.sharedKeycardModule.selectedKeyPairItem.derivedFrom === root.keyPairDerivedFrom
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (root.keyPairAccounts === "") {
|
||||||
|
// should never be here, as it's not possible to have keypair item without at least a single account
|
||||||
|
console.debug("accounts list is empty for selecting keycard pair")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let obj = JSON.parse(root.keyPairAccounts)
|
||||||
|
if (obj.error) {
|
||||||
|
console.debug("error parsing accounts for selecting keycard pair, error: ", obj.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i=0; i<obj.length; i++) {
|
||||||
|
this.tagsModel.append({"name": obj[i].Field0, "color": obj[i].Field4, "emoji": obj[i].Field3, "icon": obj[i].Field5})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (!root.usedAsSelectOption)
|
||||||
|
return
|
||||||
|
root.sharedKeycardModule.setSelectedKeyPairByTheAddressItIsDerivedFrom(root.keyPairDerivedFrom)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQml.Models 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
property bool filterProfilePair: false
|
||||||
|
property var keyPairModel
|
||||||
|
property ButtonGroup buttonGroup
|
||||||
|
|
||||||
|
DelegateModel {
|
||||||
|
id: delegateModel
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var visible = [];
|
||||||
|
for (var i = 0; i < items.count; ++i) {
|
||||||
|
var item = items.get(i);
|
||||||
|
if(root.filterProfilePair) {
|
||||||
|
if (item.model.pairType === Constants.keycard.keyPairType.profile)
|
||||||
|
visible.push(item);
|
||||||
|
}
|
||||||
|
else if (item.model.pairType !== Constants.keycard.keyPairType.profile) {
|
||||||
|
visible.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < visible.length; ++i) {
|
||||||
|
item = visible[i];
|
||||||
|
item.inPairType = true;
|
||||||
|
if (item.pairTypeIndex !== i) {
|
||||||
|
visibleItems.move(item.pairTypeIndex, i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: root.keyPairModel
|
||||||
|
|
||||||
|
groups: [DelegateModelGroup {
|
||||||
|
id: visibleItems
|
||||||
|
name: "pairType"
|
||||||
|
includeByDefault: false
|
||||||
|
}]
|
||||||
|
|
||||||
|
filterOnGroup: "pairType"
|
||||||
|
items.onChanged: update()
|
||||||
|
delegate: KeyPairItem {
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
buttonGroup: root.buttonGroup
|
||||||
|
usedAsSelectOption: true
|
||||||
|
|
||||||
|
keyPairPubKey: model.pubKey
|
||||||
|
keyPairName: model.name
|
||||||
|
keyPairIcon: model.icon
|
||||||
|
keyPairImage: model.image
|
||||||
|
keyPairDerivedFrom: model.derivedFrom
|
||||||
|
keyPairAccounts: model.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
model: delegateModel
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
import QtQml.Models 2.14
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
import shared.stores 1.0 as SharedStore
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string keyPairPubKey: ""
|
||||||
|
property string keyPairName: ""
|
||||||
|
property string keyPairIcon: ""
|
||||||
|
property string keyPairImage: ""
|
||||||
|
property string keyPairDerivedFrom: ""
|
||||||
|
property string keyPairAccounts: ""
|
||||||
|
|
||||||
|
color: Style.current.grey
|
||||||
|
radius: Style.current.halfPadding
|
||||||
|
clip: true
|
||||||
|
implicitWidth: 448
|
||||||
|
implicitHeight: 198
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (root.keyPairAccounts === "") {
|
||||||
|
// should never be here, as it's not possible to have keypair item without at least a single account
|
||||||
|
console.debug("accounts list is empty for selecting keycard pair")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let obj = JSON.parse(root.keyPairAccounts)
|
||||||
|
if (obj.error) {
|
||||||
|
console.debug("error parsing accounts for selecting keycard pair, error: ", obj.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i=0; i<obj.length; i++) {
|
||||||
|
accountsListModel.append({"path": obj[i].Field1, "address": obj[i].Field2, "balance": obj[i].Field6})
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts.model = accountsListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: accountsListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: Style.current.halfPadding
|
||||||
|
|
||||||
|
StatusListItem {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
color: "transparent"
|
||||||
|
title: root.keyPairName
|
||||||
|
|
||||||
|
icon {
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
name: root.keyPairIcon
|
||||||
|
color: Utils.colorForPubkey(root.keyPairPubKey)
|
||||||
|
letterSize: Math.max(4, this.image.width / 2.4)
|
||||||
|
charactersLen: 2
|
||||||
|
isLetterIdenticon: false
|
||||||
|
background.color: Theme.palette.primaryColor3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 1
|
||||||
|
color: Style.current.grey3
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.preferredWidth: parent.width - 2 * Style.current.padding
|
||||||
|
Layout.leftMargin: Style.current.padding
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
text: qsTr("Active Accounts")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: accounts
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.bottomMargin: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
spacing: Style.current.halfPadding * 0.5
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: parent.width - 2 * Style.current.padding
|
||||||
|
height: Style.current.xlPadding * 2
|
||||||
|
color: Theme.palette.statusModal.backgroundColor
|
||||||
|
radius: Style.current.halfPadding
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: Style.current.padding
|
||||||
|
anchors.rightMargin: Style.current.padding
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Row {
|
||||||
|
spacing: 0
|
||||||
|
padding: 0
|
||||||
|
StatusBaseText {
|
||||||
|
id: address
|
||||||
|
text: StatusQUtils.Utils.elideText(model.address, 6, 4)
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusFlatRoundButton {
|
||||||
|
height: 20
|
||||||
|
width: 20
|
||||||
|
icon.name: "external"
|
||||||
|
icon.width: 16
|
||||||
|
icon.height: 16
|
||||||
|
onClicked: {
|
||||||
|
Qt.openUrlExternally("https://etherscan.io/address/%1".arg(model.address))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
text: model.path
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: parent.height
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
text: {
|
||||||
|
if (Global.appMain) {
|
||||||
|
return "%1%2".arg(SharedStore.RootStore.currencyStore.currentCurrencySymbol)
|
||||||
|
.arg(Utils.toLocaleString(model.balance.toFixed(2), appSettings.locale, {"model.currency": true}))
|
||||||
|
}
|
||||||
|
// without language/model refactor no way to read currency symbol or `appSettings.locale` before user logs in
|
||||||
|
return "$%1".arg(Utils.toLocaleString(model.balance.toFixed(2), localAppSettings.language, {"model.currency": true}))
|
||||||
|
}
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property url source: ""
|
||||||
|
property string pattern: ""
|
||||||
|
property int startImgIndexForTheFirstLoop: 0
|
||||||
|
property int startImgIndexForOtherLoops: 0
|
||||||
|
property int endImgIndex: 0
|
||||||
|
property int duration: 0
|
||||||
|
property int loops: -1 // infinite
|
||||||
|
|
||||||
|
signal animationCompleted()
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property int currentLoop: 1
|
||||||
|
property bool isAnimation: false
|
||||||
|
|
||||||
|
function restart() {
|
||||||
|
d.currentLoop = 1
|
||||||
|
animation.from = root.startImgIndexForTheFirstLoop
|
||||||
|
animation.to = root.endImgIndex
|
||||||
|
animation.duration = root.duration
|
||||||
|
img.currentImgIndex = root.startImgIndexForTheFirstLoop
|
||||||
|
if (d.isAnimation)
|
||||||
|
animation.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPatternChanged: {
|
||||||
|
d.isAnimation = root.duration > 0 && root.pattern !== ""
|
||||||
|
d.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
onStartImgIndexForTheFirstLoopChanged: {
|
||||||
|
d.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
onEndImgIndexChanged: {
|
||||||
|
d.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
onDurationChanged: {
|
||||||
|
d.isAnimation = root.duration > 0 && root.pattern !== ""
|
||||||
|
d.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
anchors.fill: parent
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
antialiasing: true
|
||||||
|
mipmap: true
|
||||||
|
source: d.isAnimation?
|
||||||
|
Style.png(root.pattern.arg(img.currentImgIndex)) :
|
||||||
|
root.source
|
||||||
|
|
||||||
|
property int currentImgIndex: root.startImgIndexForTheFirstLoop
|
||||||
|
|
||||||
|
onCurrentImgIndexChanged: {
|
||||||
|
if (currentImgIndex == root.endImgIndex) {
|
||||||
|
|
||||||
|
if (d.currentLoop === root.loops && root.loops > -1) {
|
||||||
|
animation.stop()
|
||||||
|
root.animationCompleted()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (d.currentLoop === 1 && (root.loops === -1 || root.loops > 1)) {
|
||||||
|
animation.stop()
|
||||||
|
animation.duration = root.duration / (root.endImgIndex + 1) * (root.endImgIndex - root.startImgIndexForOtherLoops)
|
||||||
|
animation.from = root.startImgIndexForOtherLoops
|
||||||
|
animation.to = root.endImgIndex
|
||||||
|
animation.loops = root.loops == -1? Animation.Infinite : root.loops
|
||||||
|
animation.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
d.currentLoop += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation on currentImgIndex {
|
||||||
|
id: animation
|
||||||
|
from: root.startImgIndexForTheFirstLoop
|
||||||
|
to: root.endImgIndex
|
||||||
|
duration: root.duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,328 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
import StatusQ.Controls.Validators 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
import shared.stores 1.0
|
||||||
|
import shared.controls 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
|
||||||
|
signal validation(bool result)
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property bool allEntriesValid: false
|
||||||
|
property var mnemonicInput: []
|
||||||
|
readonly property var tabs: [12, 18, 24]
|
||||||
|
readonly property ListModel seedPhrases_en: BIP39_en {}
|
||||||
|
property bool wrongSeedPhrase: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.wrongSeedPhrase
|
||||||
|
|
||||||
|
onWrongSeedPhraseChanged: {
|
||||||
|
if (wrongSeedPhrase) {
|
||||||
|
invalidSeedTxt.text = qsTr("The phrase you’ve entered does not match this Keycard’s seed phrase")
|
||||||
|
invalidSeedTxt.visible = true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
invalidSeedTxt.text = ""
|
||||||
|
invalidSeedTxt.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAllEntriesValidChanged: {
|
||||||
|
if (d.allEntriesValid) {
|
||||||
|
let mnemonicString = ""
|
||||||
|
const sortTable = mnemonicInput.sort((a, b) => a.pos - b.pos)
|
||||||
|
for (let i = 0; i < mnemonicInput.length; i++) {
|
||||||
|
d.checkWordExistence(sortTable[i].seed)
|
||||||
|
mnemonicString += sortTable[i].seed + ((i === (grid.count-1)) ? "" : " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isMnemonic(mnemonicString) && root.sharedKeycardModule.validSeedPhrase(mnemonicString)) {
|
||||||
|
root.sharedKeycardModule.setSeedPhrase(mnemonicString)
|
||||||
|
} else {
|
||||||
|
invalidSeedTxt.text = qsTr("Invalid seed phrase")
|
||||||
|
invalidSeedTxt.visible = true
|
||||||
|
d.allEntriesValid = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root.validation(d.allEntriesValid)
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMnemonicLength() {
|
||||||
|
d.allEntriesValid = d.mnemonicInput.length === d.tabs[switchTabBar.currentIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkWordExistence(word) {
|
||||||
|
d.allEntriesValid = d.allEntriesValid && d.seedPhrases_en.words.includes(word)
|
||||||
|
if (d.allEntriesValid) {
|
||||||
|
invalidSeedTxt.text = ""
|
||||||
|
invalidSeedTxt.visible = false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
invalidSeedTxt.text = qsTr("The phrase you’ve entered is invalid")
|
||||||
|
invalidSeedTxt.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pasteWords () {
|
||||||
|
const clipboardText = globalUtils.getFromClipboard()
|
||||||
|
// Split words separated by commas and or blank spaces (spaces, enters, tabs)
|
||||||
|
const words = clipboardText.split(/[, \s]+/)
|
||||||
|
|
||||||
|
let index = d.tabs.indexOf(words.length)
|
||||||
|
if (index === -1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeout = 0
|
||||||
|
if (switchTabBar.currentIndex !== index) {
|
||||||
|
switchTabBar.currentIndex = index
|
||||||
|
// Set the teimeout to 100 so the grid has time to generate the new items
|
||||||
|
timeout = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
d.mnemonicInput = []
|
||||||
|
timer.setTimeout(() => {
|
||||||
|
// Populate mnemonicInput
|
||||||
|
for (let i = 0; i < words.length; i++) {
|
||||||
|
grid.addWord(i + 1, words[i], true)
|
||||||
|
}
|
||||||
|
// Populate grid
|
||||||
|
for (let j = 0; j < grid.count; j++) {
|
||||||
|
const item = grid.itemAtIndex(j)
|
||||||
|
if (!item || !item.leftComponentText) {
|
||||||
|
// The grid has gaps in it and also sometimes doesn't return the item correctly when offscreen
|
||||||
|
// in those cases, we just add the word in the array but not in the grid.
|
||||||
|
// The button will still work and import correctly. The Grid itself will be partly empty, but offscreen
|
||||||
|
// With the re-design of the grid, this should be fixed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const pos = item.mnemonicIndex
|
||||||
|
item.setWord(words[pos - 1])
|
||||||
|
}
|
||||||
|
d.checkMnemonicLength()
|
||||||
|
}, timeout)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: title
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Enter key pair seed phrase")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: timer
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusSwitchTabBar {
|
||||||
|
id: switchTabBar
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Repeater {
|
||||||
|
model: d.tabs
|
||||||
|
StatusSwitchTabButton {
|
||||||
|
text: qsTr("%1 words").arg(modelData)
|
||||||
|
id: seedPhraseWords
|
||||||
|
objectName: `${modelData}SeedButton`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
d.mnemonicInput = d.mnemonicInput.filter(function(value) {
|
||||||
|
return value.pos <= d.tabs[switchTabBar.currentIndex]
|
||||||
|
})
|
||||||
|
d.checkMnemonicLength()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusGridView {
|
||||||
|
id: grid
|
||||||
|
readonly property var wordIndex: [
|
||||||
|
["1", "3", "5", "7", "9", "11", "2", "4", "6", "8", "10", "12"]
|
||||||
|
,["1", "4", "7", "10", "13", "16", "2", "5", "8",
|
||||||
|
"11", "14", "17", "3", "6", "9", "12", "15", "18"]
|
||||||
|
,["1", "5", "9", "13", "17", "21", "2", "6", "10", "14", "18", "22",
|
||||||
|
"3", "7", "11", "15", "19", "23", "4", "8", "12", "16", "20", "24"]
|
||||||
|
]
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.preferredHeight: 312
|
||||||
|
clip: false
|
||||||
|
flow: GridView.FlowTopToBottom
|
||||||
|
cellWidth: (parent.width/(count/6))
|
||||||
|
cellHeight: 52
|
||||||
|
interactive: false
|
||||||
|
z: 100000
|
||||||
|
cacheBuffer: 9999
|
||||||
|
model: switchTabBar.currentItem.text.substring(0,2)
|
||||||
|
|
||||||
|
function addWord(pos, word, ignoreGoingNext = false) {
|
||||||
|
d.mnemonicInput.push({pos: pos, seed: word.replace(/\s/g, '')})
|
||||||
|
|
||||||
|
for (let j = 0; j < d.mnemonicInput.length; j++) {
|
||||||
|
if (d.mnemonicInput[j].pos === pos && d.mnemonicInput[j].seed !== word) {
|
||||||
|
d.mnemonicInput[j].seed = word
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//remove duplicates
|
||||||
|
const valueArr = d.mnemonicInput.map(item => item.pos)
|
||||||
|
const isDuplicate = valueArr.some((item, idx) => {
|
||||||
|
if (valueArr.indexOf(item) !== idx) {
|
||||||
|
d.mnemonicInput.splice(idx, 1)
|
||||||
|
}
|
||||||
|
return valueArr.indexOf(item) !== idx
|
||||||
|
})
|
||||||
|
if (!ignoreGoingNext) {
|
||||||
|
for (let i = 0; i < grid.count; i++) {
|
||||||
|
if (grid.itemAtIndex(i).mnemonicIndex !== (pos + 1)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.currentIndex = grid.itemAtIndex(i).itemIndex
|
||||||
|
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus()
|
||||||
|
|
||||||
|
if (grid.currentIndex !== 12) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.positionViewAtEnd()
|
||||||
|
|
||||||
|
if (grid.count === 20) {
|
||||||
|
grid.contentX = 1500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.checkMnemonicLength()
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: StatusSeedPhraseInput {
|
||||||
|
id: seedWordInput
|
||||||
|
textEdit.input.edit.objectName: `statusSeedPhraseInputField${seedWordInput.leftComponentText}`
|
||||||
|
width: (grid.cellWidth - 8)
|
||||||
|
height: (grid.cellHeight - 8)
|
||||||
|
Behavior on width { NumberAnimation { duration: 180 } }
|
||||||
|
textEdit.text: {
|
||||||
|
const pos = seedWordInput.mnemonicIndex
|
||||||
|
for (let i in d.mnemonicInput) {
|
||||||
|
const p = d.mnemonicInput[i]
|
||||||
|
if (p.pos === pos) {
|
||||||
|
return p.seed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property int mnemonicIndex: grid.wordIndex[(grid.count / 6) - 2][index]
|
||||||
|
|
||||||
|
leftComponentText: mnemonicIndex
|
||||||
|
inputList: d.seedPhrases_en
|
||||||
|
|
||||||
|
property int itemIndex: index
|
||||||
|
z: (grid.currentIndex === index) ? 150000000 : 0
|
||||||
|
onTextChanged: {
|
||||||
|
d.checkWordExistence(text)
|
||||||
|
}
|
||||||
|
onDoneInsertingWord: {
|
||||||
|
grid.addWord(mnemonicIndex, word)
|
||||||
|
}
|
||||||
|
onEditClicked: {
|
||||||
|
grid.currentIndex = index
|
||||||
|
grid.itemAtIndex(index).textEdit.input.edit.forceActiveFocus()
|
||||||
|
}
|
||||||
|
onKeyPressed: {
|
||||||
|
grid.currentIndex = index
|
||||||
|
|
||||||
|
if (event.key === Qt.Key_Backtab) {
|
||||||
|
for (let i = 0; i < grid.count; i++) {
|
||||||
|
if (grid.itemAtIndex(i).mnemonicIndex === ((mnemonicIndex - 1) >= 0 ? (mnemonicIndex - 1) : 0)) {
|
||||||
|
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(Qt.BacktabFocusReason)
|
||||||
|
textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit
|
||||||
|
event.accepted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (event.key === Qt.Key_Tab) {
|
||||||
|
for (let i = 0; i < grid.count; i++) {
|
||||||
|
if (grid.itemAtIndex(i).mnemonicIndex === ((mnemonicIndex + 1) <= grid.count ? (mnemonicIndex + 1) : grid.count)) {
|
||||||
|
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit
|
||||||
|
event.accepted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.matches(StandardKey.Paste)) {
|
||||||
|
if (d.pasteWords()) {
|
||||||
|
// Paste was done by splitting the words
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
|
event.accepted = true
|
||||||
|
if (d.allEntriesValid) {
|
||||||
|
d.sharedKeycardModule.currentState.doPrimaryAction()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) {
|
||||||
|
const wordIndex = d.mnemonicInput.findIndex(x => x.pos === mnemonicIndex)
|
||||||
|
if (wordIndex > -1) {
|
||||||
|
d.mnemonicInput.splice(wordIndex, 1)
|
||||||
|
d.checkMnemonicLength()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.onCompleted: {
|
||||||
|
const item = grid.itemAtIndex(0)
|
||||||
|
if (item) {
|
||||||
|
item.textEdit.input.edit.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: invalidSeedTxt
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.enterSeedPhrase
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.wrongSeedPhrase
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongSeedPhrase
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
import StatusQ.Controls.Validators 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
|
||||||
|
signal validation(bool result)
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property bool allEntriesValid: false
|
||||||
|
readonly property var seedPhrase: root.sharedKeycardModule.getMnemonic().split(" ")
|
||||||
|
readonly property var wordNumbers: {
|
||||||
|
let numbers = []
|
||||||
|
while (numbers.length < 3) {
|
||||||
|
let randomNo = Math.floor(Math.random() * 12)
|
||||||
|
if(numbers.indexOf(randomNo) == -1)
|
||||||
|
numbers.push(randomNo)
|
||||||
|
}
|
||||||
|
numbers.sort((a, b) => { return a < b? -1 : a > b? 1 : 0 })
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
function processText(text) {
|
||||||
|
if(text.length === 0)
|
||||||
|
return ""
|
||||||
|
if(/(^\s|^\r|^\n)|(\s$|^\r$|^\n$)/.test(text)) {
|
||||||
|
return text.trim()
|
||||||
|
}
|
||||||
|
else if(/\s|\r|\n/.test(text)) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateValidity() {
|
||||||
|
d.allEntriesValid = word0.valid && word1.valid && word2.valid
|
||||||
|
root.validation(d.allEntriesValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: title
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Confirm seed phrase words")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusInput {
|
||||||
|
id: word0
|
||||||
|
Layout.fillWidth: true
|
||||||
|
validationMode: StatusInput.ValidationMode.Always
|
||||||
|
label: qsTr("Word #%1").arg(d.wordNumbers[0] + 1)
|
||||||
|
placeholderText: qsTr("Enter word")
|
||||||
|
validators: [
|
||||||
|
StatusValidator {
|
||||||
|
validate: function (t) { return (d.seedPhrase[d.wordNumbers[0]] === word0.text); }
|
||||||
|
errorMessage: (word0.text.length) > 0 ? qsTr("This word doesn’t match") : ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
input.acceptReturn: true
|
||||||
|
input.tabNavItem: word1.input.edit
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
text = d.processText(text)
|
||||||
|
d.updateValidity()
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPressed: {
|
||||||
|
if (d.allEntriesValid &&
|
||||||
|
(input.edit.keyEvent === Qt.Key_Return ||
|
||||||
|
input.edit.keyEvent === Qt.Key_Enter)) {
|
||||||
|
event.accepted = true
|
||||||
|
root.sharedKeycardModule.currentState.doPrimaryAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusInput {
|
||||||
|
id: word1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
validationMode: StatusInput.ValidationMode.Always
|
||||||
|
label: qsTr("Word #%1").arg(d.wordNumbers[1] + 1)
|
||||||
|
placeholderText: qsTr("Enter word")
|
||||||
|
validators: [
|
||||||
|
StatusValidator {
|
||||||
|
validate: function (t) { return (d.seedPhrase[d.wordNumbers[1]] === word1.text); }
|
||||||
|
errorMessage: (word1.text.length) > 0 ? qsTr("This word doesn’t match") : ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
input.acceptReturn: true
|
||||||
|
input.tabNavItem: word2.input.edit
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
text = d.processText(text)
|
||||||
|
d.updateValidity()
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPressed: {
|
||||||
|
if (d.allEntriesValid &&
|
||||||
|
(input.edit.keyEvent === Qt.Key_Return ||
|
||||||
|
input.edit.keyEvent === Qt.Key_Enter)) {
|
||||||
|
event.accepted = true
|
||||||
|
root.sharedKeycardModule.currentState.doPrimaryAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusInput {
|
||||||
|
id: word2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
validationMode: StatusInput.ValidationMode.Always
|
||||||
|
label: qsTr("Word #%1").arg(d.wordNumbers[2] + 1)
|
||||||
|
placeholderText: qsTr("Enter word")
|
||||||
|
validators: [
|
||||||
|
StatusValidator {
|
||||||
|
validate: function (t) { return (d.seedPhrase[d.wordNumbers[2]] === word2.text); }
|
||||||
|
errorMessage: (word2.text.length) > 0 ? qsTr("This word doesn’t match") : ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
input.acceptReturn: true
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
text = d.processText(text)
|
||||||
|
d.updateValidity()
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPressed: {
|
||||||
|
if (d.allEntriesValid &&
|
||||||
|
(input.edit.keyEvent === Qt.Key_Return ||
|
||||||
|
input.edit.keyEvent === Qt.Key_Enter)) {
|
||||||
|
event.accepted = true
|
||||||
|
root.sharedKeycardModule.currentState.doPrimaryAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,8 @@ import StatusQ.Controls 0.1
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
|
|
||||||
|
import "../helpers"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -15,42 +17,119 @@ Item {
|
||||||
|
|
||||||
signal confirmationUpdated(bool value)
|
signal confirmationUpdated(bool value)
|
||||||
|
|
||||||
ColumnLayout {
|
Component {
|
||||||
anchors.centerIn: parent
|
id: knownKeyPairComponent
|
||||||
spacing: Style.current.padding
|
KeyPairItem {
|
||||||
|
keyPairPubKey: root.sharedKeycardModule.keyPairStoredOnKeycard.pubKey
|
||||||
|
keyPairName: root.sharedKeycardModule.keyPairStoredOnKeycard.name
|
||||||
|
keyPairIcon: root.sharedKeycardModule.keyPairStoredOnKeycard.icon
|
||||||
|
keyPairImage: root.sharedKeycardModule.keyPairStoredOnKeycard.image
|
||||||
|
keyPairDerivedFrom: root.sharedKeycardModule.keyPairStoredOnKeycard.derivedFrom
|
||||||
|
keyPairAccounts: root.sharedKeycardModule.keyPairStoredOnKeycard.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Image {
|
Component {
|
||||||
|
id: unknownKeyPairCompontnt
|
||||||
|
KeyPairUnknownItem {
|
||||||
|
keyPairPubKey: root.sharedKeycardModule.keyPairStoredOnKeycard.pubKey
|
||||||
|
keyPairName: root.sharedKeycardModule.keyPairStoredOnKeycard.name
|
||||||
|
keyPairIcon: root.sharedKeycardModule.keyPairStoredOnKeycard.icon
|
||||||
|
keyPairImage: root.sharedKeycardModule.keyPairStoredOnKeycard.image
|
||||||
|
keyPairDerivedFrom: root.sharedKeycardModule.keyPairStoredOnKeycard.derivedFrom
|
||||||
|
keyPairAccounts: root.sharedKeycardModule.keyPairStoredOnKeycard.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
KeycardImage {
|
||||||
id: image
|
id: image
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
||||||
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
||||||
fillMode: Image.PreserveAspectFit
|
pattern: "keycard/strong_error/img-%1"
|
||||||
antialiasing: true
|
source: ""
|
||||||
mipmap: true
|
startImgIndexForTheFirstLoop: 0
|
||||||
source: Style.png("keycard/popup_card_red_sprayed@2x")
|
startImgIndexForOtherLoops: 18
|
||||||
|
endImgIndex: 29
|
||||||
|
duration: 1300
|
||||||
|
loops: -1
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
id: title
|
id: title
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("A factory reset will delete the key on this Keycard.\nAre you sure you want to do this?")
|
text: qsTr("A factory reset will delete the key on this Keycard.\nAre you sure you want to do this?")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize3
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
color: Theme.palette.dangerColor1
|
color: Theme.palette.dangerColor1
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusCheckBox {
|
StatusCheckBox {
|
||||||
id: confirmation
|
id: confirmation
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.preferredHeight: Constants.keycard.general.messageHeight
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
leftSide: false
|
leftSide: false
|
||||||
spacing: Style.current.smallPadding
|
spacing: Style.current.smallPadding
|
||||||
font.pixelSize: Constants.keycard.general.fontSize3
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
text: qsTr("I understand the key pair on this Keycard will be deleted")
|
text: qsTr("I understand the key pair on this Keycard will be deleted")
|
||||||
|
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
root.confirmationUpdated(checked)
|
root.confirmationUpdated(checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
active: {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceComponent: {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
if (root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
|
||||||
|
return knownKeyPairComponent
|
||||||
|
}
|
||||||
|
return unknownKeyPairCompontnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmationDisplayMetadata) {
|
||||||
|
if (root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
|
||||||
|
return knownKeyPairComponent
|
||||||
|
}
|
||||||
|
return unknownKeyPairCompontnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
visible: !loader.active
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: visible? true : false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,32 @@ import StatusQ.Core 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
|
|
||||||
|
///////// Remove Later////////////
|
||||||
|
import StatusQ.Popups 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
//////////////////////////////////
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
|
|
||||||
|
import "../helpers"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var sharedKeycardModule
|
property var sharedKeycardModule
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair) {
|
||||||
|
passwordPopup.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property bool hideKeyPair: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.hideKeyPair
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: timer
|
id: timer
|
||||||
interval: 1000
|
interval: 1000
|
||||||
|
@ -22,23 +41,100 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
///////// Remove Later////////////
|
||||||
|
StatusModal {
|
||||||
|
id: passwordPopup
|
||||||
|
width: 300
|
||||||
|
height: 200
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Style.current.padding
|
header.title: qsTr("Temporary Popup")
|
||||||
|
closePolicy: Popup.NoAutoClose
|
||||||
|
contentItem: Item {
|
||||||
|
StatusInput {
|
||||||
|
id: password
|
||||||
|
width: parent.width - Style.current.padding * 2
|
||||||
|
anchors.centerIn: parent
|
||||||
|
input.clearable: true
|
||||||
|
placeholderText: qsTr("Enter password...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rightButtons: [
|
||||||
|
StatusButton {
|
||||||
|
id: primaryButton
|
||||||
|
text: qsTr("Next")
|
||||||
|
onClicked: {
|
||||||
|
root.sharedKeycardModule.setPassword(password.text)
|
||||||
|
passwordPopup.close()
|
||||||
|
root.sharedKeycardModule.currentState.doPrimaryAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
//////////////////////////////////
|
||||||
|
|
||||||
Image {
|
Component {
|
||||||
|
id: keyPairComponent
|
||||||
|
KeyPairItem {
|
||||||
|
keyPairPubKey: root.sharedKeycardModule.selectedKeyPairItem.pubKey
|
||||||
|
keyPairName: root.sharedKeycardModule.selectedKeyPairItem.name
|
||||||
|
keyPairIcon: root.sharedKeycardModule.selectedKeyPairItem.icon
|
||||||
|
keyPairImage: root.sharedKeycardModule.selectedKeyPairItem.image
|
||||||
|
keyPairDerivedFrom: root.sharedKeycardModule.selectedKeyPairItem.derivedFrom
|
||||||
|
keyPairAccounts: root.sharedKeycardModule.selectedKeyPairItem.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: knownKeyPairComponent
|
||||||
|
KeyPairItem {
|
||||||
|
keyPairPubKey: root.sharedKeycardModule.keyPairStoredOnKeycard.pubKey
|
||||||
|
keyPairName: root.sharedKeycardModule.keyPairStoredOnKeycard.name
|
||||||
|
keyPairIcon: root.sharedKeycardModule.keyPairStoredOnKeycard.icon
|
||||||
|
keyPairImage: root.sharedKeycardModule.keyPairStoredOnKeycard.image
|
||||||
|
keyPairDerivedFrom: root.sharedKeycardModule.keyPairStoredOnKeycard.derivedFrom
|
||||||
|
keyPairAccounts: root.sharedKeycardModule.keyPairStoredOnKeycard.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: unknownKeyPairCompontnt
|
||||||
|
KeyPairUnknownItem {
|
||||||
|
keyPairPubKey: root.sharedKeycardModule.keyPairStoredOnKeycard.pubKey
|
||||||
|
keyPairName: root.sharedKeycardModule.keyPairStoredOnKeycard.name
|
||||||
|
keyPairIcon: root.sharedKeycardModule.keyPairStoredOnKeycard.icon
|
||||||
|
keyPairImage: root.sharedKeycardModule.keyPairStoredOnKeycard.image
|
||||||
|
keyPairDerivedFrom: root.sharedKeycardModule.keyPairStoredOnKeycard.derivedFrom
|
||||||
|
keyPairAccounts: root.sharedKeycardModule.keyPairStoredOnKeycard.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
KeycardImage {
|
||||||
id: image
|
id: image
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
||||||
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
antialiasing: true
|
onAnimationCompleted: {
|
||||||
mipmap: true
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard) {
|
||||||
|
root.sharedKeycardModule.currentState.doSecondaryAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: Style.current.halfPadding
|
spacing: Style.current.halfPadding
|
||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||||
|
|
||||||
StatusIcon {
|
StatusIcon {
|
||||||
id: icon
|
id: icon
|
||||||
|
@ -50,7 +146,8 @@ Item {
|
||||||
}
|
}
|
||||||
StatusLoadingIndicator {
|
StatusLoadingIndicator {
|
||||||
id: loading
|
id: loading
|
||||||
visible: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard
|
visible: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair
|
||||||
}
|
}
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
id: title
|
id: title
|
||||||
|
@ -60,10 +157,71 @@ Item {
|
||||||
|
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
id: message
|
id: message
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.messageHeight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
active: {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if((root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader && !d.hideKeyPair) ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard && !d.hideKeyPair) ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted && !d.hideKeyPair) ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard && !d.hideKeyPair) ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceComponent: {
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
if (root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
|
||||||
|
return knownKeyPairComponent
|
||||||
|
}
|
||||||
|
return unknownKeyPairCompontnt
|
||||||
|
}
|
||||||
|
if ((root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader && !d.hideKeyPair) ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard && !d.hideKeyPair) ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted && !d.hideKeyPair) ||
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard && !d.hideKeyPair) ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure) {
|
||||||
|
return keyPairComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||||
|
if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
|
||||||
|
if (root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
|
||||||
|
return knownKeyPairComponent
|
||||||
|
}
|
||||||
|
return unknownKeyPairCompontnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
visible: !loader.active
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: this.visible? true : false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
|
@ -79,12 +237,12 @@ Item {
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_card_reader@2x")
|
source: Style.png("keycard/empty-reader")
|
||||||
|
pattern: ""
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
text: ""
|
text: ""
|
||||||
visible: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
|
@ -99,16 +257,48 @@ Item {
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_insert_card@2x")
|
pattern: "keycard/card_insert/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 16
|
||||||
|
duration: 1000
|
||||||
|
loops: 1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
visible: root.sharedKeycardModule.keycardData !== ""
|
text: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.wronglyInsertedCard?
|
||||||
text: qsTr("Check the card, it might be wrongly inserted")
|
qsTr("Check the card, it might be wrongly inserted") :
|
||||||
font.pixelSize: Constants.keycard.general.fontSize3
|
""
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.keycardInserted
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Keycard inserted...")
|
||||||
|
font.weight: Font.Bold
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/card_inserted/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 29
|
||||||
|
duration: 1000
|
||||||
|
loops: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
State {
|
State {
|
||||||
name: Constants.keycardSharedState.readingKeycard
|
name: Constants.keycardSharedState.readingKeycard
|
||||||
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard
|
||||||
|
@ -121,12 +311,17 @@ Item {
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_card_yellow@2x")
|
pattern: "keycard/warning/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 55
|
||||||
|
duration: 3000
|
||||||
|
loops: 1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
text: ""
|
text: ""
|
||||||
visible: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
|
@ -135,20 +330,74 @@ Item {
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: title
|
target: title
|
||||||
text: qsTr("This is not a Keycard")
|
text: qsTr("This is not a Keycard")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize2
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
color: Theme.palette.dangerColor1
|
color: Theme.palette.dangerColor1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_card_red_wrong@2x")
|
pattern: "keycard/strong_error/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 18
|
||||||
|
endImgIndex: 29
|
||||||
|
duration: 1300
|
||||||
|
loops: -1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
text: qsTr("The card inserted is not a recognised Keycard,\nplease remove and try and again")
|
text: qsTr("The card inserted is not a recognised Keycard,\nplease remove and try and again")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize3
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
color: Theme.palette.dangerColor1
|
color: Theme.palette.dangerColor1
|
||||||
visible: true
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.maxPinRetriesReached
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Keycard locked")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/strong_error/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 18
|
||||||
|
endImgIndex: 29
|
||||||
|
duration: 1300
|
||||||
|
loops: -1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: qsTr("Pin entered incorrectly too many times")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.keycardEmptyMetadata
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("This Keycard has empty metadata")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/card-inserted")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: qsTr("This Keycard already stores keys\nbut doesn't store any metadata")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.directColor1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
|
@ -157,20 +406,45 @@ Item {
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: title
|
target: title
|
||||||
text: qsTr("Keycard is empty")
|
text: qsTr("Keycard is empty")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize2
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_card_dark@2x")
|
source: Style.png("keycard/card-empty")
|
||||||
|
pattern: ""
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
text: qsTr("There is no key pair on this Keycard")
|
text: qsTr("There is no key pair on this Keycard")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize3
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.keycardNotEmpty
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardNotEmpty
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("This Keycard already stores keys")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/card-inserted")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard?
|
||||||
|
qsTr("To migrate %1 on to this Keycard, you\nwill need to perform a factory reset first")
|
||||||
|
.arg(root.sharedKeycardModule.selectedKeyPairItem.name) :
|
||||||
|
""
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
visible: true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
|
@ -185,12 +459,17 @@ Item {
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_card_green@2x")
|
pattern: "keycard/success/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 29
|
||||||
|
duration: 1300
|
||||||
|
loops: 1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
text: ""
|
text: ""
|
||||||
visible: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
|
@ -198,21 +477,127 @@ Item {
|
||||||
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: title
|
target: title
|
||||||
text: qsTr("Keycard successfully factory reset")
|
text: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard?
|
||||||
|
qsTr("Your Keycard has been reset") :
|
||||||
|
qsTr("Keycard successfully factory reset")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize1
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: image
|
target: image
|
||||||
source: Style.png("keycard/popup_card_green_checked@2x")
|
pattern: "keycard/strong_success/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 20
|
||||||
|
duration: 1000
|
||||||
|
loops: 1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: message
|
target: message
|
||||||
text: qsTr("You can now use this Keycard as if it\nwas a brand new empty Keycard")
|
text: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard?
|
||||||
font.pixelSize: Constants.keycard.general.fontSize3
|
qsTr("You can now create a new key pair on this Keycard") :
|
||||||
|
qsTr("You can now use this Keycard as if it\nwas a brand new empty Keycard")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
visible: true
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.migratingKeyPair
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Migrating key pair to Keycard")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/warning/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 55
|
||||||
|
duration: 3000
|
||||||
|
loops: -1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.keyPairMigrateSuccess
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Key pair successfully migrated")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/strong_success/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 20
|
||||||
|
duration: 1000
|
||||||
|
loops: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: qsTr("To complete migration close Status and log in with your new Keycard")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.keyPairMigrateFailure
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Key pair failed to migrated")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/strong_error/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 18
|
||||||
|
endImgIndex: 29
|
||||||
|
duration: 1300
|
||||||
|
loops: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.keycardMetadataDisplay
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Accounts on this Keycard")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/card-inserted")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,292 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
import StatusQ.Controls.Validators 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
import "../helpers"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
|
||||||
|
property int remainingAttempts: parseInt(root.sharedKeycardModule.keycardData, 10)
|
||||||
|
|
||||||
|
onRemainingAttemptsChanged: {
|
||||||
|
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin) {
|
||||||
|
pinInputField.statesInitialization()
|
||||||
|
pinInputField.forceFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onStateChanged: {
|
||||||
|
if(state === Constants.keycardSharedState.pinSet ||
|
||||||
|
state === Constants.keycardSharedState.pinVerified) {
|
||||||
|
pinInputField.setPin("123456") // we are free to set fake pin in this case
|
||||||
|
} else {
|
||||||
|
pinInputField.statesInitialization()
|
||||||
|
pinInputField.forceFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
KeycardImage {
|
||||||
|
id: image
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
||||||
|
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: title
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
font.weight: Font.Bold
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusPinInput {
|
||||||
|
id: pinInputField
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
validator: StatusIntValidator{bottom: 0; top: 999999;}
|
||||||
|
pinLen: Constants.keycard.general.keycardPinLength
|
||||||
|
enabled: root.sharedKeycardModule.currentState.stateType !== Constants.keycardSharedState.pinSet &&
|
||||||
|
root.sharedKeycardModule.currentState.stateType !== Constants.keycardSharedState.pinVerified
|
||||||
|
|
||||||
|
onPinInputChanged: {
|
||||||
|
if (root.state !== Constants.keycardSharedState.wrongPin) {
|
||||||
|
image.source = Style.png("keycard/enter-pin-%1".arg(pinInput.length))
|
||||||
|
}
|
||||||
|
if(pinInput.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(root.state === Constants.keycardSharedState.createPin ||
|
||||||
|
root.state === Constants.keycardSharedState.enterPin ||
|
||||||
|
root.state === Constants.keycardSharedState.wrongPin) {
|
||||||
|
root.sharedKeycardModule.setPin(pinInput)
|
||||||
|
root.sharedKeycardModule.currentState.doTertiaryAction()
|
||||||
|
}
|
||||||
|
else if(root.state === Constants.keycardSharedState.repeatPin) {
|
||||||
|
let pinsMatch = root.sharedKeycardModule.checkRepeatedKeycardPinWhileTyping(pinInput)
|
||||||
|
if (pinsMatch) {
|
||||||
|
info.text = qsTr("It is very important that you do not loose this PIN")
|
||||||
|
root.sharedKeycardModule.currentState.doTertiaryAction()
|
||||||
|
} else {
|
||||||
|
info.text = qsTr("PINs don't match")
|
||||||
|
image.source = Style.png("keycard/plain-error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: info
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
visible: text !== ""
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: message
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
visible: text !== ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
active: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard &&
|
||||||
|
(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin ||
|
||||||
|
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet)
|
||||||
|
|
||||||
|
sourceComponent: KeyPairItem {
|
||||||
|
keyPairPubKey: root.sharedKeycardModule.selectedKeyPairItem.pubKey
|
||||||
|
keyPairName: root.sharedKeycardModule.selectedKeyPairItem.name
|
||||||
|
keyPairIcon: root.sharedKeycardModule.selectedKeyPairItem.icon
|
||||||
|
keyPairImage: root.sharedKeycardModule.selectedKeyPairItem.image
|
||||||
|
keyPairDerivedFrom: root.sharedKeycardModule.selectedKeyPairItem.derivedFrom
|
||||||
|
keyPairAccounts: root.sharedKeycardModule.selectedKeyPairItem.accounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.enterPin
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/card-empty")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Enter this Keycard’s PIN")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: info
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.wrongPin
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/plain-error")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Enter Keycard PIN")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: info
|
||||||
|
text: qsTr("PIN incorrect")
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize3
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: qsTr("%n attempt(s) remaining", "", root.remainingAttempts)
|
||||||
|
color: root.remainingAttempts === 1?
|
||||||
|
Theme.palette.dangerColor1 :
|
||||||
|
Theme.palette.baseColor1
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.createPin
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/enter-pin-0")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Choose a Keycard PIN")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: info
|
||||||
|
text: qsTr("It is very important that you do not loose this PIN")
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize3
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.repeatPin
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
source: Style.png("keycard/enter-pin-0")
|
||||||
|
pattern: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Repeat Keycard PIN")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: info
|
||||||
|
text: qsTr("It is very important that you do not loose this PIN")
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize3
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.pinSet
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/strong_success/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 20
|
||||||
|
duration: 1300
|
||||||
|
loops: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Keycard PIN set")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: info
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.pinVerified
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified
|
||||||
|
PropertyChanges {
|
||||||
|
target: image
|
||||||
|
pattern: "keycard/strong_success/img-%1"
|
||||||
|
source: ""
|
||||||
|
startImgIndexForTheFirstLoop: 0
|
||||||
|
startImgIndexForOtherLoops: 0
|
||||||
|
endImgIndex: 20
|
||||||
|
duration: 1300
|
||||||
|
loops: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Keycard PIN verified!")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: info
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtGraphicalEffects 1.14
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
property bool hideSeed: true
|
||||||
|
|
||||||
|
signal seedPhraseRevealed()
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property var seedPhrase: root.sharedKeycardModule.getMnemonic().split(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: title
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: message
|
||||||
|
Layout.preferredHeight: Constants.keycard.general.messageHeight
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
StatusGridView {
|
||||||
|
id: grid
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: !root.hideSeed
|
||||||
|
cellWidth: parent.width * 0.5
|
||||||
|
cellHeight: 48
|
||||||
|
interactive: false
|
||||||
|
model: 12
|
||||||
|
readonly property var wordIndex: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
|
||||||
|
readonly property int spacing: 4
|
||||||
|
delegate: StatusSeedPhraseInput {
|
||||||
|
width: (grid.cellWidth - grid.spacing)
|
||||||
|
height: (grid.cellHeight - grid.spacing)
|
||||||
|
textEdit.input.edit.enabled: false
|
||||||
|
text: {
|
||||||
|
const idx = parseInt(leftComponentText) - 1;
|
||||||
|
if (!d.seedPhrase || idx < 0 || idx > d.seedPhrase.length - 1)
|
||||||
|
return "";
|
||||||
|
return d.seedPhrase[idx];
|
||||||
|
}
|
||||||
|
leftComponentText: grid.wordIndex[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GaussianBlur {
|
||||||
|
id: blur
|
||||||
|
anchors.fill: grid
|
||||||
|
visible: root.hideSeed
|
||||||
|
source: grid
|
||||||
|
radius: 16
|
||||||
|
samples: 16
|
||||||
|
transparentBorder: true
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusButton {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
visible: root.hideSeed
|
||||||
|
type: StatusBaseButton.Type.Primary
|
||||||
|
icon.name: "view"
|
||||||
|
text: qsTr("Reveal seed phrase")
|
||||||
|
onClicked: {
|
||||||
|
root.hideSeed = false;
|
||||||
|
root.seedPhraseRevealed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: Constants.keycardSharedState.seedPhraseDisplay
|
||||||
|
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.seedPhraseDisplay
|
||||||
|
PropertyChanges {
|
||||||
|
target: title
|
||||||
|
text: qsTr("Write down your seed phrase")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: message
|
||||||
|
text: qsTr("The next screen contains your seed phrase.<br/><b>Anyone</b> who sees it can use it to access to your funds.")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
import shared.status 1.0
|
||||||
|
|
||||||
|
import "../helpers"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var sharedKeycardModule
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Style.current.xlPadding
|
||||||
|
anchors.bottomMargin: Style.current.halfPadding
|
||||||
|
anchors.leftMargin: Style.current.xlPadding
|
||||||
|
anchors.rightMargin: Style.current.xlPadding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ButtonGroup {
|
||||||
|
id: keyPairsButtonGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: title
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Select a key pair")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize1
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: subTitle
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Select which key pair you’d like to move to this Keycard")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Style.current.halfPadding
|
||||||
|
Layout.fillHeight: root.sharedKeycardModule.keyPairModel.count === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
visible: !root.sharedKeycardModule.isProfileKeyPairMigrated()
|
||||||
|
Layout.preferredWidth: parent.width - 2 * Style.current.padding
|
||||||
|
Layout.leftMargin: Style.current.padding
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
text: qsTr("Profile key pair")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyPairList {
|
||||||
|
visible: !root.sharedKeycardModule.isProfileKeyPairMigrated()
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 100
|
||||||
|
Layout.fillHeight: visible && root.sharedKeycardModule.keyPairModel.count === 1
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
filterProfilePair: true
|
||||||
|
keyPairModel: root.sharedKeycardModule.keyPairModel
|
||||||
|
buttonGroup: keyPairsButtonGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
visible: root.sharedKeycardModule.isProfileKeyPairMigrated() && root.sharedKeycardModule.keyPairModel.count > 0 ||
|
||||||
|
!root.sharedKeycardModule.isProfileKeyPairMigrated() && root.sharedKeycardModule.keyPairModel.count > 1
|
||||||
|
Layout.preferredWidth: parent.width - 2 * Style.current.padding
|
||||||
|
Layout.leftMargin: Style.current.padding
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
text: qsTr("Other key pairs")
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyPairList {
|
||||||
|
visible: root.sharedKeycardModule.isProfileKeyPairMigrated() && root.sharedKeycardModule.keyPairModel.count > 0 ||
|
||||||
|
!root.sharedKeycardModule.isProfileKeyPairMigrated() && root.sharedKeycardModule.keyPairModel.count > 1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
|
||||||
|
sharedKeycardModule: root.sharedKeycardModule
|
||||||
|
keyPairModel: root.sharedKeycardModule.keyPairModel
|
||||||
|
buttonGroup: keyPairsButtonGroup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,19 @@
|
||||||
import QtQuick 2.13
|
import QtQuick 2.13
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var words: []
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", "english.txt");
|
xhr.open("GET", "english.txt");
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
var words = xhr.responseText.split('\n');
|
root.words = xhr.responseText.split('\n');
|
||||||
for (var i = 0; i < words.length; i++) {
|
for (var i = 0; i < root.words.length; i++) {
|
||||||
if (words[i] !== "") {
|
if (root.words[i] !== "") {
|
||||||
insert(count, {"seedWord": words[i]});
|
insert(count, {"seedWord": root.words[i]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,9 +67,16 @@ QtObject {
|
||||||
readonly property string loginKeycardEmpty: "LoginKeycardEmpty"
|
readonly property string loginKeycardEmpty: "LoginKeycardEmpty"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property QtObject predefinedKeycardData: QtObject {
|
||||||
|
readonly property int wronglyInsertedCard: 1
|
||||||
|
readonly property int hideKeyPair: 2
|
||||||
|
readonly property int wrongSeedPhrase: 4
|
||||||
|
}
|
||||||
|
|
||||||
readonly property QtObject keycardSharedFlow: QtObject {
|
readonly property QtObject keycardSharedFlow: QtObject {
|
||||||
readonly property string general: "General"
|
readonly property string general: "General"
|
||||||
readonly property string factoryReset: "FactoryReset"
|
readonly property string factoryReset: "FactoryReset"
|
||||||
|
readonly property string setupNewKeycard: "SetupNewKeycard"
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property QtObject keycardSharedState: QtObject {
|
readonly property QtObject keycardSharedState: QtObject {
|
||||||
|
@ -77,12 +84,31 @@ QtObject {
|
||||||
readonly property string pluginReader: "PluginReader"
|
readonly property string pluginReader: "PluginReader"
|
||||||
readonly property string readingKeycard: "ReadingKeycard"
|
readonly property string readingKeycard: "ReadingKeycard"
|
||||||
readonly property string insertKeycard: "InsertKeycard"
|
readonly property string insertKeycard: "InsertKeycard"
|
||||||
|
readonly property string keycardInserted: "KeycardInserted"
|
||||||
|
readonly property string createPin: "CreatePin"
|
||||||
|
readonly property string repeatPin: "RepeatPin"
|
||||||
|
readonly property string pinSet: "PinSet"
|
||||||
|
readonly property string pinVerified: "PinVerified"
|
||||||
readonly property string enterPin: "EnterPin"
|
readonly property string enterPin: "EnterPin"
|
||||||
|
readonly property string wrongPin: "WrongPin"
|
||||||
|
readonly property string maxPinRetriesReached: "MaxPinRetriesReached"
|
||||||
readonly property string factoryResetConfirmation: "FactoryResetConfirmation"
|
readonly property string factoryResetConfirmation: "FactoryResetConfirmation"
|
||||||
|
readonly property string factoryResetConfirmationDisplayMetadata: "FactoryResetConfirmationDisplayMetadata"
|
||||||
readonly property string factoryResetSuccess: "FactoryResetSuccess"
|
readonly property string factoryResetSuccess: "FactoryResetSuccess"
|
||||||
|
readonly property string keycardEmptyMetadata: "KeycardEmptyMetadata"
|
||||||
|
readonly property string keycardMetadataDisplay: "KeycardMetadataDisplay"
|
||||||
readonly property string keycardEmpty: "KeycardEmpty"
|
readonly property string keycardEmpty: "KeycardEmpty"
|
||||||
|
readonly property string keycardNotEmpty: "KeycardNotEmpty"
|
||||||
readonly property string notKeycard: "NotKeycard"
|
readonly property string notKeycard: "NotKeycard"
|
||||||
readonly property string recognizedKeycard: "RecognizedKeycard"
|
readonly property string recognizedKeycard: "RecognizedKeycard"
|
||||||
|
readonly property string selectExistingKeyPair: "SelectExistingKeyPair"
|
||||||
|
readonly property string enterSeedPhrase: "EnterSeedPhrase"
|
||||||
|
readonly property string wrongSeedPhrase: "WrongSeedPhrase"
|
||||||
|
readonly property string seedPhraseDisplay: "SeedPhraseDisplay"
|
||||||
|
readonly property string seedPhraseEnterWords: "SeedPhraseEnterWords"
|
||||||
|
readonly property string keyPairMigrateSuccess: "KeyPairMigrateSuccess"
|
||||||
|
readonly property string keyPairMigrateFailure: "KeyPairMigrateFailure"
|
||||||
|
readonly property string migratingKeyPair: "MigratingKeyPair"
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property QtObject keychain: QtObject {
|
readonly property QtObject keychain: QtObject {
|
||||||
|
@ -339,6 +365,17 @@ QtObject {
|
||||||
readonly property int pukCellHeight: 60
|
readonly property int pukCellHeight: 60
|
||||||
readonly property int sharedFlowImageWidth: 240
|
readonly property int sharedFlowImageWidth: 240
|
||||||
readonly property int sharedFlowImageHeight: 240
|
readonly property int sharedFlowImageHeight: 240
|
||||||
|
readonly property int popupWidth: 640
|
||||||
|
readonly property int popupHeight: 640
|
||||||
|
readonly property int popupBiggerHeight: 766
|
||||||
|
readonly property int titleHeight: 44
|
||||||
|
readonly property int messageHeight: 48
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property QtObject keyPairType: QtObject {
|
||||||
|
readonly property int profile: 0
|
||||||
|
readonly property int seedImport: 1
|
||||||
|
readonly property int privateKeyImport: 2
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property QtObject shared: QtObject {
|
readonly property QtObject shared: QtObject {
|
||||||
|
|
Loading…
Reference in New Issue