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"
|
||||
# Local Account Settings values:
|
||||
const LS_VALUE_STORE* = "store"
|
||||
const LS_VALUE_NOTNOW* = "notNow"
|
||||
const LS_VALUE_NOT_NOW* = "notNow"
|
||||
const LS_VALUE_NEVER* = "never"
|
||||
|
||||
QtObject:
|
||||
|
|
|
@ -4,6 +4,8 @@ import io_interface
|
|||
|
||||
import ../../../../core/eventemitter
|
||||
|
||||
import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module
|
||||
|
||||
logScope:
|
||||
topics = "profile-section-keycard-module-controller"
|
||||
|
||||
|
@ -23,4 +25,9 @@ proc delete*(self: Controller) =
|
|||
discard
|
||||
|
||||
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.} =
|
||||
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
|
||||
# Delegate for the view must be declared here due to use of QtObject and multi
|
||||
# inheritance, which is not well supported in Nim.
|
||||
|
|
|
@ -6,8 +6,12 @@ import ../io_interface as delegate_interface
|
|||
import ../../../../core/eventemitter
|
||||
|
||||
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 ../../../shared_modules/keycard_popup/module as keycard_shared_module
|
||||
|
||||
export io_interface
|
||||
|
||||
logScope:
|
||||
|
@ -22,16 +26,23 @@ type
|
|||
moduleLoaded: bool
|
||||
events: EventEmitter
|
||||
keycardService: keycard_service.Service
|
||||
privacyService: privacy_service.Service
|
||||
accountsService: accounts_service.Service
|
||||
walletAccountService: wallet_account_service.Service
|
||||
keycardSharedModule: keycard_shared_module.AccessInterface
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface,
|
||||
events: EventEmitter,
|
||||
keycardService: keycard_service.Service,
|
||||
privacyService: privacy_service.Service,
|
||||
accountsService: accounts_service.Service,
|
||||
walletAccountService: wallet_account_service.Service): Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.events = events
|
||||
result.keycardService = keycardService
|
||||
result.privacyService = privacyService
|
||||
result.accountsService = accountsService
|
||||
result.walletAccountService = walletAccountService
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
|
@ -42,6 +53,8 @@ method delete*(self: Module) =
|
|||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
if not self.keycardSharedModule.isNil:
|
||||
self.keycardSharedModule.delete
|
||||
|
||||
method load*(self: Module) =
|
||||
self.controller.init()
|
||||
|
@ -56,3 +69,28 @@ method viewDidLoad*(self: Module) =
|
|||
|
||||
method getModuleAsVariant*(self: Module): QVariant =
|
||||
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()
|
|
@ -18,3 +18,18 @@ QtObject:
|
|||
proc load*(self: View) =
|
||||
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.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)
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ import ../../../global/global_singleton
|
|||
import ../../../core/signals/types
|
||||
import ../../../core/eventemitter
|
||||
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:
|
||||
topics = "keycard-popup-controller"
|
||||
|
@ -15,21 +18,46 @@ type
|
|||
delegate: io_interface.AccessInterface
|
||||
events: EventEmitter
|
||||
keycardService: keycard_service.Service
|
||||
privacyService: privacy_service.Service
|
||||
accountsService: accounts_service.Service
|
||||
walletAccountService: wallet_account_service.Service
|
||||
connectionIds: seq[UUID]
|
||||
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,
|
||||
events: EventEmitter,
|
||||
keycardService: keycard_service.Service):
|
||||
keycardService: keycard_service.Service,
|
||||
privacyService: privacy_service.Service,
|
||||
accountsService: accounts_service.Service,
|
||||
walletAccountService: wallet_account_service.Service):
|
||||
Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.events = events
|
||||
result.keycardService = keycardService
|
||||
result.privacyService = privacyService
|
||||
result.accountsService = accountsService
|
||||
result.walletAccountService = walletAccountService
|
||||
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) =
|
||||
discard
|
||||
self.disconnect()
|
||||
|
||||
proc init*(self: Controller) =
|
||||
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.connectionIds.add(handlerId)
|
||||
|
||||
proc disconnect*(self: Controller) =
|
||||
for id in self.connectionIds:
|
||||
self.events.disconnect(id)
|
||||
proc getKeycardData*(self: Controller): string =
|
||||
return self.delegate.getKeycardData()
|
||||
|
||||
proc setKeycardData*(self: Controller, value: string) =
|
||||
self.delegate.setKeycardData(value)
|
||||
|
@ -50,6 +77,83 @@ proc containsMetadata*(self: Controller): bool =
|
|||
proc setContainsMetadata*(self: Controller, value: bool) =
|
||||
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) =
|
||||
self.keycardService.cancelCurrentFlow()
|
||||
# in most cases we're running another flow after canceling the current one,
|
||||
|
@ -64,9 +168,76 @@ proc runGetMetadataFlow*(self: Controller) =
|
|||
self.cancelCurrentFlow()
|
||||
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) =
|
||||
self.keycardService.resumeCurrentFlowLater()
|
||||
|
||||
proc readyToDisplayPopup*(self: Controller) =
|
||||
self.events.emit(SignalSharedKeycarModuleDisplayPopup, Args())
|
||||
|
||||
proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool) =
|
||||
let data = SharedKeycarModuleFlowTerminatedArgs(lastStepInTheCurrentFlow: lastStepInTheCurrentFlow)
|
||||
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) =
|
||||
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) =
|
||||
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: FactoryResetConfirmationState, controller: Controller) =
|
||||
if self.flowType == FlowType.FactoryReset:
|
||||
if self.flowType == FlowType.FactoryReset or
|
||||
self.flowType == FlowType.SetupNewKeycard:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
|
||||
method getNextPrimaryState*(self: FactoryResetConfirmationState, controller: Controller): State =
|
||||
return createState(StateType.PluginReader, self.flowType, nil)
|
||||
method resolveKeycardNextState*(self: FactoryResetConfirmationState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -11,3 +11,13 @@ proc delete*(self: FactoryResetSuccessState) =
|
|||
method executePrimaryCommand*(self: FactoryResetSuccessState, controller: Controller) =
|
||||
if self.flowType == FlowType.FactoryReset:
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
let state = ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
||||
if not state.isNil:
|
||||
return state
|
||||
if keycardFlowType == ResponseTypeValueInsertCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorConnection:
|
||||
controller.setKeycardData(ResponseTypeValueInsertCard)
|
||||
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = true))
|
||||
return nil
|
||||
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||
controller.setKeycardData("")
|
||||
return createState(StateType.ReadingKeycard, self.flowType, nil)
|
||||
controller.setKeycardData(getPredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||
if self.flowType == FlowType.SetupNewKeycard:
|
||||
return createState(StateType.KeycardInserted, self.flowType, self.getBackState)
|
||||
return createState(StateType.KeycardInserted, self.flowType, 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
|
||||
|
||||
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)
|
|
@ -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
|
||||
|
||||
method executePrimaryCommand*(self: NotKeycardState, controller: Controller) =
|
||||
if self.flowType == FlowType.FactoryReset:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
if self.flowType == FlowType.FactoryReset or
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorConnection:
|
||||
controller.resumeCurrentFlowLater()
|
||||
return nil
|
||||
if keycardFlowType == ResponseTypeValueInsertCard:
|
||||
return createState(StateType.InsertKeycard, self.flowType, nil)
|
||||
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -9,21 +9,16 @@ proc delete*(self: ReadingKeycardState) =
|
|||
self.State.delete
|
||||
|
||||
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)
|
||||
|
||||
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,
|
||||
controller: Controller): State =
|
||||
if self.flowType == FlowType.FactoryReset:
|
||||
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||
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)
|
||||
# this is used in case a keycard is inserted and we jump to the first meaningful screen
|
||||
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
|
|
@ -9,11 +9,15 @@ proc delete*(self: RecognizedKeycardState) =
|
|||
self.State.delete
|
||||
|
||||
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)
|
||||
|
||||
method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controller): State =
|
||||
if controller.containsMetadata():
|
||||
discard # from here we will jump to enter pin view once we add that in keycard settings
|
||||
else:
|
||||
return createState(StateType.FactoryResetConfirmation, self.flowType, nil)
|
||||
if self.flowType == FlowType.FactoryReset:
|
||||
if controller.containsMetadata():
|
||||
return createState(StateType.EnterPin, 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
|
||||
from ../../../../../app_service/service/keycard/service import KeycardEvent, KeyDetails
|
||||
from ../io_interface import FlowType
|
||||
|
||||
export KeycardEvent, KeyDetails
|
||||
|
||||
type FlowType* {.pure.} = enum
|
||||
General = "General"
|
||||
FactoryReset = "FactoryReset"
|
||||
|
||||
export FlowType, KeycardEvent, KeyDetails
|
||||
|
||||
type StateType* {.pure.} = enum
|
||||
NoState = "NoState"
|
||||
PluginReader = "PluginReader"
|
||||
ReadingKeycard = "ReadingKeycard"
|
||||
InsertKeycard = "InsertKeycard"
|
||||
KeycardInserted = "KeycardInserted"
|
||||
CreatePin = "CreatePin"
|
||||
RepeatPin = "RepeatPin"
|
||||
PinSet = "PinSet"
|
||||
PinVerified = "PinVerified"
|
||||
EnterPin = "EnterPin"
|
||||
WrongPin = "WrongPin"
|
||||
MaxPinRetriesReached = "MaxPinRetriesReached"
|
||||
FactoryResetConfirmation = "FactoryResetConfirmation"
|
||||
FactoryResetConfirmationDisplayMetadata = "FactoryResetConfirmationDisplayMetadata"
|
||||
FactoryResetSuccess = "FactoryResetSuccess"
|
||||
KeycardEmptyMetadata = "KeycardEmptyMetadata"
|
||||
KeycardMetadataDisplay = "KeycardMetadataDisplay"
|
||||
KeycardEmpty = "KeycardEmpty"
|
||||
KeycardNotEmpty = "KeycardNotEmpty"
|
||||
NotKeycard = "NotKeycard"
|
||||
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.
|
||||
|
@ -70,6 +85,10 @@ method getNextPrimaryState*(self: State, controller: Controller): State {.inlin
|
|||
method getNextSecondaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||
return nil
|
||||
|
||||
## Returns next state instance in case the "tertiary" action is triggered
|
||||
method getNextTertiaryState*(self: State, controller: Controller): State {.inline base.} =
|
||||
return nil
|
||||
|
||||
## This method is executed in case "back" button is clicked
|
||||
method executeBackCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
discard
|
||||
|
@ -82,6 +101,10 @@ method executePrimaryCommand*(self: State, controller: Controller) {.inline base
|
|||
method executeSecondaryCommand*(self: State, controller: Controller) {.inline base.} =
|
||||
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
|
||||
method resolveKeycardNextState*(self: State, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State {.inline base.} =
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import chronicles
|
||||
import parseutils, chronicles
|
||||
import ../../../../../app_service/service/keycard/constants
|
||||
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 PUKLengthForStatusApp
|
||||
import state
|
||||
|
@ -8,37 +9,217 @@ import state
|
|||
logScope:
|
||||
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
|
||||
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 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_success_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_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 pin_set_state
|
||||
include pin_verified_state
|
||||
include plugin_reader_state
|
||||
include reading_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 =
|
||||
if stateToBeCreated == StateType.CreatePin:
|
||||
return newCreatePinState(flowType, backState)
|
||||
if stateToBeCreated == StateType.EnterPin:
|
||||
return newEnterPinState(flowType, backState)
|
||||
if stateToBeCreated == StateType.EnterSeedPhrase:
|
||||
return newEnterSeedPhraseState(flowType, backState)
|
||||
if stateToBeCreated == StateType.FactoryResetConfirmationDisplayMetadata:
|
||||
return newFactoryResetConfirmationDisplayMetadataState(flowType, backState)
|
||||
if stateToBeCreated == StateType.FactoryResetConfirmation:
|
||||
return newFactoryResetConfirmationState(flowType, backState)
|
||||
if stateToBeCreated == StateType.FactoryResetSuccess:
|
||||
return newFactoryResetSuccessState(flowType, backState)
|
||||
if stateToBeCreated == StateType.InsertKeycard:
|
||||
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:
|
||||
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:
|
||||
return newNotKeycardState(flowType, backState)
|
||||
if stateToBeCreated == StateType.PinSet:
|
||||
return newPinSetState(flowType, backState)
|
||||
if stateToBeCreated == StateType.PinVerified:
|
||||
return newPinVerifiedState(flowType, backState)
|
||||
if stateToBeCreated == StateType.PluginReader:
|
||||
return newPluginReaderState(flowType, backState)
|
||||
if stateToBeCreated == StateType.ReadingKeycard:
|
||||
return newReadingKeycardState(flowType, backState)
|
||||
if stateToBeCreated == StateType.RecognizedKeycard:
|
||||
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
|
||||
|
||||
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)
|
|
@ -56,3 +56,7 @@ QtObject:
|
|||
proc secondaryActionClicked*(self: StateWrapper) {.signal.}
|
||||
proc doSecondaryAction*(self: StateWrapper) {.slot.} =
|
||||
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 ../../../../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"
|
||||
|
||||
type
|
||||
SharedKeycarModuleFlowTerminatedArgs* = ref object of Args
|
||||
lastStepInTheCurrentFlow*: bool
|
||||
|
||||
type FlowType* {.pure.} = enum
|
||||
General = "General"
|
||||
FactoryReset = "FactoryReset"
|
||||
SetupNewKeycard = "SetupNewKeycard"
|
||||
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
||||
|
@ -17,6 +24,9 @@ method delete*(self: AccessInterface) {.base.} =
|
|||
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||
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.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
@ -29,13 +39,51 @@ method onPrimaryActionClicked*(self: AccessInterface) {.base.} =
|
|||
method onSecondaryActionClicked*(self: AccessInterface) {.base.} =
|
||||
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.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method runFactoryResetFlow*(self: AccessInterface) {.base.} =
|
||||
method runFlow*(self: AccessInterface, flowToRun: FlowType) {.base.} =
|
||||
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
|
||||
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 view, controller
|
||||
import internal/[state, state_factory]
|
||||
import models/[key_pair_model, key_pair_item]
|
||||
import ../../../global/global_singleton
|
||||
import ../../../core/eventemitter
|
||||
|
||||
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
|
||||
|
||||
|
@ -19,20 +24,24 @@ type
|
|||
viewVariant: QVariant
|
||||
controller: Controller
|
||||
initialized: bool
|
||||
tmpLocalState: State # used when flow is run, until response arrives to determine next state appropriatelly
|
||||
|
||||
proc newModule*[T](delegate: T,
|
||||
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] =
|
||||
result = Module[T]()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
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
|
||||
|
||||
method delete*[T](self: Module[T]) =
|
||||
self.controller.disconnect()
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
@ -40,9 +49,54 @@ method delete*[T](self: Module[T]) =
|
|||
method getModuleAsVariant*[T](self: Module[T]): QVariant =
|
||||
return self.viewVariant
|
||||
|
||||
method getKeycardData*[T](self: Module[T]): string =
|
||||
return self.view.getKeycardData()
|
||||
|
||||
method setKeycardData*[T](self: Module[T], value: string) =
|
||||
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]) =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
|
@ -81,11 +135,32 @@ method onSecondaryActionClicked*[T](self: Module[T]) =
|
|||
self.view.setCurrentState(nextState)
|
||||
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()
|
||||
if currStateObj.isNil:
|
||||
error "sm_cannot resolve current state"
|
||||
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()
|
||||
let nextState = currStateObj.resolveKeycardNextState(keycardFlowType, keycardEvent, self.controller)
|
||||
if nextState.isNil:
|
||||
|
@ -93,8 +168,131 @@ method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEv
|
|||
self.view.setCurrentState(nextState)
|
||||
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:
|
||||
self.controller.init()
|
||||
self.view.setCurrentState(newPluginReaderState(FlowType.FactoryReset, nil))
|
||||
self.controller.runGetMetadataFlow()
|
||||
if flowToRun == FlowType.FactoryReset:
|
||||
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 io_interface
|
||||
import internal/[state, state_wrapper]
|
||||
import models/[key_pair_model, key_pair_item, key_pair_selected_item]
|
||||
|
||||
QtObject:
|
||||
type
|
||||
|
@ -8,11 +9,30 @@ QtObject:
|
|||
delegate: io_interface.AccessInterface
|
||||
currentState: StateWrapper
|
||||
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
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.currentStateVariant.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
|
||||
|
||||
proc newView*(delegate: io_interface.AccessInterface): View =
|
||||
|
@ -25,6 +45,7 @@ QtObject:
|
|||
signalConnect(result.currentState, "backActionClicked()", result, "onBackActionClicked()", 2)
|
||||
signalConnect(result.currentState, "primaryActionClicked()", result, "onPrimaryActionClicked()", 2)
|
||||
signalConnect(result.currentState, "secondaryActionClicked()", result, "onSecondaryActionClicked()", 2)
|
||||
signalConnect(result.currentState, "tertiaryActionClicked()", result, "onTertiaryActionClicked()", 2)
|
||||
|
||||
proc currentStateObj*(self: View): State =
|
||||
return self.currentState.getStateObj()
|
||||
|
@ -57,5 +78,84 @@ QtObject:
|
|||
proc onSecondaryActionClicked*(self: View) {.slot.} =
|
||||
self.delegate.onSecondaryActionClicked()
|
||||
|
||||
proc runFactoryResetFlow*(self: View) {.slot.} =
|
||||
self.delegate.runFactoryResetFlow()
|
||||
proc onTertiaryActionClicked*(self: View) {.slot.} =
|
||||
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
|
||||
|
||||
const WalletTypeDefaultStatusAccount* = ""
|
||||
const WalletTypeGenerated* = "generated"
|
||||
const WalletTypeSeed* = "seed"
|
||||
const WalletTypeWatch* = "watch"
|
||||
const WalletTypeKey* = "key"
|
||||
|
||||
type BalanceDto* = object
|
||||
balance*: float64
|
||||
currencyBalance*: float64
|
||||
|
|
|
@ -253,8 +253,8 @@ StatusSectionLayout {
|
|||
implicitWidth: parent.width
|
||||
implicitHeight: parent.height
|
||||
|
||||
keycardStore: profileView.store.keycardStore
|
||||
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.keycard)
|
||||
keycardStore: root.store.keycardStore
|
||||
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.keycard)
|
||||
contentWidth: d.contentWidth
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,7 @@ QtObject {
|
|||
|
||||
property var keycardModule
|
||||
|
||||
function runSetupKeycardPopup() {
|
||||
root.keycardModule.runSetupKeycardPopup()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ import utils 1.0
|
|||
import shared.panels 1.0
|
||||
import shared.controls 1.0
|
||||
import shared.status 1.0
|
||||
import shared.popups.keycard 1.0
|
||||
|
||||
import "../stores"
|
||||
import "../controls"
|
||||
import "../panels"
|
||||
import "../popups"
|
||||
|
||||
SettingsContentBase {
|
||||
id: root
|
||||
|
@ -33,6 +35,29 @@ SettingsContentBase {
|
|||
id: contentColumn
|
||||
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 {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredHeight: sourceSize.height
|
||||
|
@ -70,8 +95,8 @@ SettingsContentBase {
|
|||
color: Theme.palette.baseColor1
|
||||
}
|
||||
]
|
||||
sensor.onClicked: {
|
||||
console.warn("TODO: Run Set up Keycard flow...")
|
||||
onClicked: {
|
||||
root.keycardStore.runSetupKeycardPopup()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +117,7 @@ SettingsContentBase {
|
|||
color: Theme.palette.baseColor1
|
||||
}
|
||||
]
|
||||
sensor.onClicked: {
|
||||
onClicked: {
|
||||
console.warn("TODO: Generate a seed phrase...")
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +132,7 @@ SettingsContentBase {
|
|||
color: Theme.palette.baseColor1
|
||||
}
|
||||
]
|
||||
sensor.onClicked: {
|
||||
onClicked: {
|
||||
console.warn("TODO: Import or restore via a seed phrase...")
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +147,7 @@ SettingsContentBase {
|
|||
color: Theme.palette.baseColor1
|
||||
}
|
||||
]
|
||||
sensor.onClicked: {
|
||||
onClicked: {
|
||||
console.warn("TODO: Import from Keycard to Status Desktop...")
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +169,7 @@ SettingsContentBase {
|
|||
color: Theme.palette.baseColor1
|
||||
}
|
||||
]
|
||||
sensor.onClicked: {
|
||||
onClicked: {
|
||||
console.warn("TODO: Check what’s on a Keycard...")
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +184,7 @@ SettingsContentBase {
|
|||
color: Theme.palette.baseColor1
|
||||
}
|
||||
]
|
||||
sensor.onClicked: {
|
||||
onClicked: {
|
||||
console.warn("TODO: Factory reset a Keycard...")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,30 +15,91 @@ StatusModal {
|
|||
|
||||
property var sharedKeycardModule
|
||||
|
||||
width: 640
|
||||
height: 640
|
||||
margins: 8
|
||||
width: Constants.keycard.general.popupWidth
|
||||
height: {
|
||||
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
|
||||
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 {
|
||||
id: d
|
||||
property bool factoryResetConfirmed: false
|
||||
property bool resetInProgress: d.factoryResetConfirmed && root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard
|
||||
property bool primaryButtonEnabled: false
|
||||
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: {
|
||||
hasCloseButton = !resetInProgress
|
||||
onDisablePopupCloseChanged: {
|
||||
hasCloseButton = !disablePopupClose
|
||||
}
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
// for all states but the `factoryResetConfirmation` cancel the flow is primary action
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||
{
|
||||
root.sharedKeycardModule.currentState.doSecondaryAction()
|
||||
return
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||
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.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()
|
||||
}
|
||||
|
@ -50,19 +111,53 @@ StatusModal {
|
|||
sourceComponent: {
|
||||
if (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.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.keycardEmptyMetadata ||
|
||||
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.recognizedKeycard)
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay)
|
||||
{
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -80,8 +175,72 @@ StatusModal {
|
|||
KeycardConfirmation {
|
||||
sharedKeycardModule: root.sharedKeycardModule
|
||||
|
||||
Component.onCompleted: {
|
||||
d.primaryButtonEnabled = false
|
||||
}
|
||||
|
||||
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 {
|
||||
id: backButton
|
||||
visible: root.sharedKeycardModule.currentState.displayBackButton
|
||||
height: primaryButton.height
|
||||
width: primaryButton.height
|
||||
onClicked: {
|
||||
root.sharedKeycardModule.currentState.backAction()
|
||||
}
|
||||
|
@ -101,13 +262,62 @@ StatusModal {
|
|||
StatusButton {
|
||||
id: secondaryButton
|
||||
text: {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||
return qsTr("Cancel")
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||
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 ""
|
||||
}
|
||||
visible: {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||
return true
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||
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
|
||||
}
|
||||
highlighted: focus
|
||||
|
@ -119,20 +329,130 @@ StatusModal {
|
|||
StatusButton {
|
||||
id: primaryButton
|
||||
text: {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||
return qsTr("Factory reset this Keycard")
|
||||
if (d.resetInProgress ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess)
|
||||
return qsTr("Done")
|
||||
return qsTr("Cancel")
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard) {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||
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 ||
|
||||
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: {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetConfirmation)
|
||||
return d.factoryResetConfirmed
|
||||
if (d.resetInProgress)
|
||||
return false
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair) {
|
||||
if (d.disablePopupClose) {
|
||||
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
|
||||
}
|
||||
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
|
||||
|
||||
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 "../helpers"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
|
@ -15,42 +17,119 @@ Item {
|
|||
|
||||
signal confirmationUpdated(bool value)
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.current.padding
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
||||
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
||||
fillMode: Image.PreserveAspectFit
|
||||
antialiasing: true
|
||||
mipmap: true
|
||||
source: Style.png("keycard/popup_card_red_sprayed@2x")
|
||||
pattern: "keycard/strong_error/img-%1"
|
||||
source: ""
|
||||
startImgIndexForTheFirstLoop: 0
|
||||
startImgIndexForOtherLoops: 18
|
||||
endImgIndex: 29
|
||||
duration: 1300
|
||||
loops: -1
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: title
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||
wrapMode: Text.WordWrap
|
||||
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
|
||||
}
|
||||
|
||||
StatusCheckBox {
|
||||
id: confirmation
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredHeight: Constants.keycard.general.messageHeight
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
leftSide: false
|
||||
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")
|
||||
|
||||
onCheckedChanged: {
|
||||
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.Components 0.1
|
||||
|
||||
///////// Remove Later////////////
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
//////////////////////////////////
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import "../helpers"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
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 {
|
||||
id: timer
|
||||
interval: 1000
|
||||
|
@ -22,23 +41,100 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
///////// Remove Later////////////
|
||||
StatusModal {
|
||||
id: passwordPopup
|
||||
width: 300
|
||||
height: 200
|
||||
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
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredHeight: Constants.keycard.shared.imageHeight
|
||||
Layout.preferredWidth: Constants.keycard.shared.imageWidth
|
||||
fillMode: Image.PreserveAspectFit
|
||||
antialiasing: true
|
||||
mipmap: true
|
||||
|
||||
onAnimationCompleted: {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard) {
|
||||
root.sharedKeycardModule.currentState.doSecondaryAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Style.current.halfPadding
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredHeight: Constants.keycard.general.titleHeight
|
||||
|
||||
StatusIcon {
|
||||
id: icon
|
||||
|
@ -50,7 +146,8 @@ Item {
|
|||
}
|
||||
StatusLoadingIndicator {
|
||||
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 {
|
||||
id: title
|
||||
|
@ -60,10 +157,71 @@ Item {
|
|||
|
||||
StatusBaseText {
|
||||
id: message
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: Constants.keycard.general.messageHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
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: [
|
||||
|
@ -79,12 +237,12 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: image
|
||||
source: Style.png("keycard/popup_card_reader@2x")
|
||||
source: Style.png("keycard/empty-reader")
|
||||
pattern: ""
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
text: ""
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
State {
|
||||
|
@ -99,16 +257,48 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
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 {
|
||||
target: message
|
||||
visible: root.sharedKeycardModule.keycardData !== ""
|
||||
text: qsTr("Check the card, it might be wrongly inserted")
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
text: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.wronglyInsertedCard?
|
||||
qsTr("Check the card, it might be wrongly inserted") :
|
||||
""
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
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 {
|
||||
name: Constants.keycardSharedState.readingKeycard
|
||||
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard
|
||||
|
@ -121,12 +311,17 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
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 {
|
||||
target: message
|
||||
text: ""
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
State {
|
||||
|
@ -135,20 +330,74 @@ Item {
|
|||
PropertyChanges {
|
||||
target: title
|
||||
text: qsTr("This is not a Keycard")
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
font.weight: Font.Bold
|
||||
color: Theme.palette.dangerColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
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 {
|
||||
target: message
|
||||
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
|
||||
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 {
|
||||
|
@ -157,20 +406,45 @@ Item {
|
|||
PropertyChanges {
|
||||
target: title
|
||||
text: qsTr("Keycard is empty")
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
font.weight: Font.Bold
|
||||
color: Theme.palette.directColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: image
|
||||
source: Style.png("keycard/popup_card_dark@2x")
|
||||
source: Style.png("keycard/card-empty")
|
||||
pattern: ""
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
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
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
|
@ -185,12 +459,17 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
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 {
|
||||
target: message
|
||||
text: ""
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
State {
|
||||
|
@ -198,21 +477,127 @@ Item {
|
|||
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess
|
||||
PropertyChanges {
|
||||
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.weight: Font.Bold
|
||||
color: Theme.palette.directColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
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 {
|
||||
target: message
|
||||
text: qsTr("You can now use this Keycard as if it\nwas a brand new empty Keycard")
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
text: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard?
|
||||
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
|
||||
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
|
||||
|
||||
ListModel {
|
||||
id: root
|
||||
|
||||
property var words: []
|
||||
|
||||
Component.onCompleted: {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "english.txt");
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
var words = xhr.responseText.split('\n');
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
if (words[i] !== "") {
|
||||
insert(count, {"seedWord": words[i]});
|
||||
root.words = xhr.responseText.split('\n');
|
||||
for (var i = 0; i < root.words.length; i++) {
|
||||
if (root.words[i] !== "") {
|
||||
insert(count, {"seedWord": root.words[i]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,9 +67,16 @@ QtObject {
|
|||
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 string general: "General"
|
||||
readonly property string factoryReset: "FactoryReset"
|
||||
readonly property string setupNewKeycard: "SetupNewKeycard"
|
||||
}
|
||||
|
||||
readonly property QtObject keycardSharedState: QtObject {
|
||||
|
@ -77,12 +84,31 @@ QtObject {
|
|||
readonly property string pluginReader: "PluginReader"
|
||||
readonly property string readingKeycard: "ReadingKeycard"
|
||||
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 wrongPin: "WrongPin"
|
||||
readonly property string maxPinRetriesReached: "MaxPinRetriesReached"
|
||||
readonly property string factoryResetConfirmation: "FactoryResetConfirmation"
|
||||
readonly property string factoryResetConfirmationDisplayMetadata: "FactoryResetConfirmationDisplayMetadata"
|
||||
readonly property string factoryResetSuccess: "FactoryResetSuccess"
|
||||
readonly property string keycardEmptyMetadata: "KeycardEmptyMetadata"
|
||||
readonly property string keycardMetadataDisplay: "KeycardMetadataDisplay"
|
||||
readonly property string keycardEmpty: "KeycardEmpty"
|
||||
readonly property string keycardNotEmpty: "KeycardNotEmpty"
|
||||
readonly property string notKeycard: "NotKeycard"
|
||||
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 {
|
||||
|
@ -339,6 +365,17 @@ QtObject {
|
|||
readonly property int pukCellHeight: 60
|
||||
readonly property int sharedFlowImageWidth: 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 {
|
||||
|
|
Loading…
Reference in New Issue