fix(@desktop/keycard): onboarding flow `I already use Status` -> `Login with Keycard` updated
Onboarding flow updated according to the latest related figma changes.
This commit is contained in:
parent
eb5ad8c911
commit
095578b517
|
@ -19,6 +19,7 @@ type PredefinedKeycardData* {.pure.} = enum
|
|||
OfferPukForUnlock = 16
|
||||
UseUnlockLabelForLockedState = 32
|
||||
UseGeneralMessageForLockedState = 64
|
||||
MaxPUKReached = 128
|
||||
|
||||
# Forward declaration
|
||||
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State
|
||||
|
|
|
@ -209,6 +209,12 @@ proc getSeedPhraseLength*(self: Controller): int =
|
|||
proc setKeyUid*(self: Controller, value: string) =
|
||||
self.tmpKeyUid = value
|
||||
|
||||
proc getKeyUid*(self: Controller): string =
|
||||
self.tmpKeyUid
|
||||
|
||||
proc getKeycardData*(self: Controller): string =
|
||||
return self.delegate.getKeycardData()
|
||||
|
||||
proc setKeycardData*(self: Controller, value: string) =
|
||||
self.delegate.setKeycardData(value)
|
||||
|
||||
|
@ -267,7 +273,7 @@ proc validMnemonic*(self: Controller, mnemonic: string): bool =
|
|||
return true
|
||||
return false
|
||||
|
||||
proc importMnemonic*(self: Controller): bool =
|
||||
proc importMnemonic(self: Controller): bool =
|
||||
let error = self.accountsService.importMnemonic(self.tmpSeedPhrase)
|
||||
if(error.len == 0):
|
||||
self.delegate.importAccountSuccess()
|
||||
|
@ -369,6 +375,10 @@ proc loginAccountKeycard*(self: Controller) =
|
|||
if(error.len > 0):
|
||||
self.delegate.emitAccountLoginError(error)
|
||||
|
||||
proc getKeyUidForSeedPhrase*(self: Controller, seedPhrase: string): string =
|
||||
let acc = self.accountsService.createAccountFromMnemonic(seedPhrase)
|
||||
return acc.keyUid
|
||||
|
||||
proc seedPhraseRefersToSelectedKeyPair*(self: Controller, seedPhrase: string): bool =
|
||||
let selectedAccount = self.getSelectedLoginAccount()
|
||||
let accFromSP = self.accountsService.createAccountFromMnemonic(seedPhrase)
|
||||
|
|
|
@ -14,7 +14,8 @@ method executeBackCommand*(self: KeycardCreatePinState, controller: Controller)
|
|||
controller.setPin("")
|
||||
controller.setPinMatch(false)
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard or
|
||||
self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.cancelCurrentFlow()
|
||||
|
||||
method getNextPrimaryState*(self: KeycardCreatePinState, controller: Controller): State =
|
||||
|
|
|
@ -10,7 +10,8 @@ proc delete*(self: KeycardInsertKeycardState) =
|
|||
|
||||
method executeBackCommand*(self: KeycardInsertKeycardState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard or
|
||||
self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.cancelCurrentFlow()
|
||||
|
||||
method resolveKeycardNextState*(self: KeycardInsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
|
@ -21,9 +22,9 @@ method resolveKeycardNextState*(self: KeycardInsertKeycardState, keycardFlowType
|
|||
if keycardFlowType == ResponseTypeValueInsertCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorConnection:
|
||||
controller.setKeycardData(ResponseTypeValueInsertCard)
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = true))
|
||||
return nil
|
||||
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||
controller.setKeycardData("")
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||
return createState(StateType.KeycardInsertedKeycard, self.flowType, self.getBackState)
|
||||
return nil
|
|
@ -10,7 +10,8 @@ proc delete*(self: KeycardInsertedKeycardState) =
|
|||
|
||||
method executeBackCommand*(self: KeycardInsertedKeycardState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard or
|
||||
self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.cancelCurrentFlow()
|
||||
|
||||
method getNextPrimaryState*(self: KeycardInsertedKeycardState, controller: Controller): State =
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
type
|
||||
KeycardNotKeycardState* = ref object of State
|
||||
KeycardLockedState* = ref object of State
|
||||
|
||||
proc newKeycardNotKeycardState*(flowType: FlowType, backState: State): KeycardNotKeycardState =
|
||||
result = KeycardNotKeycardState()
|
||||
result.setup(flowType, StateType.KeycardNotKeycard, backState)
|
||||
proc newKeycardLockedState*(flowType: FlowType, backState: State): KeycardLockedState =
|
||||
result = KeycardLockedState()
|
||||
result.setup(flowType, StateType.KeycardLocked, backState)
|
||||
|
||||
proc delete*(self: KeycardNotKeycardState) =
|
||||
self.State.delete
|
||||
proc delete*(self: KeycardLockedState) =
|
||||
self.State.delete
|
||||
|
||||
method executePrimaryCommand*(self: KeycardLockedState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys:
|
||||
controller.runFactoryResetPopup()
|
|
@ -8,14 +8,6 @@ proc newKeycardMaxPairingSlotsReachedState*(flowType: FlowType, backState: State
|
|||
proc delete*(self: KeycardMaxPairingSlotsReachedState) =
|
||||
self.State.delete
|
||||
|
||||
method executePrimaryCommand*(self: KeycardMaxPairingSlotsReachedState, controller: Controller) =
|
||||
method getNextPrimaryState*(self: KeycardMaxPairingSlotsReachedState, controller: Controller): State =
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.runFactoryResetPopup()
|
||||
|
||||
method executeSecondaryCommand*(self: KeycardMaxPairingSlotsReachedState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.runRecoverAccountFlow()
|
||||
|
||||
method resolveKeycardNextState*(self: KeycardMaxPairingSlotsReachedState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
return ensureReaderAndCardPresenceAndResolveNextOnboardingState(self, keycardFlowType, keycardEvent, controller)
|
||||
return createState(StateType.KeycardRecover, self.flowType(), self)
|
|
@ -9,4 +9,5 @@ proc delete*(self: KeycardMaxPinRetriesReachedState) =
|
|||
self.State.delete
|
||||
|
||||
method getNextPrimaryState*(self: KeycardMaxPinRetriesReachedState, controller: Controller): State =
|
||||
return createState(StateType.KeycardRecover, self.flowType(), self.getBackState)
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
return createState(StateType.KeycardRecover, self.flowType(), self)
|
|
@ -8,14 +8,6 @@ proc newKeycardMaxPukRetriesReachedState*(flowType: FlowType, backState: State):
|
|||
proc delete*(self: KeycardMaxPukRetriesReachedState) =
|
||||
self.State.delete
|
||||
|
||||
method executePrimaryCommand*(self: KeycardMaxPukRetriesReachedState, controller: Controller) =
|
||||
method getNextPrimaryState*(self: KeycardMaxPukRetriesReachedState, controller: Controller): State =
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.runFactoryResetPopup()
|
||||
|
||||
method executeSecondaryCommand*(self: KeycardMaxPukRetriesReachedState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.runRecoverAccountFlow()
|
||||
|
||||
method resolveKeycardNextState*(self: KeycardMaxPukRetriesReachedState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
return ensureReaderAndCardPresenceAndResolveNextOnboardingState(self, keycardFlowType, keycardEvent, controller)
|
||||
return createState(StateType.KeycardRecover, self.flowType(), self)
|
|
@ -1,13 +1,9 @@
|
|||
type
|
||||
KeycardLockedState* = ref object of State
|
||||
KeycardNotKeycardState* = ref object of State
|
||||
|
||||
proc newKeycardLockedState*(flowType: FlowType, backState: State): KeycardLockedState =
|
||||
result = KeycardLockedState()
|
||||
result.setup(flowType, StateType.KeycardLocked, backState)
|
||||
proc newKeycardNotKeycardState*(flowType: FlowType, backState: State): KeycardNotKeycardState =
|
||||
result = KeycardNotKeycardState()
|
||||
result.setup(flowType, StateType.KeycardNotKeycard, backState)
|
||||
|
||||
proc delete*(self: KeycardLockedState) =
|
||||
self.State.delete
|
||||
|
||||
method executePrimaryCommand*(self: KeycardLockedState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys:
|
||||
controller.runFactoryResetPopup()
|
||||
proc delete*(self: KeycardNotKeycardState) =
|
||||
self.State.delete
|
|
@ -10,7 +10,8 @@ proc delete*(self: KeycardPluginReaderState) =
|
|||
|
||||
method executeBackCommand*(self: KeycardPluginReaderState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard or
|
||||
self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.cancelCurrentFlow()
|
||||
|
||||
method resolveKeycardNextState*(self: KeycardPluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
|
|
|
@ -10,7 +10,8 @@ proc delete*(self: KeycardReadingKeycardState) =
|
|||
|
||||
method executeBackCommand*(self: KeycardReadingKeycardState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard or
|
||||
self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.cancelCurrentFlow()
|
||||
|
||||
method getNextPrimaryState*(self: KeycardReadingKeycardState, controller: Controller): State =
|
||||
|
|
|
@ -10,7 +10,8 @@ proc delete*(self: KeycardRecognizedKeycardState) =
|
|||
|
||||
method executeBackCommand*(self: KeycardRecognizedKeycardState, controller: Controller) =
|
||||
if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard or
|
||||
self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.cancelCurrentFlow()
|
||||
|
||||
method getNextPrimaryState*(self: KeycardRecognizedKeycardState, controller: Controller): State =
|
||||
|
@ -18,3 +19,5 @@ method getNextPrimaryState*(self: KeycardRecognizedKeycardState, controller: Con
|
|||
return createState(StateType.KeycardCreatePin, self.flowType, self.getBackState)
|
||||
if self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, self.getBackState)
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
return createState(StateType.KeycardEnterPin, self.flowType, self.getBackState)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
type
|
||||
KeycardWrongKeycardState* = ref object of State
|
||||
|
||||
proc newKeycardWrongKeycardState*(flowType: FlowType, backState: State): KeycardWrongKeycardState =
|
||||
result = KeycardWrongKeycardState()
|
||||
result.setup(flowType, StateType.KeycardWrongKeycard, backState)
|
||||
|
||||
proc delete*(self: KeycardWrongKeycardState) =
|
||||
self.State.delete
|
|
@ -33,6 +33,7 @@ method resolveKeycardNextState*(self: KeycardWrongPukState, keycardFlowType: str
|
|||
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == RequestParamPUKRetries:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true))
|
||||
return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
controller.setKeycardEvent(keycardEvent)
|
||||
|
|
|
@ -35,9 +35,9 @@ method resolveKeycardNextState*(self: LoginKeycardInsertKeycardState, keycardFlo
|
|||
if keycardFlowType == ResponseTypeValueInsertCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorConnection:
|
||||
controller.setKeycardData(ResponseTypeValueInsertCard)
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = true))
|
||||
return nil
|
||||
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||
controller.setKeycardData("")
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||
return createState(StateType.LoginKeycardReadingKeycard, self.flowType, nil)
|
||||
return nil
|
|
@ -32,6 +32,7 @@ type StateType* {.pure.} = enum
|
|||
KeycardInsertedKeycard = "KeycardInsertedKeycard"
|
||||
KeycardReadingKeycard = "KeycardReadingKeycard"
|
||||
KeycardRecognizedKeycard = "KeycardRecognizedKeycard"
|
||||
KeycardWrongKeycard = "KeycardWrongKeycard"
|
||||
KeycardCreatePin = "KeycardCreatePin"
|
||||
KeycardRepeatPin = "KeycardRepeatPin"
|
||||
KeycardPinSet = "KeycardPinSet"
|
||||
|
|
|
@ -6,6 +6,9 @@ from ../../../../app_service/service/keycard/service import PINLengthForStatusAp
|
|||
from ../../../../app_service/service/keycard/service import PUKLengthForStatusApp
|
||||
import state
|
||||
|
||||
from ../../shared_modules/keycard_popup/internal/state_factory import PredefinedKeycardData
|
||||
from ../../shared_modules/keycard_popup/internal/state_factory import updatePredefinedKeycardData
|
||||
|
||||
logScope:
|
||||
topics = "startup-module-state-factory"
|
||||
|
||||
|
@ -37,6 +40,7 @@ include keycard_reading_keycard_state
|
|||
include keycard_recognized_keycard_state
|
||||
include keycard_recover_state
|
||||
include keycard_repeat_pin_state
|
||||
include keycard_wrong_keycard_state
|
||||
include keycard_wrong_pin_state
|
||||
include keycard_wrong_puk_state
|
||||
include notification_state
|
||||
|
@ -106,6 +110,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
|
|||
return newKeycardWrongPinState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardEnterPuk:
|
||||
return newKeycardEnterPukState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardWrongKeycard:
|
||||
return newKeycardWrongKeycardState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardWrongPuk:
|
||||
return newKeycardWrongPukState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardDisplaySeedPhrase:
|
||||
|
@ -168,7 +174,7 @@ proc ensureReaderAndCardPresenceOnboarding*(state: State, keycardFlowType: strin
|
|||
return nil
|
||||
return createState(StateType.KeycardInsertKeycard, state.flowType, state.getBackState)
|
||||
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||
controller.setKeycardData("")
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||
return createState(StateType.KeycardInsertedKeycard, state.flowType, state.getBackState)
|
||||
|
||||
proc ensureReaderAndCardPresenceLogin*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State =
|
||||
|
@ -186,7 +192,7 @@ proc ensureReaderAndCardPresenceLogin*(state: State, keycardFlowType: string, ke
|
|||
return nil
|
||||
return createState(StateType.LoginKeycardInsertKeycard, state.flowType, state.getBackState)
|
||||
if keycardFlowType == ResponseTypeValueCardInserted:
|
||||
controller.setKeycardData("")
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false))
|
||||
return createState(StateType.LoginKeycardReadingKeycard, state.flowType, state.getBackState)
|
||||
|
||||
proc ensureReaderAndCardPresenceAndResolveNextOnboardingState*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State =
|
||||
|
@ -252,9 +258,11 @@ proc ensureReaderAndCardPresenceAndResolveNextOnboardingState*(state: State, key
|
|||
return createState(StateType.KeycardPinSet, state.flowType, state.getBackState)
|
||||
|
||||
if state.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = false))
|
||||
controller.setKeyUid(keycardEvent.keyUid)
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len == 0:
|
||||
return createState(StateType.KeycardEnterPin, state.flowType, state.getBackState)
|
||||
return createState(StateType.KeycardRecognizedKeycard, state.flowType, state.getBackState)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
|
@ -262,10 +270,11 @@ proc ensureReaderAndCardPresenceAndResolveNextOnboardingState*(state: State, key
|
|||
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorNoKeys:
|
||||
return createState(StateType.KeycardEmpty, state.flowType, state.getBackState)
|
||||
return createState(StateType.KeycardEmpty, state.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == RequestParamPUKRetries:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true))
|
||||
return createState(StateType.KeycardMaxPukRetriesReached, state.flowType, state.getBackState)
|
||||
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||
keycardEvent.error.len > 0 and
|
||||
|
@ -274,7 +283,7 @@ proc ensureReaderAndCardPresenceAndResolveNextOnboardingState*(state: State, key
|
|||
if keycardFlowType == ResponseTypeValueEnterNewPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorRequireInit:
|
||||
return createState(StateType.KeycardCreatePin, state.flowType, state.getBackState)
|
||||
return createState(StateType.KeycardCreatePin, state.flowType, nil)
|
||||
|
||||
if state.flowType == FlowType.AppLogin:
|
||||
if keycardFlowType == ResponseTypeValueSwapCard and
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
type
|
||||
UserProfileEnterSeedPhraseState* = ref object of State
|
||||
successfulImport: bool
|
||||
correctKeycard: bool
|
||||
|
||||
proc newUserProfileEnterSeedPhraseState*(flowType: FlowType, backState: State): UserProfileEnterSeedPhraseState =
|
||||
result = UserProfileEnterSeedPhraseState()
|
||||
result.setup(flowType, StateType.UserProfileEnterSeedPhrase, backState)
|
||||
result.successfulImport = false
|
||||
result.correctKeycard = false
|
||||
|
||||
proc delete*(self: UserProfileEnterSeedPhraseState) =
|
||||
self.State.delete
|
||||
|
@ -20,6 +22,9 @@ method getNextPrimaryState*(self: UserProfileEnterSeedPhraseState, controller: C
|
|||
if self.flowType == FlowType.FirstRunOldUserImportSeedPhrase or
|
||||
self.flowType == FlowType.FirstRunNewUserImportSeedPhrase:
|
||||
return createState(StateType.UserProfileCreate, self.flowType, self)
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
if not self.correctKeycard:
|
||||
return createState(StateType.KeycardWrongKeycard, self.flowType, nil)
|
||||
|
||||
method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller: Controller) =
|
||||
if self.flowType == FlowType.AppLogin:
|
||||
|
@ -28,12 +33,14 @@ method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller:
|
|||
if self.successfulImport:
|
||||
controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), puk = "", factoryReset = true)
|
||||
else:
|
||||
self.successfulImport = controller.importMnemonic()
|
||||
self.successfulImport = controller.validMnemonic(controller.getSeedPhrase())
|
||||
if self.successfulImport:
|
||||
if self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard:
|
||||
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase())
|
||||
elif self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), puk = "", factoryReset = true)
|
||||
if self.flowType == FlowType.FirstRunOldUserKeycardImport:
|
||||
self.correctKeycard = controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getKeyUid()
|
||||
if self.correctKeycard:
|
||||
controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), puk = "", factoryReset = true)
|
||||
|
||||
method resolveKeycardNextState*(self: UserProfileEnterSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
|
|
|
@ -118,6 +118,9 @@ method checkRepeatedKeycardPinWhileTyping*(self: AccessInterface, pin: string):
|
|||
method getSeedPhrase*(self: AccessInterface): string {.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")
|
||||
|
||||
|
|
|
@ -295,6 +295,9 @@ method checkRepeatedKeycardPinWhileTyping*[T](self: Module[T], pin: string): boo
|
|||
method getSeedPhrase*[T](self: Module[T]): string =
|
||||
return self.controller.getSeedPhrase()
|
||||
|
||||
method getKeycardData*[T](self: Module[T]): string =
|
||||
return self.view.getKeycardData()
|
||||
|
||||
method setKeycardData*[T](self: Module[T], value: string) =
|
||||
self.view.setKeycardData(value)
|
||||
|
||||
|
|
|
@ -184,9 +184,7 @@ QtObject:
|
|||
self.startFlow(payload)
|
||||
|
||||
proc startRecoverAccountFlow*(self: Service, seedPhraseLength: int, seedPhrase: string, puk: string, factoryReset: bool) =
|
||||
var payload = %* {
|
||||
RequestParamOverwrite: true
|
||||
}
|
||||
var payload = %* { }
|
||||
if seedPhrase.len > 0 and seedPhraseLength > 0:
|
||||
payload[RequestParamMnemonic] = %* seedPhrase
|
||||
payload[RequestParamMnemonicLen] = %* seedPhraseLength
|
||||
|
|
|
@ -104,6 +104,7 @@ OnboardingBasePage {
|
|||
if (root.startupStore.currentStartupState.stateType === Constants.startupState.keycardNotEmpty ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardNotKeycard ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardEmpty ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardWrongKeycard ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardLocked ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardRecover ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPairingSlotsReached ||
|
||||
|
|
|
@ -29,7 +29,7 @@ Item {
|
|||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
height: Constants.keycard.general.onboardingHeight
|
||||
spacing: Style.current.padding
|
||||
spacing: Style.current.bigPadding
|
||||
|
||||
KeycardImage {
|
||||
id: image
|
||||
|
@ -123,7 +123,7 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: info
|
||||
visible: root.startupStore.startupModuleInst.keycardData !== ""
|
||||
visible: root.startupStore.startupModuleInst.keycardData & Constants.predefinedKeycardData.wronglyInsertedCard
|
||||
text: qsTr("Check the card, it might be wrongly inserted")
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
color: Theme.palette.baseColor1
|
||||
|
|
|
@ -48,7 +48,7 @@ Item {
|
|||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
height: Constants.keycard.general.onboardingHeight
|
||||
spacing: Style.current.padding
|
||||
spacing: Style.current.bigPadding
|
||||
|
||||
KeycardImage {
|
||||
id: image
|
||||
|
|
|
@ -49,120 +49,114 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: footerWrapper.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
height: Constants.keycard.general.onboardingHeight
|
||||
spacing: Style.current.bigPadding
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.current.padding
|
||||
StatusBaseText {
|
||||
id: title
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
font.weight: Font.Bold
|
||||
color: Theme.palette.directColor1
|
||||
text: qsTr("Enter PUK code to recover Keycard")
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: title
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
font.weight: Font.Bold
|
||||
color: Theme.palette.directColor1
|
||||
text: qsTr("Enter PUK code to recover Keycard")
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: d.rowSpacing
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: d.rowSpacing
|
||||
|
||||
Component.onCompleted: {
|
||||
for (var i = 0; i < children.length - 1; ++i) {
|
||||
if(children[i] && children[i].input && children[i+1] && children[i+1].input){
|
||||
children[i].input.tabNavItem = children[i+1].input.edit
|
||||
}
|
||||
}
|
||||
if(children.length > 0){
|
||||
children[0].input.edit.forceActiveFocus()
|
||||
Component.onCompleted: {
|
||||
for (var i = 0; i < children.length - 1; ++i) {
|
||||
if(children[i] && children[i].input && children[i+1] && children[i+1].input){
|
||||
children[i].input.tabNavItem = children[i+1].input.edit
|
||||
}
|
||||
}
|
||||
if(children.length > 0){
|
||||
children[0].input.edit.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: d.pukLength
|
||||
delegate: StatusInput {
|
||||
Layout.preferredWidth: Constants.keycard.general.pukCellWidth
|
||||
Layout.preferredHeight: Constants.keycard.general.pukCellHeight
|
||||
input.acceptReturn: true
|
||||
validators: [
|
||||
StatusRegularExpressionValidator {
|
||||
regularExpression: /[0-9]/
|
||||
errorMessage: ""
|
||||
},
|
||||
StatusMinLengthValidator {
|
||||
minLength: 1
|
||||
errorMessage: ""
|
||||
}
|
||||
]
|
||||
|
||||
onTextChanged: {
|
||||
text = text.trim()
|
||||
if(text.length >= 1) {
|
||||
text = text.charAt(0);
|
||||
}
|
||||
if(Utils.isDigit(text)) {
|
||||
let nextInd = index+1
|
||||
if(nextInd <= rowLayout.children.length - 1 &&
|
||||
rowLayout.children[nextInd] &&
|
||||
rowLayout.children[nextInd].input){
|
||||
rowLayout.children[nextInd].input.edit.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
else {
|
||||
text = ""
|
||||
}
|
||||
d.pukArray[index] = text
|
||||
d.updateValidity()
|
||||
Repeater {
|
||||
model: d.pukLength
|
||||
delegate: StatusInput {
|
||||
Layout.preferredWidth: Constants.keycard.general.pukCellWidth
|
||||
Layout.preferredHeight: Constants.keycard.general.pukCellHeight
|
||||
input.acceptReturn: true
|
||||
validators: [
|
||||
StatusRegularExpressionValidator {
|
||||
regularExpression: /[0-9]/
|
||||
errorMessage: ""
|
||||
},
|
||||
StatusMinLengthValidator {
|
||||
minLength: 1
|
||||
errorMessage: ""
|
||||
}
|
||||
]
|
||||
|
||||
onKeyPressed: {
|
||||
if(input.edit.keyEvent === Qt.Key_Backspace){
|
||||
if (text == ""){
|
||||
let prevInd = index-1
|
||||
if(prevInd >= 0){
|
||||
rowLayout.children[prevInd].input.edit.forceActiveFocus()
|
||||
}
|
||||
onTextChanged: {
|
||||
text = text.trim()
|
||||
if(text.length >= 1) {
|
||||
text = text.charAt(0);
|
||||
}
|
||||
if(Utils.isDigit(text)) {
|
||||
let nextInd = index+1
|
||||
if(nextInd <= rowLayout.children.length - 1 &&
|
||||
rowLayout.children[nextInd] &&
|
||||
rowLayout.children[nextInd].input){
|
||||
rowLayout.children[nextInd].input.edit.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
else {
|
||||
text = ""
|
||||
}
|
||||
d.pukArray[index] = text
|
||||
d.updateValidity()
|
||||
}
|
||||
|
||||
onKeyPressed: {
|
||||
if(input.edit.keyEvent === Qt.Key_Backspace){
|
||||
if (text == ""){
|
||||
let prevInd = index-1
|
||||
if(prevInd >= 0){
|
||||
rowLayout.children[prevInd].input.edit.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
else if (input.edit.keyEvent === Qt.Key_Return ||
|
||||
input.edit.keyEvent === Qt.Key_Enter) {
|
||||
if(d.allEntriesValid) {
|
||||
event.accepted = true
|
||||
d.submitPuk()
|
||||
}
|
||||
}
|
||||
else if (input.edit.keyEvent === Qt.Key_Return ||
|
||||
input.edit.keyEvent === Qt.Key_Enter) {
|
||||
if(d.allEntriesValid) {
|
||||
event.accepted = true
|
||||
d.submitPuk()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
id: info
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
color: Theme.palette.dangerColor1
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: footerWrapper
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: Constants.keycard.general.footerWrapperHeight
|
||||
StatusBaseText {
|
||||
id: info
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
color: Theme.palette.dangerColor1
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Style.current.padding
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
enabled: d.allEntriesValid
|
||||
text: qsTr("Recover Keycard")
|
||||
onClicked: {
|
||||
|
|
|
@ -20,7 +20,7 @@ Item {
|
|||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
height: Constants.keycard.general.onboardingHeight
|
||||
spacing: Style.current.padding
|
||||
spacing: Style.current.bigPadding
|
||||
|
||||
KeycardImage {
|
||||
id: image
|
||||
|
@ -37,7 +37,9 @@ Item {
|
|||
|
||||
StatusBaseText {
|
||||
id: info
|
||||
visible: text.length > 0
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
|
@ -74,6 +76,7 @@ Item {
|
|||
|
||||
StatusBaseText {
|
||||
id: message
|
||||
visible: text.length > 0
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
@ -131,12 +134,14 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: title
|
||||
text: ""
|
||||
text: qsTr("Keycard is empty")
|
||||
color: Theme.palette.directColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: info
|
||||
text: qsTr("The keycard is empty")
|
||||
color: Theme.palette.dangerColor1
|
||||
text: qsTr("There is no key pair on this Keycard")
|
||||
color: Theme.palette.directColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
}
|
||||
PropertyChanges {
|
||||
|
@ -232,8 +237,11 @@ Item {
|
|||
}
|
||||
},
|
||||
State {
|
||||
name: Constants.startupState.keycardMaxPairingSlotsReached
|
||||
when: root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPairingSlotsReached
|
||||
name: "lockedState"
|
||||
when: root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPinRetriesReached ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPukRetriesReached ||
|
||||
root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPairingSlotsReached
|
||||
|
||||
PropertyChanges {
|
||||
target: image
|
||||
pattern: "keycard/strong_error/img-%1"
|
||||
|
@ -252,92 +260,24 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: info
|
||||
text: qsTr("Max pairing slots reached for this keycard")
|
||||
text: {
|
||||
let t = qsTr("You will need to unlock it before proceeding")
|
||||
if (root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPinRetriesReached)
|
||||
t += qsTr("\nMax PIN retries reached for this keycard")
|
||||
if (root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPukRetriesReached)
|
||||
t += qsTr("\nMax PUK retries reached for this keycard")
|
||||
if (root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPairingSlotsReached)
|
||||
t += qsTr("\nMax pairing slots reached for this keycard")
|
||||
return t
|
||||
}
|
||||
color: Theme.palette.dangerColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
}
|
||||
PropertyChanges {
|
||||
target: button
|
||||
text: qsTr("Factory reset")
|
||||
text: qsTr("Unlock Keycard")
|
||||
type: StatusBaseButton.Type.Normal
|
||||
}
|
||||
PropertyChanges {
|
||||
target: link
|
||||
text: qsTr("Insert another Keycard")
|
||||
color: Theme.palette.primaryColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
text: ""
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: Constants.startupState.keycardMaxPukRetriesReached
|
||||
when: root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPukRetriesReached
|
||||
PropertyChanges {
|
||||
target: image
|
||||
pattern: "keycard/strong_error/img-%1"
|
||||
source: ""
|
||||
startImgIndexForTheFirstLoop: 0
|
||||
startImgIndexForOtherLoops: 18
|
||||
endImgIndex: 29
|
||||
duration: 1300
|
||||
loops: -1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: title
|
||||
text: qsTr("Keycard locked")
|
||||
color: Theme.palette.dangerColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: info
|
||||
text: qsTr("Max PUK retries reached for this keycard")
|
||||
color: Theme.palette.dangerColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
}
|
||||
PropertyChanges {
|
||||
target: button
|
||||
text: qsTr("Factory reset")
|
||||
type: StatusBaseButton.Type.Normal
|
||||
}
|
||||
PropertyChanges {
|
||||
target: link
|
||||
text: qsTr("Insert another Keycard")
|
||||
color: Theme.palette.primaryColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
text: ""
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: Constants.startupState.keycardMaxPinRetriesReached
|
||||
when: root.startupStore.currentStartupState.stateType === Constants.startupState.keycardMaxPinRetriesReached
|
||||
PropertyChanges {
|
||||
target: image
|
||||
pattern: "keycard/strong_error/img-%1"
|
||||
source: ""
|
||||
startImgIndexForTheFirstLoop: 0
|
||||
startImgIndexForOtherLoops: 18
|
||||
endImgIndex: 29
|
||||
duration: 1300
|
||||
loops: -1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: title
|
||||
text: ""
|
||||
}
|
||||
PropertyChanges {
|
||||
target: info
|
||||
text: qsTr("Keycard locked")
|
||||
color: Theme.palette.dangerColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: button
|
||||
text: qsTr("Recover your Keycard")
|
||||
type: StatusBaseButton.Type.Danger
|
||||
}
|
||||
PropertyChanges {
|
||||
target: link
|
||||
text: ""
|
||||
|
@ -362,7 +302,7 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: title
|
||||
text: qsTr("Recover your Keycard")
|
||||
text: qsTr("Unlock this Keycard")
|
||||
color: Theme.palette.directColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
}
|
||||
|
@ -372,18 +312,59 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: button
|
||||
text: qsTr("Recover with seed phrase")
|
||||
type: StatusBaseButton.Type.Danger
|
||||
text: qsTr("Unlock using seed phrase")
|
||||
type: StatusBaseButton.Type.Normal
|
||||
}
|
||||
PropertyChanges {
|
||||
target: link
|
||||
text: qsTr("Recover with PUK")
|
||||
color: Theme.palette.dangerColor1
|
||||
text: qsTr("Unlock using PUK")
|
||||
enabled: !(root.startupStore.startupModuleInst.keycardData & Constants.predefinedKeycardData.maxPUKReached)
|
||||
color: !enabled? Theme.palette.baseColor1 : Theme.palette.primaryColor1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
text: ""
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: Constants.startupState.keycardWrongKeycard
|
||||
when: root.startupStore.currentStartupState.stateType === Constants.startupState.keycardWrongKeycard
|
||||
PropertyChanges {
|
||||
target: image
|
||||
pattern: "keycard/strong_error/img-%1"
|
||||
source: ""
|
||||
startImgIndexForTheFirstLoop: 0
|
||||
startImgIndexForOtherLoops: 18
|
||||
endImgIndex: 29
|
||||
duration: 1300
|
||||
loops: -1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: title
|
||||
text: qsTr("Wrong Keycard inserted")
|
||||
color: Theme.palette.dangerColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: info
|
||||
text: qsTr("The card inserted is not linked to your profile.")
|
||||
color: Theme.palette.dangerColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize2
|
||||
}
|
||||
PropertyChanges {
|
||||
target: button
|
||||
text: ""
|
||||
}
|
||||
PropertyChanges {
|
||||
target: link
|
||||
text: ""
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
text: qsTr("Remove Keycard and try again")
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -615,7 +615,7 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
visible: root.startupStore.startupModuleInst.keycardData !== ""
|
||||
visible: root.startupStore.startupModuleInst.keycardData & Constants.predefinedKeycardData.wronglyInsertedCard
|
||||
text: qsTr("Check the card, it might be wrongly inserted")
|
||||
font.pixelSize: Constants.keycard.general.fontSize3
|
||||
color: Theme.palette.baseColor1
|
||||
|
|
|
@ -42,7 +42,7 @@ Item {
|
|||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
height: Constants.keycard.general.onboardingHeight
|
||||
spacing: Style.current.padding
|
||||
spacing: Style.current.bigPadding
|
||||
|
||||
StatusBaseText {
|
||||
id: title
|
||||
|
|
|
@ -67,7 +67,7 @@ Item {
|
|||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
height: Constants.keycard.general.onboardingHeight
|
||||
spacing: Style.current.padding
|
||||
spacing: Style.current.bigPadding
|
||||
|
||||
StatusBaseText {
|
||||
id: title
|
||||
|
|
|
@ -42,6 +42,7 @@ QtObject {
|
|||
readonly property string keycardInsertedKeycard: "KeycardInsertedKeycard"
|
||||
readonly property string keycardReadingKeycard: "KeycardReadingKeycard"
|
||||
readonly property string keycardRecognizedKeycard: "KeycardRecognizedKeycard"
|
||||
readonly property string keycardWrongKeycard: "KeycardWrongKeycard"
|
||||
readonly property string keycardCreatePin: "KeycardCreatePin"
|
||||
readonly property string keycardRepeatPin: "KeycardRepeatPin"
|
||||
readonly property string keycardPinSet: "KeycardPinSet"
|
||||
|
@ -80,6 +81,7 @@ QtObject {
|
|||
readonly property int offerPukForUnlock: 16
|
||||
readonly property int useUnlockLabelForLockedState: 32
|
||||
readonly property int useGeneralMessageForLockedState: 64
|
||||
readonly property int maxPUKReached: 128
|
||||
}
|
||||
|
||||
readonly property QtObject keycardSharedFlow: QtObject {
|
||||
|
|
Loading…
Reference in New Issue