fix(wallet): user is unable to authenticate using biometrics
Fixes #14404
This commit is contained in:
parent
3f41db0efc
commit
42a60642e8
|
@ -0,0 +1,9 @@
|
|||
type
|
||||
KeycardFlowStartedState* = ref object of State
|
||||
|
||||
proc newKeycardFlowStartedState*(flowType: FlowType, backState: State): KeycardFlowStartedState =
|
||||
result = KeycardFlowStartedState()
|
||||
result.setup(flowType, StateType.KeycardFlowStarted, backState)
|
||||
|
||||
proc delete*(self: KeycardFlowStartedState) =
|
||||
self.State.delete
|
|
@ -6,6 +6,7 @@ export FlowType, KeycardEvent, KeyDetails
|
|||
|
||||
type StateType* {.pure.} = enum
|
||||
NoState = "NoState"
|
||||
KeycardFlowStarted = "KeycardFlowStarted"
|
||||
Biometrics = "Biometrics"
|
||||
NoPCSCService = "NoPCSCService"
|
||||
PluginReader = "PluginReader"
|
||||
|
|
|
@ -87,6 +87,7 @@ include keycard_create_account_old_seed_phrase_failure_state
|
|||
include keycard_create_account_old_seed_phrase_success_state
|
||||
include keycard_empty_metadata_state
|
||||
include keycard_empty_state
|
||||
include keycard_flow_started_state
|
||||
include keycard_inserted_state
|
||||
include keycard_metadata_display_state
|
||||
include keycard_not_empty_state
|
||||
|
|
|
@ -119,6 +119,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
|
|||
return newCreatingAccountOldSeedPhraseFailureState(flowType, backState)
|
||||
if stateToBeCreated == StateType.CreatingAccountOldSeedPhraseSuccess:
|
||||
return newCreatingAccountOldSeedPhraseSuccessState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardFlowStarted:
|
||||
return newKeycardFlowStartedState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardInserted:
|
||||
return newKeycardInsertedState(flowType, backState)
|
||||
if stateToBeCreated == StateType.KeycardEmptyMetadata:
|
||||
|
|
|
@ -497,11 +497,14 @@ method prepareKeyPairForProcessing*[T](self: Module[T], keyUid: string, keycardU
|
|||
item.setIcon("keycard")
|
||||
self.view.setKeyPairForProcessing(item)
|
||||
|
||||
proc displayReadingState[T](self: Module[T], flowType: FlowType, backState: State) =
|
||||
proc displayKeycardFlowStartedState[T](self: Module[T], flowType: FlowType, backState: State, displayStartedState: bool = true) =
|
||||
self.tmpLocalState = newReadingKeycardState(flowType, backState)
|
||||
self.view.setCurrentState(self.tmpLocalState)
|
||||
if not displayStartedState:
|
||||
return
|
||||
let keycardFlowStartedState = newKeycardFlowStartedState(flowType, backState)
|
||||
self.view.setCurrentState(keycardFlowStartedState)
|
||||
self.controller.readyToDisplayPopup()
|
||||
debug "sm_cannot - display reading state", setCurrFlow=self.tmpLocalState.flowType(), setCurrState=self.tmpLocalState.stateType()
|
||||
debug "sm_cannot - display reading state", setCurrFlow=keycardFlowStartedState.flowType(), setCurrState=keycardFlowStartedState.stateType()
|
||||
|
||||
method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths: seq[string] = @[], txHash = "", forceFlow = false, returnToFlow = FlowType.General) =
|
||||
## In case of `Authentication` or `Sign` flow, if keyUid is provided, that keypair will be authenticated,
|
||||
|
@ -525,7 +528,7 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
if flowToRun == FlowType.FactoryReset:
|
||||
if keyUid.len > 0:
|
||||
self.prepareKeyPairForProcessing(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true)
|
||||
return
|
||||
if flowToRun == FlowType.SetupNewKeycard:
|
||||
|
@ -542,7 +545,7 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
return
|
||||
self.setSelectedKeyPair(filteredItems[0])
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runLoadAccountFlow()
|
||||
return
|
||||
if flowToRun == FlowType.Authentication:
|
||||
|
@ -550,7 +553,7 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
if keyUid.len == 0 or keyUid == singletonInstance.userProfile.getKeyUid():
|
||||
if singletonInstance.userProfile.getIsKeycardUser():
|
||||
self.prepareKeyPairItemForAuthentication(singletonInstance.userProfile.getKeyUid())
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runAuthenticationFlow(singletonInstance.userProfile.getKeyUid(), bip44Paths)
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
self.controller.connectKeychainSignals()
|
||||
|
@ -558,7 +561,7 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
return
|
||||
self.view.setCurrentState(newEnterPasswordState(flowToRun, nil))
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil, displayStartedState = false)
|
||||
self.controller.connectKeychainSignals()
|
||||
self.controller.tryToObtainDataFromKeychain()
|
||||
else:
|
||||
|
@ -567,7 +570,7 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
return
|
||||
else:
|
||||
self.prepareKeyPairItemForAuthentication(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runAuthenticationFlow(keyUid, bip44Paths)
|
||||
return
|
||||
if flowToRun == FlowType.Sign:
|
||||
|
@ -593,7 +596,7 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
return
|
||||
self.runningFlow = flowToRun
|
||||
self.prepareKeyPairItemForAuthentication(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runSignFlow(keyUid, bip44Paths[0], txHash)
|
||||
if finalKeyUid == singletonInstance.userProfile.getKeyUid() and
|
||||
singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
|
@ -604,48 +607,48 @@ proc proceedWithRunFlow[T](self: Module[T], flowToRun: FlowType, keyUid: string,
|
|||
## since we can run unlock keycard flow from an already running flow, in order to avoid changing displayed keypair
|
||||
## (locked keypair) we have to set keycard uid of a keycard used in the flow we're jumping from to `UnlockKeycard` flow.
|
||||
self.prepareKeyPairForProcessing(keyUid, self.controller.getKeycardUid())
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true)
|
||||
return
|
||||
if flowToRun == FlowType.DisplayKeycardContent:
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true)
|
||||
return
|
||||
if flowToRun == FlowType.RenameKeycard:
|
||||
self.prepareKeyPairForProcessing(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true) # we're firstly displaying the keycard content
|
||||
return
|
||||
if flowToRun == FlowType.ChangeKeycardPin:
|
||||
self.prepareKeyPairForProcessing(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runChangePinFlow()
|
||||
return
|
||||
if flowToRun == FlowType.ChangeKeycardPuk:
|
||||
self.prepareKeyPairForProcessing(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runChangePukFlow()
|
||||
return
|
||||
if flowToRun == FlowType.ChangePairingCode:
|
||||
self.prepareKeyPairForProcessing(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runChangePairingFlow()
|
||||
return
|
||||
if flowToRun == FlowType.CreateCopyOfAKeycard:
|
||||
self.prepareKeyPairForProcessing(keyUid)
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true)
|
||||
return
|
||||
if flowToRun == FlowType.SetupNewKeycardNewSeedPhrase:
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runLoadAccountFlow()
|
||||
return
|
||||
if flowToRun == FlowType.SetupNewKeycardOldSeedPhrase:
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runLoadAccountFlow()
|
||||
return
|
||||
if flowToRun == FlowType.ImportFromKeycard:
|
||||
self.displayReadingState(flowToRun, nil)
|
||||
self.displayKeycardFlowStartedState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true, exportMasterAddr = true)
|
||||
return
|
||||
if flowToRun == FlowType.MigrateFromKeycardToApp:
|
||||
|
|
|
@ -23,6 +23,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
sourceComponent: {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.biometrics:
|
||||
case Constants.keycardSharedState.noPCSCService:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
|
|
|
@ -23,6 +23,7 @@ QtObject {
|
|||
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.recognizedKeycard:
|
||||
|
@ -104,6 +105,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.setupNewKeycardNewSeedPhrase:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -130,6 +132,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.setupNewKeycardOldSeedPhrase:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -157,6 +160,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.importFromKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -176,6 +180,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.factoryReset:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -198,6 +203,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.authentication:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -224,6 +230,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -245,6 +252,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -265,6 +273,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.displayKeycardContent:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -283,6 +292,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.renameKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -302,6 +312,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.changeKeycardPin:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -322,6 +333,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.changeKeycardPuk:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -342,6 +354,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.changePairingCode:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -361,6 +374,7 @@ QtObject {
|
|||
|
||||
case Constants.keycardSharedFlow.createCopyOfAKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -435,6 +449,7 @@ QtObject {
|
|||
case Constants.keycardSharedState.wrongPin:
|
||||
return qsTr("Use biometrics")
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
|
@ -461,6 +476,7 @@ QtObject {
|
|||
case Constants.keycardSharedState.wrongPin:
|
||||
return qsTr("Use biometrics")
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
|
@ -622,6 +638,7 @@ QtObject {
|
|||
case Constants.keycardSharedFlow.setupNewKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -831,6 +848,7 @@ QtObject {
|
|||
case Constants.keycardSharedFlow.authentication:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -870,6 +888,7 @@ QtObject {
|
|||
case Constants.keycardSharedFlow.sign:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
|
@ -1364,6 +1383,7 @@ QtObject {
|
|||
if (userProfile.usingBiometricLogin) {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
|
@ -1383,6 +1403,7 @@ QtObject {
|
|||
if (userProfile.usingBiometricLogin) {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardFlowStarted:
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
|
|
|
@ -41,7 +41,8 @@ Item {
|
|||
|
||||
readonly property bool hideKeyPair: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.hideKeyPair
|
||||
readonly property bool copyFromAKeycardPartDone: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.copyFromAKeycardPartDone
|
||||
readonly property bool continuousProcessingAnimation: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
|
||||
readonly property bool continuousProcessingAnimation: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardFlowStarted ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToApp ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountNewSeedPhrase ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountOldSeedPhrase ||
|
||||
|
@ -637,7 +638,8 @@ Item {
|
|||
},
|
||||
State {
|
||||
name: d.processingStateName
|
||||
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardFlowStarted ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToApp ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountNewSeedPhrase ||
|
||||
|
@ -652,6 +654,9 @@ Item {
|
|||
PropertyChanges {
|
||||
target: title
|
||||
text: {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardFlowStarted) {
|
||||
return qsTr("Starting...")
|
||||
}
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard) {
|
||||
return qsTr("Reading Keycard...")
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ QtObject {
|
|||
}
|
||||
|
||||
readonly property QtObject keycardSharedState: QtObject {
|
||||
readonly property string keycardFlowStarted: "KeycardFlowStarted"
|
||||
readonly property string biometrics: "Biometrics"
|
||||
readonly property string noPCSCService: "NoPCSCService"
|
||||
readonly property string noState: "NoState"
|
||||
|
|
Loading…
Reference in New Issue