fix(@desktop/keycard): migrating keypair looks somehow stucked for a while before switching to `Migrating key pair to Keycard` state
Fixes: #8177
This commit is contained in:
parent
db7769b072
commit
557703543c
|
@ -138,7 +138,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
|||
result.nodeConfigurationService = node_configuration_service.newService(statusFoundation.fleetConfiguration,
|
||||
result.settingsService)
|
||||
result.keychainService = keychain_service.newService(statusFoundation.events)
|
||||
result.accountsService = accounts_service.newService(statusFoundation.fleetConfiguration)
|
||||
result.accountsService = accounts_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||
statusFoundation.fleetConfiguration)
|
||||
result.networkService = network_service.newService(statusFoundation.events, result.settingsService)
|
||||
result.contactsService = contacts_service.newService(
|
||||
statusFoundation.events, statusFoundation.threadpool, result.networkService, result.settingsService,
|
||||
|
|
|
@ -49,6 +49,8 @@ proc init*(self: Controller) =
|
|||
|
||||
self.events.on(SIGNAL_NEW_KEYCARD_SET) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
if not args.success:
|
||||
return
|
||||
self.delegate.onNewKeycardSet(args.keyPair)
|
||||
|
||||
self.events.on(SIGNAL_KEYCARD_LOCKED) do(e: Args):
|
||||
|
|
|
@ -167,6 +167,9 @@ method load*(self: Module) =
|
|||
self.refreshWalletAccounts()
|
||||
|
||||
self.events.on(SIGNAL_NEW_KEYCARD_SET) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
if not args.success:
|
||||
return
|
||||
self.refreshWalletAccounts()
|
||||
|
||||
self.controller.init()
|
||||
|
|
|
@ -51,6 +51,8 @@ type
|
|||
tmpUsePinFromBiometrics: bool
|
||||
tmpOfferToStoreUpdatedPinToKeychain: bool
|
||||
tmpKeycardUid: string
|
||||
tmpAddingMigratedKeypairSuccess: bool
|
||||
tmpConvertingProfileSuccess: bool
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface,
|
||||
uniqueIdentifier: string,
|
||||
|
@ -78,6 +80,8 @@ proc newController*(delegate: io_interface.AccessInterface,
|
|||
result.tmpSeedPhraseLength = 0
|
||||
result.tmpSelectedKeyPairIsProfile = false
|
||||
result.tmpUsePinFromBiometrics = false
|
||||
result.tmpAddingMigratedKeypairSuccess = false
|
||||
result.tmpConvertingProfileSuccess = false
|
||||
|
||||
proc serviceApplicable[T](service: T): bool =
|
||||
if not service.isNil:
|
||||
|
@ -141,6 +145,16 @@ proc init*(self: Controller) =
|
|||
self.delegate.onUserAuthenticated(args.password, args.pin)
|
||||
self.connectionIds.add(handlerId)
|
||||
|
||||
self.events.on(SIGNAL_NEW_KEYCARD_SET) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
self.tmpAddingMigratedKeypairSuccess = args.success
|
||||
self.delegate.onSecondaryActionClicked()
|
||||
|
||||
self.events.on(SIGNAL_CONVERTING_PROFILE_KEYPAIR) do(e: Args):
|
||||
let args = ResultArgs(e)
|
||||
self.tmpConvertingProfileSuccess = args.success
|
||||
self.delegate.onSecondaryActionClicked()
|
||||
|
||||
proc getKeycardData*(self: Controller): string =
|
||||
return self.delegate.getKeycardData()
|
||||
|
||||
|
@ -289,15 +303,18 @@ proc verifyPassword*(self: Controller, password: string): bool =
|
|||
return
|
||||
return self.accountsService.verifyPassword(password)
|
||||
|
||||
proc convertSelectedKeyPairToKeycardAccount*(self: Controller, password: string): bool =
|
||||
proc convertSelectedKeyPairToKeycardAccount*(self: Controller, password: string) =
|
||||
if not serviceApplicable(self.accountsService):
|
||||
return
|
||||
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true)
|
||||
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
|
||||
return self.accountsService.convertToKeycardAccount(self.tmpSelectedKeyPairDto.keyUid,
|
||||
self.accountsService.convertToKeycardAccount(self.tmpSelectedKeyPairDto.keyUid,
|
||||
currentPassword = password,
|
||||
newPassword = acc.derivedAccounts.encryption.publicKey)
|
||||
|
||||
proc getConvertingProfileSuccess*(self: Controller): bool =
|
||||
return self.tmpConvertingProfileSuccess
|
||||
|
||||
proc getLoggedInAccount*(self: Controller): AccountDto =
|
||||
if not serviceApplicable(self.accountsService):
|
||||
return
|
||||
|
@ -429,8 +446,8 @@ proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool) =
|
|||
let (_, flowEvent) = self.getLastReceivedKeycardData()
|
||||
var data = SharedKeycarModuleFlowTerminatedArgs(uniqueIdentifier: self.uniqueIdentifier,
|
||||
lastStepInTheCurrentFlow: lastStepInTheCurrentFlow)
|
||||
let exportedEncryptionPubKey = flowEvent.generatedWalletAccount.publicKey
|
||||
if lastStepInTheCurrentFlow:
|
||||
let exportedEncryptionPubKey = flowEvent.generatedWalletAccount.publicKey
|
||||
data.password = if exportedEncryptionPubKey.len > 0: exportedEncryptionPubKey else: self.getPassword()
|
||||
data.pin = self.getPin()
|
||||
data.keyUid = flowEvent.keyUid
|
||||
|
@ -452,13 +469,16 @@ proc getBalanceForAddress*(self: Controller, address: string): float64 =
|
|||
return
|
||||
return self.walletAccountService.fetchBalanceForAddress(address)
|
||||
|
||||
proc addMigratedKeyPair*(self: Controller, keyPair: KeyPairDto): bool =
|
||||
proc addMigratedKeyPair*(self: Controller, keyPair: KeyPairDto) =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
return
|
||||
if not serviceApplicable(self.accountsService):
|
||||
return
|
||||
let keystoreDir = self.accountsService.getKeyStoreDir()
|
||||
return self.walletAccountService.addMigratedKeyPair(keyPair, keystoreDir)
|
||||
self.walletAccountService.addMigratedKeyPairAsync(keyPair, keystoreDir)
|
||||
|
||||
proc getAddingMigratedKeypairSuccess*(self: Controller): bool =
|
||||
return self.tmpAddingMigratedKeypairSuccess
|
||||
|
||||
proc getAllMigratedKeyPairs*(self: Controller): seq[KeyPairDto] =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
|
|
|
@ -1,33 +1,36 @@
|
|||
type
|
||||
MigratingKeyPairState* = ref object of State
|
||||
migrationSuccess: bool
|
||||
authenticationDone: bool
|
||||
authenticationOk: bool
|
||||
addingMigratedKeypairDone: bool
|
||||
addingMigratedKeypairOk: bool
|
||||
profileConversionDone: bool
|
||||
profileConversionOk: bool
|
||||
|
||||
proc newMigratingKeyPairState*(flowType: FlowType, backState: State): MigratingKeyPairState =
|
||||
result = MigratingKeyPairState()
|
||||
result.setup(flowType, StateType.MigratingKeyPair, backState)
|
||||
result.migrationSuccess = false
|
||||
result.authenticationDone = false
|
||||
result.authenticationOk = false
|
||||
result.addingMigratedKeypairDone = false
|
||||
result.addingMigratedKeypairOk = false
|
||||
result.profileConversionDone = false
|
||||
result.profileConversionOk = false
|
||||
|
||||
proc delete*(self: MigratingKeyPairState) =
|
||||
self.State.delete
|
||||
|
||||
proc doMigration(self: MigratingKeyPairState, controller: Controller) =
|
||||
if self.flowType == FlowType.SetupNewKeycard:
|
||||
let password = controller.getPassword()
|
||||
controller.setPassword("")
|
||||
if controller.getSelectedKeyPairIsProfile():
|
||||
self.migrationSuccess = controller.verifyPassword(password)
|
||||
if not self.migrationSuccess:
|
||||
return
|
||||
let selectedKeyPairDto = controller.getSelectedKeyPairDto()
|
||||
self.migrationSuccess = controller.addMigratedKeyPair(selectedKeyPairDto)
|
||||
if not self.migrationSuccess:
|
||||
return
|
||||
if controller.getSelectedKeyPairIsProfile():
|
||||
self.migrationSuccess = self.migrationSuccess and controller.convertSelectedKeyPairToKeycardAccount(password)
|
||||
if not self.migrationSuccess:
|
||||
return
|
||||
controller.runStoreMetadataFlow(selectedKeyPairDto.keycardName, controller.getPin(),
|
||||
controller.getSelectedKeyPairWalletPaths())
|
||||
controller.addMigratedKeyPair(selectedKeyPairDto)
|
||||
|
||||
proc doConversion(self: MigratingKeyPairState, controller: Controller) =
|
||||
let password = controller.getPassword()
|
||||
controller.convertSelectedKeyPairToKeycardAccount(password)
|
||||
|
||||
proc runStoreMetadataFlow(self: MigratingKeyPairState, controller: Controller) =
|
||||
let selectedKeyPairDto = controller.getSelectedKeyPairDto()
|
||||
controller.runStoreMetadataFlow(selectedKeyPairDto.keycardName, controller.getPin(), controller.getSelectedKeyPairWalletPaths())
|
||||
|
||||
method executePrePrimaryStateCommand*(self: MigratingKeyPairState, controller: Controller) =
|
||||
if self.flowType == FlowType.SetupNewKeycard:
|
||||
|
@ -37,12 +40,39 @@ method executePrePrimaryStateCommand*(self: MigratingKeyPairState, controller: C
|
|||
self.doMigration(controller)
|
||||
|
||||
method executePreSecondaryStateCommand*(self: MigratingKeyPairState, controller: Controller) =
|
||||
## Secondary action is called after each async action during migration process.
|
||||
if self.flowType == FlowType.SetupNewKeycard:
|
||||
if controller.getSelectedKeyPairIsProfile():
|
||||
if not self.authenticationDone:
|
||||
self.authenticationDone = true
|
||||
let password = controller.getPassword()
|
||||
self.authenticationOk = controller.verifyPassword(password)
|
||||
if self.authenticationOk:
|
||||
self.doMigration(controller)
|
||||
return
|
||||
if not self.addingMigratedKeypairDone:
|
||||
self.addingMigratedKeypairDone = true
|
||||
self.addingMigratedKeypairOk = controller.getAddingMigratedKeypairSuccess()
|
||||
if self.addingMigratedKeypairOk:
|
||||
self.doConversion(controller)
|
||||
return
|
||||
if not self.profileConversionDone:
|
||||
self.profileConversionDone = true
|
||||
self.profileConversionOk = controller.getConvertingProfileSuccess()
|
||||
if self.profileConversionOk:
|
||||
self.runStoreMetadataFlow(controller)
|
||||
else:
|
||||
if not self.addingMigratedKeypairDone:
|
||||
self.addingMigratedKeypairDone = true
|
||||
self.addingMigratedKeypairOk = controller.getAddingMigratedKeypairSuccess()
|
||||
if self.addingMigratedKeypairOk:
|
||||
self.runStoreMetadataFlow(controller)
|
||||
|
||||
method getNextSecondaryState*(self: MigratingKeyPairState, controller: Controller): State =
|
||||
if self.flowType == FlowType.SetupNewKeycard:
|
||||
if not self.migrationSuccess:
|
||||
if self.authenticationDone and not self.authenticationOk or
|
||||
self.addingMigratedKeypairDone and not self.addingMigratedKeypairOk or
|
||||
self.profileConversionDone and not self.profileConversionOk:
|
||||
return createState(StateType.KeyPairMigrateFailure, self.flowType, nil)
|
||||
|
||||
method resolveKeycardNextState*(self: MigratingKeyPairState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#################################################
|
||||
# Async convert profile keypair
|
||||
#################################################
|
||||
|
||||
type
|
||||
ConvertToKeycardAccountTaskArg* = ref object of QObjectTaskArg
|
||||
accountDataJson: JsonNode
|
||||
settingsJson: JsonNode
|
||||
hashedCurrentPassword: string
|
||||
newPassword: string
|
||||
keyStoreDir: string
|
||||
|
||||
const convertToKeycardAccountTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[ConvertToKeycardAccountTaskArg](argEncoded)
|
||||
try:
|
||||
let response = status_account.convertToKeycardAccount(arg.keyStoreDir, arg.accountDataJson, arg.settingsJson,
|
||||
arg.hashedCurrentPassword, arg.newPassword)
|
||||
arg.finish(response)
|
||||
except Exception as e:
|
||||
error "error converting profile keypair: ", message = e.msg
|
||||
arg.finish("")
|
|
@ -8,6 +8,9 @@ from ../keycard/service import KeycardEvent, KeyDetails
|
|||
import ../../../backend/general as status_general
|
||||
import ../../../backend/core as status_core
|
||||
|
||||
import ../../../app/core/eventemitter
|
||||
import ../../../app/core/signals/types
|
||||
import ../../../app/core/tasks/[qt, threadpool]
|
||||
import ../../../app/core/fleets/fleet_configuration
|
||||
import ../../common/[account_constants, network_constants, utils, string_utils]
|
||||
import ../../../constants as main_constants
|
||||
|
@ -30,10 +33,18 @@ const KDF_ITERATIONS* {.intdefine.} = 256_000
|
|||
# specific peer to set for testing messaging and mailserver functionality with squish.
|
||||
let TEST_PEER_ENR = getEnv("TEST_PEER_ENR").string
|
||||
|
||||
const SIGNAL_CONVERTING_PROFILE_KEYPAIR* = "convertingProfileKeypair"
|
||||
|
||||
type ResultArgs* = ref object of Args
|
||||
success*: bool
|
||||
|
||||
include utils
|
||||
include async_tasks
|
||||
|
||||
QtObject:
|
||||
type Service* = ref object of QObject
|
||||
events: EventEmitter
|
||||
threadpool: ThreadPool
|
||||
fleetConfiguration: FleetConfiguration
|
||||
generatedAccounts: seq[GeneratedAccountDto]
|
||||
accounts: seq[AccountDto]
|
||||
|
@ -46,10 +57,11 @@ QtObject:
|
|||
proc delete*(self: Service) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newService*(fleetConfiguration: FleetConfiguration): Service =
|
||||
result = Service()
|
||||
proc newService*(events: EventEmitter, threadpool: ThreadPool, fleetConfiguration: FleetConfiguration): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.events = events
|
||||
result.threadpool = threadpool
|
||||
result.fleetConfiguration = fleetConfiguration
|
||||
result.isFirstTimeAccountLogin = false
|
||||
result.keyStoreDir = main_constants.ROOTKEYSTOREDIR
|
||||
|
@ -677,8 +689,7 @@ QtObject:
|
|||
error "error: ", procName="verifyAccountPassword", errName = e.name, errDesription = e.msg
|
||||
|
||||
|
||||
proc convertToKeycardAccount*(self: Service, keyUid: string, currentPassword: string, newPassword: string): bool =
|
||||
try:
|
||||
proc convertToKeycardAccount*(self: Service, keyUid: string, currentPassword: string, newPassword: string) =
|
||||
var accountDataJson = %* {
|
||||
"name": self.getLoggedInAccount().name,
|
||||
"key-uid": keyUid
|
||||
|
@ -695,18 +706,31 @@ QtObject:
|
|||
return
|
||||
|
||||
let hashedCurrentPassword = hashString(currentPassword)
|
||||
let response = status_account.convertToKeycardAccount(self.keyStoreDir, accountDataJson, settingsJson,
|
||||
hashedCurrentPassword, newPassword)
|
||||
let arg = ConvertToKeycardAccountTaskArg(
|
||||
tptr: cast[ByteAddress](convertToKeycardAccountTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onConvertToKeycardAccount",
|
||||
accountDataJson: accountDataJson,
|
||||
settingsJson: settingsJson,
|
||||
keyStoreDir: self.keyStoreDir,
|
||||
hashedCurrentPassword: hashedCurrentPassword,
|
||||
newPassword: newPassword
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
if(response.result.contains("error")):
|
||||
let errMsg = response.result["error"].getStr
|
||||
proc onConvertToKeycardAccount*(self: Service, response: string) {.slot.} =
|
||||
var result = false
|
||||
try:
|
||||
let rpcResponse = Json.decode(response, RpcResponse[JsonNode])
|
||||
if(rpcResponse.result.contains("error")):
|
||||
let errMsg = rpcResponse.result["error"].getStr
|
||||
if(errMsg.len == 0):
|
||||
return true
|
||||
result = true
|
||||
else:
|
||||
error "error: ", procName="convertToKeycardAccount", errDesription = errMsg
|
||||
return false
|
||||
except Exception as e:
|
||||
error "error: ", procName="convertToKeycardAccount", errName = e.name, errDesription = e.msg
|
||||
error "error handilng migrated keypair response", errDesription=e.msg
|
||||
self.events.emit(SIGNAL_CONVERTING_PROFILE_KEYPAIR, ResultArgs(success: result))
|
||||
|
||||
proc verifyPassword*(self: Service, password: string): bool =
|
||||
try:
|
||||
|
|
|
@ -443,3 +443,26 @@ const prepareTokensTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
|||
|
||||
arg.finish(builtTokensPerAccount)
|
||||
|
||||
#################################################
|
||||
# Async add migrated keypair
|
||||
#################################################
|
||||
|
||||
type
|
||||
AddMigratedKeyPairTaskArg* = ref object of QObjectTaskArg
|
||||
keyPair: KeyPairDto
|
||||
keyStoreDir: string
|
||||
|
||||
const addMigratedKeyPairTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[AddMigratedKeyPairTaskArg](argEncoded)
|
||||
try:
|
||||
let response = backend.addMigratedKeyPair(
|
||||
arg.keyPair.keycardUid,
|
||||
arg.keyPair.keycardName,
|
||||
arg.keyPair.keyUid,
|
||||
arg.keyPair.accountsAddresses,
|
||||
arg.keyStoreDir
|
||||
)
|
||||
arg.finish(response)
|
||||
except Exception as e:
|
||||
error "error adding new keypair: ", message = e.msg
|
||||
arg.finish("")
|
|
@ -89,6 +89,7 @@ type TokensPerAccountArgs* = ref object of Args
|
|||
accountsTokens*: OrderedTable[string, seq[WalletTokenDto]] # [wallet address, list of tokens]
|
||||
|
||||
type KeycardActivityArgs* = ref object of Args
|
||||
success*: bool
|
||||
keycardUid*: string
|
||||
keycardNewUid*: string
|
||||
keycardNewName*: string
|
||||
|
@ -113,6 +114,7 @@ QtObject:
|
|||
walletAccounts: OrderedTable[string, WalletAccountDto]
|
||||
timerStartTimeInSeconds: int64
|
||||
priceCache: TimedCache
|
||||
processedKeyPair: KeyPairDto
|
||||
|
||||
# Forward declaration
|
||||
proc buildAllTokens(self: Service, calledFromTimerOrInit = false)
|
||||
|
@ -547,6 +549,28 @@ QtObject:
|
|||
error "error: ", procName=procName, errDesription = errMsg
|
||||
return false
|
||||
|
||||
proc addMigratedKeyPairAsync*(self: Service, keyPair: KeyPairDto, keyStoreDir: string) =
|
||||
let arg = AddMigratedKeyPairTaskArg(
|
||||
tptr: cast[ByteAddress](addMigratedKeyPairTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onMigratedKeyPairAdded",
|
||||
keyPair: keyPair,
|
||||
keyStoreDir: keyStoreDir
|
||||
)
|
||||
self.processedKeyPair = keyPair
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc onMigratedKeyPairAdded*(self: Service, response: string) {.slot.} =
|
||||
var result = false
|
||||
try:
|
||||
let rpcResponse = Json.decode(response, RpcResponse[JsonNode])
|
||||
result = self.responseHasNoErrors("addMigratedKeyPair", rpcResponse)
|
||||
except Exception as e:
|
||||
error "error handilng migrated keypair response", errDesription=e.msg
|
||||
let data = KeycardActivityArgs(success: result, keyPair: self.processedKeyPair)
|
||||
self.processedKeyPair = KeyPairDto()
|
||||
self.events.emit(SIGNAL_NEW_KEYCARD_SET, data)
|
||||
|
||||
proc addMigratedKeyPair*(self: Service, keyPair: KeyPairDto, keyStoreDir: string): bool =
|
||||
try:
|
||||
let response = backend.addMigratedKeyPair(
|
||||
|
@ -558,7 +582,7 @@ QtObject:
|
|||
)
|
||||
result = self.responseHasNoErrors("addMigratedKeyPair", response)
|
||||
if result:
|
||||
self.events.emit(SIGNAL_NEW_KEYCARD_SET, KeycardActivityArgs(keyPair: keyPair))
|
||||
self.events.emit(SIGNAL_NEW_KEYCARD_SET, KeycardActivityArgs(success: true, keyPair: keyPair))
|
||||
except Exception as e:
|
||||
error "error: ", procName="addMigratedKeyPair", errName = e.name, errDesription = e.msg
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ Item {
|
|||
id: d
|
||||
|
||||
readonly property bool hideKeyPair: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.hideKeyPair
|
||||
readonly property bool continuousProcessingAnimation: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
@ -484,13 +485,25 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: image
|
||||
pattern: Constants.keycardAnimations.warning.pattern
|
||||
pattern: d.continuousProcessingAnimation?
|
||||
Constants.keycardAnimations.processing.pattern :
|
||||
Constants.keycardAnimations.warning.pattern
|
||||
source: ""
|
||||
startImgIndexForTheFirstLoop: Constants.keycardAnimations.warning.startImgIndexForTheFirstLoop
|
||||
startImgIndexForOtherLoops: Constants.keycardAnimations.warning.startImgIndexForOtherLoops
|
||||
endImgIndex: Constants.keycardAnimations.warning.endImgIndex
|
||||
duration: Constants.keycardAnimations.warning.duration
|
||||
loops: Constants.keycardAnimations.warning.loops
|
||||
startImgIndexForTheFirstLoop: d.continuousProcessingAnimation?
|
||||
Constants.keycardAnimations.processing.startImgIndexForTheFirstLoop :
|
||||
Constants.keycardAnimations.warning.startImgIndexForTheFirstLoop
|
||||
startImgIndexForOtherLoops: d.continuousProcessingAnimation?
|
||||
Constants.keycardAnimations.processing.startImgIndexForOtherLoops :
|
||||
Constants.keycardAnimations.warning.startImgIndexForOtherLoops
|
||||
endImgIndex: d.continuousProcessingAnimation?
|
||||
Constants.keycardAnimations.processing.endImgIndex :
|
||||
Constants.keycardAnimations.warning.endImgIndex
|
||||
duration: d.continuousProcessingAnimation?
|
||||
Constants.keycardAnimations.processing.duration :
|
||||
Constants.keycardAnimations.warning.duration
|
||||
loops: d.continuousProcessingAnimation?
|
||||
Constants.keycardAnimations.processing.loops :
|
||||
Constants.keycardAnimations.warning.loops
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
|
|
|
@ -196,6 +196,15 @@ QtObject {
|
|||
readonly property int loops: 1
|
||||
}
|
||||
|
||||
readonly property QtObject processing: QtObject {
|
||||
readonly property string pattern: "keycard/warning/img-%1"
|
||||
readonly property int startImgIndexForTheFirstLoop: 0
|
||||
readonly property int startImgIndexForOtherLoops: 18
|
||||
readonly property int endImgIndex: 47
|
||||
readonly property int duration: 1500
|
||||
readonly property int loops: -1
|
||||
}
|
||||
|
||||
readonly property QtObject strongError: QtObject {
|
||||
readonly property string pattern: "keycard/strong_error/img-%1"
|
||||
readonly property int startImgIndexForTheFirstLoop: 0
|
||||
|
|
Loading…
Reference in New Issue