diff --git a/src/app/modules/main/wallet_section/accounts/controller.nim b/src/app/modules/main/wallet_section/accounts/controller.nim index abf8ccb58f..4bd602e8ab 100644 --- a/src/app/modules/main/wallet_section/accounts/controller.nim +++ b/src/app/modules/main/wallet_section/accounts/controller.nim @@ -1,9 +1,7 @@ import sugar, sequtils, tables import io_interface import ../../../../../app_service/service/wallet_account/service as wallet_account_service -import ../../../../../app_service/service/accounts/service as accounts_service import ../../../../../app_service/service/network/service as network_service -import ../../../../../app_service/service/token/service as token_service import ../../../../../app_service/service/currency/service as currency_service import ../../../../../app_service/service/currency/dto as currency_dto @@ -12,7 +10,6 @@ import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_modu import ../../../../core/eventemitter -const UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER* = "WalletSection-AccountsModule" const UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_AUTH_IDENTIFIER* = "WalletSection-AccountsModule-Authentication" type @@ -20,27 +17,21 @@ type delegate: io_interface.AccessInterface events: EventEmitter walletAccountService: wallet_account_service.Service - accountsService: accounts_service.Service networkService: network_service.Service - tokenService: token_service.Service currencyService: currency_service.Service proc newController*( delegate: io_interface.AccessInterface, events: EventEmitter, walletAccountService: wallet_account_service.Service, - accountsService: accounts_service.Service, networkService: network_service.Service, - tokenService: token_service.Service, currencyService: currency_service.Service, ): Controller = result = Controller() result.delegate = delegate result.events = events result.walletAccountService = walletAccountService - result.accountsService = accountsService result.networkService = networkService - result.tokenService = tokenService result.currencyService = currencyService proc delete*(self: Controller) = @@ -53,65 +44,12 @@ proc init*(self: Controller) = return self.delegate.onUserAuthenticated(args.pin, args.password, args.keyUid) - self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED_AND_WALLET_ADDRESS_GENERATED) do(e: Args): - let args = SharedKeycarModuleUserAuthenticatedAndWalletAddressGeneratedArgs(e) - if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER: - return - self.delegate.onUserAuthenticatedAndWalletAddressGenerated(args.address, args.publicKey, args.derivedFrom, args.password) - - self.events.on(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_DETAILS_FETCHED) do(e: Args): - let args = DerivedAddressesArgs(e) - var derivedAddress: DerivedAddressDto - if args.derivedAddresses.len > 0: - derivedAddress = args.derivedAddresses[0] - self.delegate.addressDetailsFetched(derivedAddress, args.error) - - self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED) do(e: Args): - let args = SharedKeycarModuleFlowTerminatedArgs(e) - if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER: - return - self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow) - proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] = return self.walletAccountService.getWalletAccounts() -proc generateNewAccount*(self: Controller, password: string, accountName: string, color: string, emoji: string, - path: string, derivedFrom: string, skipPasswordVerification: bool): string = - return self.walletAccountService.generateNewAccount(password, accountName, color, emoji, path, derivedFrom, skipPasswordVerification) - -proc addAccountsFromPrivateKey*(self: Controller, privateKey: string, password: string, accountName: string, color: string, - emoji: string, skipPasswordVerification: bool): string = - return self.walletAccountService.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji, skipPasswordVerification) - -proc addAccountsFromSeed*(self: Controller, seedPhrase: string, password: string, accountName: string, color: string, - emoji: string, path: string, skipPasswordVerification: bool): string = - return self.walletAccountService.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji, path, skipPasswordVerification) - -proc addWatchOnlyAccount*(self: Controller, address: string, accountName: string, color: string, emoji: string): string = - return self.walletAccountService.addWatchOnlyAccount(address, accountName, color, emoji) - proc deleteAccount*(self: Controller, address: string, password = "") = self.walletAccountService.deleteAccount(address, password) -proc fetchDerivedAddressDetails*(self: Controller, address: string) = - self.walletAccountService.fetchDerivedAddressDetails(address) - -method getDerivedAddress*(self: Controller, password: string, derivedFrom: string, path: string, hashPassword: bool)= - self.walletAccountService.getDerivedAddress(password, derivedFrom, path, hashPassword) - -method getDerivedAddressList*(self: Controller, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool)= - self.walletAccountService.getDerivedAddressList(password, derivedFrom, path, pageSize, pageNumber, hashPassword) - -method getDerivedAddressListForMnemonic*(self: Controller, mnemonic: string, path: string, pageSize: int, pageNumber: int) = - self.walletAccountService.getDerivedAddressListForMnemonic(mnemonic, path, pageSize, pageNumber) - -method getDerivedAddressForPrivateKey*(self: Controller, privateKey: string) = - self.walletAccountService.getDerivedAddressForPrivateKey(privateKey) - -proc validSeedPhrase*(self: Controller, seedPhrase: string): bool = - let err = self.accountsService.validateMnemonic(seedPhrase) - return err.len == 0 - proc authenticateKeyPair*(self: Controller, keyUid = "") = let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_AUTH_IDENTIFIER, keyUid: keyUid) @@ -120,11 +58,6 @@ proc authenticateKeyPair*(self: Controller, keyUid = "") = proc getAllMigratedKeyPairs*(self: Controller): seq[KeyPairDto] = return self.walletAccountService.getAllMigratedKeyPairs() -proc addWalletAccount*(self: Controller, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType, - color, emoji: string): string = - return self.walletAccountService.addWalletAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, - accountType, color, emoji) - proc getChainIds*(self: Controller): seq[int] = return self.networkService.getNetworks().map(n => n.chainId) diff --git a/src/app/modules/main/wallet_section/accounts/io_interface.nim b/src/app/modules/main/wallet_section/accounts/io_interface.nim index 30f5fe2b68..452f126057 100644 --- a/src/app/modules/main/wallet_section/accounts/io_interface.nim +++ b/src/app/modules/main/wallet_section/accounts/io_interface.nim @@ -16,70 +16,20 @@ method isLoaded*(self: AccessInterface): bool {.base.} = method syncKeycard*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method generateNewAccount*(self: AccessInterface, password: string, accountName: string, color: string, emoji: string, path: string, derivedFrom: string): string {.base.} = - raise newException(ValueError, "No implementation available") - -method addNewWalletAccountGeneratedFromKeycard*(self: AccessInterface, accountType: string, accountName: string, - color: string, emoji: string): string {.base.} = - raise newException(ValueError, "No implementation available") - -method addAccountsFromPrivateKey*(self: AccessInterface, privateKey: string, password: string, accountName: string, color: string, emoji: string): string {.base.} = - raise newException(ValueError, "No implementation available") - -method addAccountsFromSeed*(self: AccessInterface, seedPhrase: string, password: string, accountName: string, color: string, emoji: string, path: string): string {.base.} = - raise newException(ValueError, "No implementation available") - -method addWatchOnlyAccount*(self: AccessInterface, address: string, accountName: string, color: string, emoji: string): string {.base.} = - raise newException(ValueError, "No implementation available") - method deleteAccount*(self: AccessInterface, keyUid: string, address: string) {.base.} = raise newException(ValueError, "No implementation available") method refreshWalletAccounts*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method getDerivedAddress*(self: AccessInterface, password: string, derivedFrom: string, path: string, hashPassword: bool) {.base.} = - raise newException(ValueError, "No implementation available") - -method getDerivedAddressList*(self: AccessInterface, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool) {.base.} = - raise newException(ValueError, "No implementation available") - -method getDerivedAddressListForMnemonic*(self: AccessInterface, mnemonic: string, path: string, pageSize: int, pageNumber: int) {.base.} = - raise newException(ValueError, "No implementation available") - -method getDerivedAddressForPrivateKey*(self: AccessInterface, privateKey: string) {.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. method viewDidLoad*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method validSeedPhrase*(self: AccessInterface, value: string): bool {.base.} = - raise newException(ValueError, "No implementation available") - method authenticateUser*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") method onUserAuthenticated*(self: AccessInterface, pin: string, password: string, keyUid: string) {.base.} = raise newException(ValueError, "No implementation available") - -method authenticateUserAndDeriveAddressOnKeycardForPath*(self: AccessInterface, keyUid: string, derivationPath: string, searchForFirstAvailableAddress: bool) {.base.} = - raise newException(ValueError, "No implementation available") - -method createSharedKeycardModule*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - -method destroySharedKeycarModule*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - -method onUserAuthenticatedAndWalletAddressGenerated*(self: AccessInterface, address: string, publicKey: string, - derivedFrom: string, password: string) {.base.} = - raise newException(ValueError, "No implementation available") - -method addressDetailsFetched*(self: AccessInterface, derivedAddress: DerivedAddressDto, error: string) {.base.} = - raise newException(ValueError, "No implementation available") - -method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} = - raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/wallet_section/accounts/module.nim b/src/app/modules/main/wallet_section/accounts/module.nim index 777338e4ae..a0bb36fc5b 100644 --- a/src/app/modules/main/wallet_section/accounts/module.nim +++ b/src/app/modules/main/wallet_section/accounts/module.nim @@ -7,25 +7,18 @@ import ../../../../core/eventemitter import ../../../../../app_service/common/account_constants import ../../../../../app_service/service/keycard/service as keycard_service import ../../../../../app_service/service/wallet_account/service as wallet_account_service -import ../../../../../app_service/service/accounts/service as accounts_service import ../../../../../app_service/service/network/service as network_service -import ../../../../../app_service/service/token/service as token_service import ../../../../../app_service/service/currency/service as currency_service -import ../../../shared_models/token_model as token_model -import ../../../shared_models/token_item as token_item -import ../../../shared_modules/keycard_popup/models/key_pair_item as keycard_key_pair_item -import ../../../shared_modules/keycard_popup/module as keycard_shared_module -import ./compact_item as compact_item -import ./compact_model as compact_model +import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module export io_interface +# TODO: remove it completely if after wallet settings part refactore this is not needed. type AuthenticationReason {.pure.} = enum - LoggedInUserAuthentication = 0 - DeriveAccountForKeyPairAuthentication - DeleteAccountAuthentication + DeleteAccountAuthentication = 0 +# TODO: remove it completely if after wallet settings part refactore this is not needed. type WalletAccountDetails = object address: string path: string @@ -40,44 +33,29 @@ type view: View controller: Controller moduleLoaded: bool - keycardService: keycard_service.Service - accountsService: accounts_service.Service walletAccountService: wallet_account_service.Service - keycardSharedModule: keycard_shared_module.AccessInterface processingWalletAccount: WalletAccountDetails authentiactionReason: AuthenticationReason proc newModule*( delegate: delegate_interface.AccessInterface, events: EventEmitter, - keycardService: keycard_service.Service, walletAccountService: wallet_account_service.Service, - accountsService: accounts_service.Service, networkService: network_service.Service, - tokenService: token_service.Service, currencyService: currency_service.Service ): Module = result = Module() result.delegate = delegate result.events = events - result.keycardService = keycardService - result.accountsService = accountsService result.walletAccountService = walletAccountService result.view = newView(result) - result.controller = controller.newController(result, events, walletAccountService, accountsService, networkService, tokenService, currencyService) + result.controller = controller.newController(result, events, walletAccountService, networkService, currencyService) result.moduleLoaded = false - result.authentiactionReason = AuthenticationReason.LoggedInUserAuthentication + result.authentiactionReason = AuthenticationReason.DeleteAccountAuthentication method delete*(self: Module) = self.view.delete self.controller.delete - if not self.keycardSharedModule.isNil: - self.keycardSharedModule.delete - -method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) = - if not self.keycardSharedModule.isNil: - self.keycardSharedModule.delete - self.keycardSharedModule = nil method refreshWalletAccounts*(self: Module) = let keyPairMigrated = proc(migratedKeyPairs: seq[KeyPairDto], keyUid: string): bool = @@ -131,10 +109,6 @@ method load*(self: Module) = self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e:Args): self.refreshWalletAccounts() - self.events.on(SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_READY) do(e:Args): - var args = DerivedAddressesArgs(e) - self.view.setDerivedAddresses(args.derivedAddresses, args.error) - self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e:Args): self.refreshWalletAccounts() @@ -168,24 +142,6 @@ proc tryKeycardSync(self: Module, keyUid, pin: string) = let dataForKeycardToSync = SharedKeycarModuleArgs(pin: pin, keyUid: keyUid) self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC, dataForKeycardToSync) -method generateNewAccount*(self: Module, password: string, accountName: string, color: string, emoji: string, - path: string, derivedFrom: string): string = - let skipPasswordVerification = singletonInstance.userProfile.getIsKeycardUser() - return self.controller.generateNewAccount(password, accountName, color, emoji, path, derivedFrom, skipPasswordVerification) - -method addAccountsFromPrivateKey*(self: Module, privateKey: string, password: string, accountName: string, color: string, - emoji: string): string = - let skipPasswordVerification = singletonInstance.userProfile.getIsKeycardUser() - return self.controller.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji, skipPasswordVerification) - -method addAccountsFromSeed*(self: Module, seedPhrase: string, password: string, accountName: string, color: string, - emoji: string, path: string): string = - let skipPasswordVerification = singletonInstance.userProfile.getIsKeycardUser() - return self.controller.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji, path, skipPasswordVerification) - -method addWatchOnlyAccount*(self: Module, address: string, accountName: string, color: string, emoji: string): string = - return self.controller.addWatchOnlyAccount(address, accountName, color, emoji) - proc authenticateActivityForKeyUid(self: Module, keyUid: string, reason: AuthenticationReason) = self.authentiactionReason = reason let keyPair = self.controller.getMigratedKeyPairByKeyUid(keyUid) @@ -205,117 +161,15 @@ method deleteAccount*(self: Module, keyUid: string, address: string) = self.processingWalletAccount = WalletAccountDetails(keyUid: keyUid, address: address) self.authenticateActivityForKeyUid(keyUid, AuthenticationReason.DeleteAccountAuthentication) -method getDerivedAddress*(self: Module, password: string, derivedFrom: string, path: string, hashPassword: bool) = - self.controller.getDerivedAddress(password, derivedFrom, path, hashPassword) - -method getDerivedAddressList*(self: Module, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool) = - self.controller.getDerivedAddressList(password, derivedFrom, path, pageSize, pageNumber, hashPassword) - -method getDerivedAddressListForMnemonic*(self: Module, mnemonic: string, path: string, pageSize: int, pageNumber: int) = - self.controller.getDerivedAddressListForMnemonic(mnemonic, path, pageSize, pageNumber) - -method getDerivedAddressForPrivateKey*(self: Module, privateKey: string) = - self.controller.getDerivedAddressForPrivateKey(privateKey) - -method validSeedPhrase*(self: Module, value: string): bool = - return self.controller.validSeedPhrase(value) - -method authenticateUser*(self: Module) = - self.authenticateActivityForKeyUid(singletonInstance.userProfile.getKeyUid(), AuthenticationReason.LoggedInUserAuthentication) - method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: string) = - if self.authentiactionReason == AuthenticationReason.LoggedInUserAuthentication or - self.authentiactionReason == AuthenticationReason.DeriveAccountForKeyPairAuthentication: - if password.len > 0: - self.view.userAuthenticationSuccess(password) - else: - self.view.userAuthentiactionFail() - elif self.authentiactionReason == AuthenticationReason.DeleteAccountAuthentication: - if self.processingWalletAccount.keyUid == keyUid: + if self.authentiactionReason == AuthenticationReason.DeleteAccountAuthentication: + if self.processingWalletAccount.keyUid != keyUid: + error "cannot resolve key uid of an account being deleted", keyUid=keyUid + return + if pin.len == PINLengthForStatusApp: # keycard keypair authentication self.controller.deleteAccount(self.processingWalletAccount.address) - if pin.len == PINLengthForStatusApp: - self.tryKeycardSync(keyUid, pin) - if password.len > 0 and keyUid.len == 0: + self.tryKeycardSync(keyUid, pin) + elif password.len > 0: # regular keypair authentication - self.controller.deleteAccount(self.processingWalletAccount.address, password) - -method createSharedKeycardModule*(self: Module) = - if self.keycardSharedModule.isNil: - self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER, - self.events, self.keycardService, settingsService = nil, networkService = nil, privacyService = nil, self.accountsService, - self.walletAccountService, keychainService = nil) - -method destroySharedKeycarModule*(self: Module) = - if not self.keycardSharedModule.isNil: - let kpForProcessing = self.keycardSharedModule.getKeyPairForProcessing() - if not kpForProcessing.isNil: - self.tryKeycardSync(kpForProcessing.getKeyUid(), self.keycardSharedModule.getPin()) - self.keycardSharedModule.delete - self.keycardSharedModule = nil - -proc checkIfWalletAccountIsAlreadyCreated(self: Module, keyUid: string, derivationPath: string): bool = - let walletAccounts = self.controller.getWalletAccounts() - for w in walletAccounts: - if w.keyUid == keyUid and w.path == derivationPath: - return true - return false - -proc findFirstAvaliablePathForWallet(self: Module, keyUid: string): string = - let walletAccounts = self.controller.getWalletAccounts() - # starting from 1, "0" is already reserved for the default wallet account - for i in 1 .. 256: # we hope that nobody will have 256 accounts added, so no need to change derivation tree - let path = account_constants.PATH_WALLET_ROOT & "/" & $i - var found = false - for w in walletAccounts: - if w.keyUid == keyUid and w.path == path: - found = true - break - if not found: - return path - error "we couldn't find available wallet account path" - -method authenticateUserAndDeriveAddressOnKeycardForPath*(self: Module, keyUid: string, derivationPath: string, searchForFirstAvailableAddress: bool) = - self.authentiactionReason = AuthenticationReason.DeriveAccountForKeyPairAuthentication - var finalPath = derivationPath - if searchForFirstAvailableAddress and - self.checkIfWalletAccountIsAlreadyCreated(keyUid, finalPath): - finalPath = self.findFirstAvaliablePathForWallet(keyUid) - if self.keycardSharedModule.isNil: - self.createSharedKeycardModule() - self.processingWalletAccount = WalletAccountDetails(keyUid: keyUid, path: finalPath) - self.view.setDerivedAddressesLoading(true) - self.view.setDerivedAddressesError("") - self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.AuthenticateAndDeriveAccountAddress, keyUid, finalPath) - -method onUserAuthenticatedAndWalletAddressGenerated*(self: Module, address: string, publicKey: string, - derivedFrom: string, password: string) = - if address.len == 0: - self.view.setDerivedAddressesError("wrong-path") # this should be checked on the UI side and we should not allow entering invalid path format - if password.len == 0: - self.view.setDerivedAddressesLoading(false) - return - self.onUserAuthenticated(pin = "", password, keyUid = "") - self.processingWalletAccount.address = address - self.processingWalletAccount.addressAccountIsDerivedFrom = derivedFrom - self.processingWalletAccount.publicKey = publicKey - self.controller.fetchDerivedAddressDetails(address) - -method addressDetailsFetched*(self: Module, derivedAddress: DerivedAddressDto, error: string) = - var derivedAddressDto = derivedAddress - if error.len > 0: - derivedAddressDto.address = self.processingWalletAccount.address - derivedAddressDto.alreadyCreated = true - self.view.setDerivedAddresses(@[derivedAddressDto], error) - -method addNewWalletAccountGeneratedFromKeycard*(self: Module, accountType: string, accountName: string, color: string, - emoji: string): string = - return self.controller.addWalletAccount(accountName, - self.processingWalletAccount.address, - self.processingWalletAccount.path, - self.processingWalletAccount.addressAccountIsDerivedFrom, - self.processingWalletAccount.publicKey, - self.processingWalletAccount.keyUid, - accountType, - color, - emoji) + self.controller.deleteAccount(self.processingWalletAccount.address, password) \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/accounts/view.nim b/src/app/modules/main/wallet_section/accounts/view.nim index c20fa6366a..60d62b459d 100644 --- a/src/app/modules/main/wallet_section/accounts/view.nim +++ b/src/app/modules/main/wallet_section/accounts/view.nim @@ -24,15 +24,11 @@ QtObject: watchOnly: Model imported: Model generatedAccounts: GeneratedWalletModel - derivedAddresses: DerivedAddressModel - derivedAddressesLoading: bool - derivedAddressesError: string modelVariant: QVariant generatedVariant: QVariant importedVariant: QVariant watchOnlyVariant: QVariant generatedAccountsVariant: QVariant - derivedAddressesVariant: QVariant tmpAddress: string proc delete*(self: View) = @@ -46,8 +42,6 @@ QtObject: self.watchOnlyVariant.delete self.generatedAccounts.delete self.generatedAccountsVariant.delete - self.derivedAddresses.delete - self.derivedAddressesVariant.delete self.QObject.delete proc newView*(delegate: io_interface.AccessInterface): View = @@ -64,10 +58,6 @@ QtObject: result.watchOnlyVariant = newQVariant(result.watchOnly) result.generatedAccounts = newGeneratedWalletModel() result.generatedAccountsVariant = newQVariant(result.generatedAccounts) - result.derivedAddresses = newDerivedAddressModel() - result.derivedAddressesLoading = false - result.derivedAddressesError = "" - result.derivedAddressesVariant = newQVariant(result.derivedAddresses) proc load*(self: View) = self.delegate.viewDidLoad() @@ -117,44 +107,6 @@ QtObject: read = getGeneratedAccounts notify = generatedAccountsChanged - proc derivedAddressesChanged*(self: View) {.signal.} - - proc getDerivedAddresses(self: View): QVariant {.slot.} = - return self.derivedAddressesVariant - - QtProperty[QVariant] derivedAddresses: - read = getDerivedAddresses - notify = derivedAddressesChanged - - proc derivedAddressesLoadingChanged*(self: View) {.signal.} - - proc getDerivedAddressesLoading(self: View): bool {.slot.} = - return self.derivedAddressesLoading - - proc setDerivedAddressesLoading*(self: View, loading: bool) {.slot.} = - if self.derivedAddressesLoading != loading: - self.derivedAddressesLoading = loading - self.derivedAddressesLoadingChanged() - - QtProperty[bool] derivedAddressesLoading: - read = getDerivedAddressesLoading - write = setDerivedAddressesLoading - notify = derivedAddressesLoadingChanged - - proc derivedAddressErrorChanged*(self: View) {.signal.} - - proc getDerivedAddressesError(self: View): string {.slot.} = - return self.derivedAddressesError - - proc setDerivedAddressesError*(self: View, error: string) {.slot.} = - self.derivedAddressesError = error - self.derivedAddressErrorChanged() - - QtProperty[string] derivedAddressesError: - read = getDerivedAddressesError - write = setDerivedAddressesError - notify = derivedAddressErrorChanged - proc setItems*(self: View, items: seq[Item]) = self.model.setItems(items) @@ -206,22 +158,6 @@ QtObject: self.generated.setItems(generated) self.generatedAccounts.setItems(generatedAccounts) - proc generateNewAccount*(self: View, password: string, accountName: string, color: string, emoji: string, path: string, derivedFrom: string): string {.slot.} = - return self.delegate.generateNewAccount(password, accountName, color, emoji, path, derivedFrom) - - proc addNewWalletAccountGeneratedFromKeycard*(self: View, accountType: string, accountName: string, color: string, - emoji: string): string {.slot.} = - return self.delegate.addNewWalletAccountGeneratedFromKeycard(accountType, accountName, color, emoji) - - proc addAccountsFromPrivateKey*(self: View, privateKey: string, password: string, accountName: string, color: string, emoji: string): string {.slot.} = - return self.delegate.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji) - - proc addAccountsFromSeed*(self: View, seedPhrase: string, password: string, accountName: string, color: string, emoji: string, path: string): string {.slot.} = - return self.delegate.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji, path) - - proc addWatchOnlyAccount*(self: View, address: string, accountName: string, color: string, emoji: string): string {.slot.} = - return self.delegate.addWatchOnlyAccount(address, accountName, color, emoji) - proc deleteAccount*(self: View, keyUid: string, address: string) {.slot.} = self.delegate.deleteAccount(keyUid, address) @@ -235,71 +171,4 @@ QtObject: self.tmpAddress = address proc getAccountAssetsByAddress*(self: View): QVariant {.slot.} = - return self.model.getAccountAssetsByAddress(self.tmpAddress) - - proc setDerivedAddresses*(self: View, derivedAddresses: seq[wallet_account_service.DerivedAddressDto], error: string) = - var items: seq[DerivedAddressItem] = @[] - for item in derivedAddresses: - items.add(initDerivedAddressItem(item.address, item.path, item.hasActivity, item.alreadyCreated)) - self.derivedAddresses.setItems(items) - self.setDerivedAddressesError(error) - self.setDerivedAddressesLoading(false) - self.derivedAddressesChanged() - - proc getDerivedAddress*(self: View, password: string, derivedFrom: string, path: string, hashPassword: bool) {.slot.} = - self.setDerivedAddressesLoading(true) - self.setDerivedAddressesError("") - self.delegate.getDerivedAddress(password, derivedfrom, path, hashPassword) - - proc getDerivedAddressList*(self: View, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool) {.slot.} = - self.setDerivedAddressesLoading(true) - self.setDerivedAddressesError("") - self.delegate.getDerivedAddressList(password, derivedfrom, path, pageSize, pageNumber, hashPassword) - - proc getDerivedAddressListForMnemonic*(self: View, mnemonic: string, path: string, pageSize: int, pageNumber: int) {.slot.} = - self.setDerivedAddressesLoading(true) - self.setDerivedAddressesError("") - self.delegate.getDerivedAddressListForMnemonic(mnemonic, path, pageSize, pageNumber) - - proc getDerivedAddressForPrivateKey*(self: View, privateKey: string) {.slot.} = - self.setDerivedAddressesLoading(true) - self.setDerivedAddressesError("") - self.delegate.getDerivedAddressForPrivateKey(privateKey) - - proc resetDerivedAddressModel*(self: View) {.slot.} = - var items: seq[DerivedAddressItem] = @[] - self.derivedAddresses.setItems(items) - self.derivedAddressesChanged() - - proc getDerivedAddressAtIndex*(self: View, index: int): string {.slot.} = - return self.derivedAddresses.getDerivedAddressAtIndex(index) - - proc getDerivedAddressPathAtIndex*(self: View, index: int): string {.slot.} = - return self.derivedAddresses.getDerivedAddressPathAtIndex(index) - - proc getDerivedAddressHasActivityAtIndex*(self: View, index: int): bool {.slot.} = - return self.derivedAddresses.getDerivedAddressHasActivityAtIndex(index) - - proc getDerivedAddressAlreadyCreatedAtIndex*(self: View, index: int): bool {.slot.} = - return self.derivedAddresses.getDerivedAddressAlreadyCreatedAtIndex(index) - - proc getNextSelectableDerivedAddressIndex*(self: View): int {.slot.} = - return self.derivedAddresses.getNextSelectableDerivedAddressIndex() - - proc validSeedPhrase*(self: View, value: string): bool {.slot.} = - return self.delegate.validSeedPhrase(value) - - proc userAuthenticationSuccess*(self: View, password: string) {.signal.} - proc userAuthentiactionFail*(self: View) {.signal.} - - proc authenticateUser*(self: View) {.slot.} = - self.delegate.authenticateUser() - - proc createSharedKeycardModule*(self: View) {.slot.} = - self.delegate.createSharedKeycardModule() - - proc destroySharedKeycarModule*(self: View) {.slot.} = - self.delegate.destroySharedKeycarModule() - - proc authenticateUserAndDeriveAddressOnKeycardForPath*(self: View, keyUid: string, derivationPath: string, searchForFirstAvailableAddress: bool) {.slot.} = - self.delegate.authenticateUserAndDeriveAddressOnKeycardForPath(keyUid, derivationPath, searchForFirstAvailableAddress) + return self.model.getAccountAssetsByAddress(self.tmpAddress) \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/module.nim b/src/app/modules/main/wallet_section/module.nim index f1e0bf7126..fd69c8e452 100644 --- a/src/app/modules/main/wallet_section/module.nim +++ b/src/app/modules/main/wallet_section/module.nim @@ -4,7 +4,7 @@ import ./controller, ./view import ./io_interface as io_interface import ../io_interface as delegate_interface -import ./accounts/module as accountsModule +import ./accounts/module as accounts_module import ./all_tokens/module as all_tokens_module import ./collectibles/module as collectibles_module import ./current_account/module as current_account_module @@ -70,7 +70,7 @@ proc newModule*( result.controller = newController(result, settingsService, walletAccountService, currencyService) result.view = newView(result) - result.accountsModule = accounts_module.newModule(result, events, keycardService, walletAccountService, accountsService, networkService, tokenService, currencyService) + result.accountsModule = accounts_module.newModule(result, events, walletAccountService, networkService, currencyService) result.allTokensModule = all_tokens_module.newModule(result, events, tokenService, walletAccountService) result.collectiblesModule = collectibles_module.newModule(result, events, collectibleService, walletAccountService, networkService, nodeService, networkConnectionService) result.currentAccountModule = current_account_module.newModule(result, events, walletAccountService, networkService, tokenService, currencyService) diff --git a/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml b/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml deleted file mode 100644 index e266a485e5..0000000000 --- a/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml +++ /dev/null @@ -1,134 +0,0 @@ -import QtQuick 2.12 -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 StatusQ.Components 0.1 - -import utils 1.0 -import "../stores" - -ColumnLayout { - id: derivationPathSelect - - property string path: "" - property bool useFullyCustomPath: true - - function reset() { - if (derivationPathSelect.useFullyCustomPath) { - derivationPathFullyCustomInput.text = _internal.customDerivationRootPath - } - else { - derivationPathStatusDefaultInput.text = _internal.defaultDerivationIndex - } - if (!_internal.userInputTimer.running) { - _internal.userInputTimer.start() - } - } - - QtObject { - id: _internal - readonly property string defaultDerivationIndex: "1" - property var userInputTimer: Timer { - // 1 second wait after each key press - interval: 1000 - running: false - onTriggered: { - if (derivationPathSelect.useFullyCustomPath) { - derivationPathSelect.path = derivationPathFullyCustomInput.text - } - else { - if (derivationPathStatusDefaultInput.text === "") { - return - } - derivationPathSelect.path = _internal.defaultDerivationRootPath + derivationPathStatusDefaultInput.text - } - } - } - property bool pathError: Utils.isInvalidPath(RootStore.derivedAddressesError) - property bool derivationAddressLoading: RootStore.derivedAddressesLoading - property string customDerivationRootPath: "m/44'/60'/0'/0" - property string defaultDerivationRootPath: "m/44'/60'/0'/0/" - } - - Component { - id: loadedIcon - StatusIcon { - icon: _internal.pathError ? "cancel" : "checkmark" - height: 14 - width: 14 - color: _internal.pathError ? Theme.palette.dangerColor1 : Theme.palette.primaryColor1 - } - } - Component { - id: loadingIcon - StatusLoadingIndicator { - color: Theme.palette.directColor4 - } - } - - Component { - id: fixedLeftPart - StatusBaseText { - rightPadding: 0 - text: _internal.defaultDerivationRootPath - color: Theme.palette.baseColor1 - font: derivationPathStatusDefaultInput.font - } - } - - spacing: 7 - - RowLayout { - StatusBaseText { - id: inputLabel - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - text: qsTr("Derivation Path") - font.pixelSize: 15 - } - StatusButton { - id: resetButton - Layout.alignment: Qt.AlignTop - size: StatusBaseButton.Size.Tiny - text: qsTr("Reset") - font.pixelSize: 15 - padding: 0 - normalColor: "transparent" - onClicked: derivationPathSelect.reset() - } - } - StatusInput { - id: derivationPathFullyCustomInput - Layout.preferredHeight: 64 - Layout.preferredWidth: parent.width - visible: derivationPathSelect.useFullyCustomPath - maximumHeight: 64 - text: _internal.customDerivationRootPath - input.color: _internal.pathError ? Theme.palette.dangerColor1 : Theme.palette.directColor1 - input.rightComponent: _internal.derivationAddressLoading ? loadingIcon : loadedIcon - onTextChanged: _internal.userInputTimer.start() - } - StatusInput { - id: derivationPathStatusDefaultInput - Layout.preferredHeight: 64 - Layout.preferredWidth: parent.width - visible: !derivationPathSelect.useFullyCustomPath - maximumHeight: 64 - text: _internal.defaultDerivationIndex - input.color: _internal.pathError ? Theme.palette.dangerColor1 : Theme.palette.directColor1 - input.rightComponent: _internal.derivationAddressLoading ? loadingIcon : loadedIcon - input.leftComponent: fixedLeftPart - onTextChanged: _internal.userInputTimer.start() - validationMode: StatusInput.ValidationMode.IgnoreInvalidInput - validators: [ - StatusRegularExpressionValidator { - regularExpression: /^[0-9]{0,9}$/ - errorMessage: "" - } - ] - } -} - diff --git a/ui/app/AppLayouts/Wallet/panels/DerivedAddressesPanel.qml b/ui/app/AppLayouts/Wallet/panels/DerivedAddressesPanel.qml deleted file mode 100644 index 090f146609..0000000000 --- a/ui/app/AppLayouts/Wallet/panels/DerivedAddressesPanel.qml +++ /dev/null @@ -1,254 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.14 -import QtQuick.Layouts 1.14 - -import StatusQ.Core 0.1 -import StatusQ.Core.Theme 0.1 -import StatusQ.Popups 0.1 -import StatusQ.Components 0.1 -import StatusQ.Controls 0.1 - -import utils 1.0 - -import "../stores" - -Item { - id: derivedAddresses - - property int selectedAccountType: Constants.AddAccountType.GenerateNew - property string selectedKeyUid: RootStore.defaultSelectedKeyUid - property bool selectedKeyUidMigratedToKeycard: RootStore.defaultSelectedKeyUidMigratedToKeycard - property string selectedPath: "" - property string pathSubFix: "" - property bool isLoading: RootStore.derivedAddressesLoading - property bool pathError: Utils.isInvalidPath(RootStore.derivedAddressesError) - - property alias selectedAddress: selectedDerivedAddress.title - property alias selectedAddressAvailable: selectedDerivedAddress.enabled - - function reset() { - RootStore.resetDerivedAddressModel() - _internal.nextSelectableAddressIndex = 0 - selectedDerivedAddress.pathSubFix = 0 - selectedDerivedAddress.title = "---" - selectedDerivedAddress.subTitle = qsTr("No activity") - selectedDerivedAddress.enabled = false - } - - onIsLoadingChanged: { - if(isLoading) { - selectedDerivedAddress.title = qsTr("Pending") - selectedDerivedAddress.subTitle = "" - } - } - - onPathErrorChanged: { - if(pathError) { - selectedDerivedAddress.title = qsTr("Invalid path") - selectedDerivedAddress.subTitle = "" - } - } - - QtObject { - id: _internal - - readonly property bool showEnterPinPassButton: !RootStore.loggedInUserAuthenticated && - derivedAddresses.selectedAccountType !== Constants.AddAccountType.ImportSeedPhrase && - derivedAddresses.selectedAccountType !== Constants.AddAccountType.ImportPrivateKey - property int pageSize: 6 - property int noOfPages: Math.ceil(RootStore.derivedAddressesList.count/pageSize) - property int lastPageSize: RootStore.derivedAddressesList.count - ((noOfPages -1) * pageSize) - property bool isLastPage: stackLayout.currentIndex == (noOfPages - 1) - property int nextSelectableAddressIndex: RootStore.getNextSelectableDerivedAddressIndex() - - onNextSelectableAddressIndexChanged: { - stackLayout.currentIndex = nextSelectableAddressIndex/_internal.pageSize - if(nextSelectableAddressIndex >= 0 && nextSelectableAddressIndex < RootStore.derivedAddressesList.count) { - selectedDerivedAddress.title = RootStore.getDerivedAddressData(nextSelectableAddressIndex) - selectedDerivedAddress.hasActivity = RootStore.getDerivedAddressHasActivityData(nextSelectableAddressIndex) - selectedDerivedAddress.subTitle = RootStore.getDerivedAddressHasActivityData(nextSelectableAddressIndex) ? qsTr("Has Activity"): qsTr("No Activity") - selectedDerivedAddress.enabled = !RootStore.getDerivedAddressAlreadyCreatedData(nextSelectableAddressIndex) - selectedDerivedAddress.pathSubFix = nextSelectableAddressIndex - } - } - - // dimensions - property int popupWidth: 359 - property int maxAddressWidth: 102 - - function runAction() { - if (derivedAddresses.selectedKeyUidMigratedToKeycard) - RootStore.authenticateUserAndDeriveAddressOnKeycardForPath(derivedAddresses.selectedKeyUid, derivedAddresses.selectedPath, false) - else - RootStore.authenticateUser() - } - } - - Connections { - target: RootStore.derivedAddressesList - function onModelReset() { - _internal.pageSize = 0 - _internal.pageSize = 6 - _internal.nextSelectableAddressIndex = -1 - _internal.nextSelectableAddressIndex = RootStore.getNextSelectableDerivedAddressIndex() - } - } - - ColumnLayout { - id: layout - width: parent.width - spacing: 7 - StatusBaseText { - id: inputLabel - width: parent.width - text: qsTr("Account") - font.pixelSize: 15 - color: selectedDerivedAddress.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1 - } - StatusListItem { - id: selectedDerivedAddress - property int pathSubFix: 0 - property bool hasActivity: false - implicitWidth: parent.width - visible: !_internal.showEnterPinPassButton - color: "transparent" - border.width: 1 - border.color: Theme.palette.baseColor2 - title: "---" - subTitle: selectedDerivedAddress.hasActivity ? qsTr("Has Activity"): qsTr("No Activity") - statusListItemSubTitle.color: selectedDerivedAddress.hasActivity ? Theme.palette.primaryColor1 : Theme.palette.baseColor1 - statusListItemTitle.wrapMode: Text.NoWrap - statusListItemTitle.width: _internal.maxAddressWidth - statusListItemTitle.elide: Qt.ElideMiddle - statusListItemTitle.anchors.left: undefined - statusListItemTitle.anchors.right: undefined - components: [ - StatusIcon { - width: 24 - height: 24 - icon: "chevron-down" - color: Theme.palette.baseColor1 - visible: RootStore.derivedAddressesList.count > 1 - } - ] - onClicked: { - if(RootStore.derivedAddressesList.count > 0 && RootStore.derivedAddressesList.count !== 1) - derivedAddressPopup.popup(derivedAddresses.x - layout.width - Style.current.bigPadding , derivedAddresses.y + layout.height + 8) - } - enabled: RootStore.derivedAddressesList.count > 0 - Component.onCompleted: derivedAddresses.pathSubFix = Qt.binding(function() { return pathSubFix}) - } - - StatusButton { - visible: _internal.showEnterPinPassButton - text: qsTr("Preview address") - highlighted: focus - - onClicked: _internal.runAction() - } - } - - StatusMenu { - id: derivedAddressPopup - width: _internal.popupWidth - contentItem: Column { - StackLayout { - id: stackLayout - Layout.fillWidth:true - Layout.fillHeight: true - Repeater { - id: pageModel - model: _internal.noOfPages - delegate: Page { - id: page - contentItem: ColumnLayout { - Repeater { - id: repeater - model: _internal.isLastPage ? _internal.lastPageSize : _internal.pageSize - delegate: StatusListItem { - id: element - property int actualIndex: index + (stackLayout.currentIndex* _internal.pageSize) - property bool hasActivity: { - if(actualIndex >= 0 && actualIndex < RootStore.derivedAddressesList.count) { - return RootStore.getDerivedAddressHasActivityData(actualIndex) - } - return false - } - implicitWidth: derivedAddressPopup.width - statusListItemTitle.wrapMode: Text.NoWrap - statusListItemTitle.width: _internal.maxAddressWidth - statusListItemTitle.elide: Qt.ElideMiddle - statusListItemTitle.anchors.left: undefined - statusListItemTitle.anchors.right: undefined - title: { - if(actualIndex >= 0 && actualIndex < RootStore.derivedAddressesList.count) { - return RootStore.getDerivedAddressData(actualIndex) - } - return "" - } - subTitle: element.hasActivity ? qsTr("Has Activity"): qsTr("No Activity") - statusListItemSubTitle.color: element.hasActivity ? Theme.palette.primaryColor1 : Theme.palette.baseColor1 - enabled: { - if(actualIndex >= 0 && actualIndex < RootStore.derivedAddressesList.count) { - return !RootStore.getDerivedAddressAlreadyCreatedData(actualIndex) - } - return true - } - components: [ - StatusBaseText { - text: element.actualIndex - font.pixelSize: 15 - color: Theme.palette.baseColor1 - }, - Rectangle { - radius: width/2 - height: 5 - width: 5 - color: Theme.palette.primaryColor1 - visible: element.hasActivity - anchors.verticalCenter: parent.verticalCenter - } - ] - onClicked: { - selectedDerivedAddress.title = title - selectedDerivedAddress.subTitle = subTitle - selectedDerivedAddress.pathSubFix = actualIndex - selectedDerivedAddress.hasActivity = element.hasActivity - derivedAddressPopup.close() - } - Component.onCompleted: { - if(RootStore.derivedAddressesList.count === 1 && index === 0) { - selectedDerivedAddress.title = title - selectedDerivedAddress.subTitle = subTitle - selectedDerivedAddress.pathSubFix = actualIndex - selectedDerivedAddress.hasActivity = element.hasActivity - selectedDerivedAddress.enabled = !RootStore.getDerivedAddressAlreadyCreatedData(index) - } - } - } - } - } - background: Rectangle { - implicitWidth: stackLayout.width - implicitHeight: stackLayout.height - color: Theme.palette.statusMenu.backgroundColor - radius: 8 - } - } - } - } - - PageIndicator { - id: pageIndicator - anchors.horizontalCenter: parent.horizontalCenter - interactive: true - currentIndex: stackLayout.currentIndex - count: stackLayout.count - onCurrentIndexChanged: stackLayout.currentIndex = currentIndex - } - } - } -} - - - diff --git a/ui/app/AppLayouts/Wallet/panels/ImportPrivateKeyPanel.qml b/ui/app/AppLayouts/Wallet/panels/ImportPrivateKeyPanel.qml deleted file mode 100644 index e5b6329ae5..0000000000 --- a/ui/app/AppLayouts/Wallet/panels/ImportPrivateKeyPanel.qml +++ /dev/null @@ -1,122 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Layouts 1.14 - -import StatusQ.Core 0.1 -import StatusQ.Core.Theme 0.1 -import StatusQ.Controls 0.1 -import StatusQ.Components 0.1 -import StatusQ.Core.Utils 0.1 -import StatusQ.Controls.Validators 0.1 - -import utils 1.0 -import "../stores" - -ColumnLayout { - - property string text: privateKey.text - property bool valid: privateKey.valid - - function resetMe() { - d.errorString = "" - privateKey.text = "" - privateKey.reset() - } - - function validateMe() { - if (privateKey.text === "") { - d.errorString = qsTr("You need to enter a private key") - } else if (!Utils.isPrivateKey(privateKey.text)) { - d.errorString = qsTr("Enter a valid private key (64 characters hexadecimal string)") - } else { - d.errorString = "" - } - return d.errorString === "" && !d.invalidPrivateKeyError - } - - QtObject { - id: d - readonly property int privateKeyCharLimit: 66 - property string errorString: "" - readonly property bool accountAreadyAddedError: Utils.accountAlreadyExistsError(RootStore.derivedAddressesError) - readonly property bool invalidPrivateKeyError: Utils.isInvalidPrivateKey(RootStore.derivedAddressesError) - } - - spacing: 24 - - StatusInput { - id: privateKey - - label: qsTr("Private key") - charLimit: d.privateKeyCharLimit - input.multiline: true - minimumHeight: 80 - maximumHeight: 108 - placeholderText: qsTr("Paste the contents of your private key") - errorMessage: d.errorString - validators: [ - StatusMinLengthValidator { - minLength: 1 - errorMessage: qsTr("You need to enter a private key") - }, - StatusValidator { - property var validate: function (value) { - return Utils.isPrivateKey(value) - } - errorMessage: qsTr("Enter a valid private key (64 characters hexadecimal string)") - } - ] - asyncValidators: [ - StatusAsyncValidator { - id: privateKeyAsyncValidator - Connections { - target: d - function onInvalidPrivateKeyErrorChanged() { - privateKeyAsyncValidator.validationComplete("", !d.invalidPrivateKeyError) - } - } - validate: (value) => !d.invalidPrivateKeyError - name: "asyncPKCheck" - errorMessage: qsTr("Enter a valid private key") - } - ] - onTextChanged: { - if(valid) { - RootStore.getDerivedAddressForPrivateKey(text) - } - } - - onVisibleChanged: { - if(visible) - privateKey.input.edit.forceActiveFocus(); - } - } - - ColumnLayout { - spacing: 8 - - StatusBaseText { - id: inputLabel - Layout.alignment: Qt.AlignLeft - Layout.fillWidth: true - text: qsTr("Public address") - font.pixelSize: 15 - } - - StatusListItem { - id: derivedAddress - property string address: RootStore.derivedAddressesList.count > 0 ? RootStore.getDerivedAddressData(0) : "---" - property bool hasActivity: RootStore.derivedAddressesList.count > 0 ? RootStore.getDerivedAddressHasActivityData(0) : false - Layout.alignment: Qt.AlignHCenter - asset.bgColor: "transparent" - border.width: 1 - border.color: Theme.palette.baseColor2 - type: d.accountAreadyAddedError ? StatusListItem.Type.Danger : StatusListItem.Type.Primary - statusListItemSubTitle.color: derivedAddress.hasActivity ? Theme.palette.primaryColor1 : Theme.palette.baseColor1 - title: d.accountAreadyAddedError ? qsTr("Account already added") : RootStore.derivedAddressesLoading ? qsTr("Pending") : derivedAddress.address - subTitle: RootStore.derivedAddressesLoading || d.accountAreadyAddedError ? "" : derivedAddress.hasActivity ? qsTr("Has Activity"): qsTr("No Activity") - sensor.enabled: false - } - } -} - - diff --git a/ui/app/AppLayouts/Wallet/panels/ImportSeedPhrasePanel.qml b/ui/app/AppLayouts/Wallet/panels/ImportSeedPhrasePanel.qml deleted file mode 100644 index c18039711a..0000000000 --- a/ui/app/AppLayouts/Wallet/panels/ImportSeedPhrasePanel.qml +++ /dev/null @@ -1,268 +0,0 @@ -import QtQuick 2.12 - -import StatusQ.Core 0.1 -import StatusQ.Core.Theme 0.1 -import StatusQ.Controls 0.1 - -import utils 1.0 -import shared.stores 1.0 -import shared.controls 1.0 - -import "../stores" - -StatusGridView { - id: grid - - property bool isValid: false - property string mnemonicString: "" - property int preferredHeight: (cellHeight * model/2) + footerItem.height - signal enterPressed() - - function reset() { - _internal.errorString = "" - mnemonicString = "" - _internal.mnemonicInput = []; - if (!grid.atXBeginning) { - grid.positionViewAtBeginning(); - } - for(var i = 0; i < grid.model; i++) { - if(grid.itemAtIndex(i)) { - grid.itemAtIndex(i).textEdit.text = "" - grid.itemAtIndex(i).textEdit.reset() - } - } - grid.isValid = false - } - - function validate() { - _internal.errorString = "" - if (!Utils.isMnemonic(mnemonicString)) { - _internal.errorString = qsTr("Invalid seed phrase") - } else { - if (!RootStore.validSeedPhrase(mnemonicString)) { - _internal.errorString = qsTr("Invalid seed phrase") + '. ' + - qsTr("This seed phrase doesn't match our supported dictionary. Check for misspelled words.") - } - } - return _internal.errorString === "" - } - - QtObject { - id: _internal - property int seedPhraseInputWidth: (parent.width/2) - property int seedPhraseInputHeight: 48 - property var mnemonicInput: [] - property string errorString: "" - readonly property var seedPhraseWordsOptions: [12, 18, 24] - - function getSeedPhraseString() { - var seedPhrase = "" - for(var i = 0; i < grid.model; i++) { - if(!!grid.itemAtIndex(i)) { - seedPhrase += grid.itemAtIndex(i).text + " " - } - } - return seedPhrase - } - } - - cellWidth: _internal.seedPhraseInputWidth - cellHeight: _internal.seedPhraseInputHeight - interactive: false - z: 100000 - - onModelChanged: { - mnemonicString = ""; - let menmonicInputTemp = _internal.mnemonicInput.filter(function(value) { - return value.pos <= grid.count - }) - _internal.mnemonicInput = [] - for (let i = 0; i < menmonicInputTemp.length; i++) { - // .pos starts with 1 - grid.itemAtIndex(menmonicInputTemp[i].pos - 1).setWord(menmonicInputTemp[i].seed) - grid.addWord(menmonicInputTemp[i].pos, - menmonicInputTemp[i].seed, - true) - } - } - - Timer { - id: timer - } - - - onIsValidChanged: { - if(isValid) { - mnemonicString = _internal.getSeedPhraseString() - } - } - - onVisibleChanged: { - if(visible) { - grid.itemAtIndex(0).textEdit.input.edit.forceActiveFocus() - } - } - - function pasteWords () { - const clipboardText = globalUtils.getFromClipboard() - // Split words separated by commas and or blank spaces (spaces, enters, tabs) - let words = clipboardText.split(/[, \s]+/) - - let timeout = 0 - let indexOfWordsOption = _internal.seedPhraseWordsOptions.indexOf(words.length) - if(indexOfWordsOption == -1) { - return false - } - footerItem.switchToIndex(indexOfWordsOption) - timeout = 100 - - timer.setTimeout(function(){ - _internal.mnemonicInput = [] - for (let i = 0; i < words.length; i++) { - const item = grid.itemAtIndex(i) - if (item && item.leftComponentText) - item.setWord(words[i]) - } - }, timeout); - - return true - } - - function addWord(pos, word, ignoreGoingNext) { - _internal.mnemonicInput.push({"pos": pos, "seed": word.replace(/\s/g, '')}); - for (var j = 0; j < _internal.mnemonicInput.length; j++) { - if (_internal.mnemonicInput[j].pos === pos && _internal.mnemonicInput[j].seed !== word) { - _internal.mnemonicInput[j].seed = word; - } - } - //remove duplicates - var valueArr = _internal.mnemonicInput.map(function(item){ return item.pos }); - var isDuplicate = valueArr.some(function(item, idx){ - if (valueArr.indexOf(item) !== idx) { - _internal.mnemonicInput.splice(idx, 1); - } - return valueArr.indexOf(item) !== idx - }); - if (!ignoreGoingNext) { - for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) { - if (parseInt(grid.itemAtIndex(i).leftComponentText) === (parseInt(pos)+1)) { - grid.currentIndex = grid.itemAtIndex(i).itemIndex; - grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(); - if (grid.currentIndex === 11) { - grid.positionViewAtEnd(); - if (grid.count === 20) { - grid.contentX = 1500; - } - } - } - } - } - grid.isValid = (_internal.mnemonicInput.length === grid.model); - } - - delegate: StatusSeedPhraseInput { - id: statusSeedInput - width: grid.cellWidth - (Style.current.halfPadding/2) - height: (grid.cellHeight - Style.current.halfPadding) - textEdit.errorMessageCmp.visible: false - textEdit.input.placeholder.objectName: "seedPhraseInputPlaceholder" + index - leftComponentText: index + 1 - inputList: BIP39_en { } - property int itemIndex: index - z: (grid.currentIndex === index) ? 150000000 : 0 - onDoneInsertingWord: { - grid.addWord(leftComponentText, word) - } - onEditClicked: { - grid.currentIndex = index; - grid.itemAtIndex(index).textEdit.input.edit.forceActiveFocus(); - } - onKeyPressed: { - if (event.key === Qt.Key_Backtab) { - for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) { - if (parseInt(grid.itemAtIndex(i).leftComponentText) === ((parseInt(leftComponentText)-1) >= 0 ? (parseInt(leftComponentText)-1) : 0)) { - grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(Qt.TabFocusReason); - textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit; - event.accepted = true - break - } - } - } else if (event.key === Qt.Key_Tab) { - for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) { - if (parseInt(grid.itemAtIndex(i).leftComponentText) === ((parseInt(leftComponentText)+1) <= grid.count ? (parseInt(leftComponentText)+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 (grid.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 - grid.enterPressed() - return - } - - if (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) { - var wordIndex = _internal.mnemonicInput.findIndex(x => x.pos === leftComponentText); - if (wordIndex > -1) { - _internal.mnemonicInput.splice(wordIndex , 1); - grid.isValid = _internal.mnemonicInput.length === grid.model - } - } - - grid.currentIndex = index; - } - } - footer: Item { - id: footerC - function switchToIndex(index) { - changeSeedNbWordsTabBar.currentIndex = index - } - width: grid.width - (Style.current.halfPadding/2) - height: changeSeedNbWordsTabBar.height + errorMessage.height + Style.current.padding*2 - StatusBaseText { - id: errorMessage - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: Style.current.padding - - height: visible ? implicitHeight : 0 - visible: !!text - text: _internal.errorString - - font.pixelSize: 12 - color: Theme.palette.dangerColor1 - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - } - StatusSwitchTabBar { - id: changeSeedNbWordsTabBar - width: parent.width - anchors.top: errorMessage.bottom - anchors.topMargin: Style.current.padding - Repeater { - model: _internal.seedPhraseWordsOptions - StatusSwitchTabButton { - text: qsTr("%n word(s)", "", modelData) - } - } - onCurrentIndexChanged: { - grid.model = _internal.seedPhraseWordsOptions[changeSeedNbWordsTabBar.currentIndex] - } - } - } -} - - diff --git a/ui/app/AppLayouts/Wallet/panels/SelectGeneratedAccount.qml b/ui/app/AppLayouts/Wallet/panels/SelectGeneratedAccount.qml deleted file mode 100644 index 6914a080fb..0000000000 --- a/ui/app/AppLayouts/Wallet/panels/SelectGeneratedAccount.qml +++ /dev/null @@ -1,139 +0,0 @@ -import QtQuick 2.12 -import QtQml.Models 2.14 - -import StatusQ.Core.Theme 0.1 -import StatusQ.Controls 0.1 -import StatusQ.Components 0.1 -import StatusQ.Core.Utils 0.1 - -import utils 1.0 -import "../stores" - -StatusSelect { - id: selectAccountType - - property int addAccountType - property string derivedFromAddress: "" - property string selectedKeyUid: userProfile.keyUid - property bool selectedKeyUidMigratedToKeycard: userProfile.isKeycardUser - - function resetMe() { - _internal.getGeneratedAccountsModel() - selectAccountType.addAccountType = Constants.AddAccountType.GenerateNew - selectAccountType.selectedKeyUid = userProfile.keyUid - selectAccountType.selectedKeyUidMigratedToKeycard = userProfile.isKeycardUser - } - - Connections { - target: RootStore.generatedAccountsViewModel - function onModelReset() { - _internal.delegateModel.model = RootStore.generatedAccountsViewModel - _internal.getGeneratedAccountsModel() - } - } - - QtObject { - id: _internal - property string importSeedPhraseID: "importNewSeedPhrase" - property string importPrivateKeyID: "generateFromPrivateKey" - property string addWatchOnlyAccountID: "watchOnlyAccount" - - property var delegateModel: DelegateModel { - model: RootStore.generatedAccountsViewModel - onModelUpdated: { - _internal.getGeneratedAccountsModel() - } - } - property ListModel generatedAccountsModel: ListModel{} - - function getGeneratedAccountsModel() { - if(generatedAccountsModel) { - generatedAccountsModel.clear() - for (var row = 0; row < _internal.delegateModel.model.count; row++) { - if (_internal.delegateModel.items.count > 0) { - var item = _internal.delegateModel.items.get(row).model; - generatedAccountsModel.append({"name": item.name, "iconName": item.iconName, "generatedModel": item.generatedModel, "derivedfrom": item.derivedfrom, "isHeader": false, - "keyUid": item.keyUid, "migratedToKeycard": item.migratedToKeycard}) - if (row === 0 && _internal.delegateModel.model.count > 1) { - generatedAccountsModel.append({"name": qsTr("Imported"), "iconName": "", "derivedfrom": "", "isHeader": true, "keyUid": "", "migratedToKeycard": false}) - } - } - } - generatedAccountsModel.append({"name": qsTr("Add new"), "iconName": "", "derivedfrom": "", "isHeader": true, "keyUid": "", "migratedToKeycard": false}) - generatedAccountsModel.append({"name": qsTr("Import new Seed Phrase"), "iconName": "seed-phrase", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false, "objectName": _internal.importSeedPhraseID}) - generatedAccountsModel.append({"name": qsTr("Generate from Private key"), "iconName": "password", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false, "objectName": _internal.importPrivateKeyID}) - generatedAccountsModel.append({"name": qsTr("Add a watch-only address"), "iconName": "show", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false, "objectName": _internal.addWatchOnlyAccountID}) - } - } - } - - label: qsTr("Origin") - model: _internal.generatedAccountsModel - selectedItemComponent: StatusListItem { - id: selectedItem - asset.bgColor: "transparent" - border.width: 1 - border.color: Theme.palette.baseColor2 - tagsDelegate: StatusListItemTag { - bgColor: model.color - bgRadius: 6 - height: Style.current.bigPadding - closeButtonVisible: false - asset.emoji: model.emoji - asset.emojiSize: Emoji.size.verySmall - asset.isLetterIdenticon: true - title: model.name - titleText.font.pixelSize: 12 - titleText.color: Theme.palette.indirectColor1 - } - } - menuDelegate: StatusListItem { - id: defaultListItem - objectName: !!model.objectName ? model.objectName : "" - title: model.name - asset.name: model.iconName - tagsModel : model.generatedModel - enabled: !model.isHeader - asset.bgColor: "transparent" - asset.color: model.generatedModel ? Theme.palette.primaryColor1 : Theme.palette.directColor5 - tagsDelegate: StatusListItemTag { - bgColor: model.color - bgRadius: 6 - height: 24 - closeButtonVisible: false - asset.emoji: model.emoji - asset.emojiSize: Emoji.size.verySmall - asset.isLetterIdenticon: true - title: model.name - titleText.font.pixelSize: 12 - titleText.color: Theme.palette.indirectColor1 - } - onClicked: { - selectAccountType.addAccountType = (model.objectName === _internal.importSeedPhraseID) ? Constants.AddAccountType.ImportSeedPhrase : - (model.objectName === _internal.importPrivateKeyID) ? Constants.AddAccountType.ImportPrivateKey : - (model.objectName === _internal.addWatchOnlyAccountID) ? Constants.AddAccountType.WatchOnly : - Constants.AddAccountType.GenerateNew - selectedItem.title = model.name - selectedItem.asset.name = model.iconName - selectedItem.tagsModel = model.generatedModel - selectedItem.enabled = !model.isHeader - - selectAccountType.derivedFromAddress = model.derivedfrom - selectAccountType.selectedKeyUid = model.keyUid - selectAccountType.selectedKeyUidMigratedToKeycard = model.migratedToKeycard - - selectMenu.close() - } - Component.onCompleted: { - if(index === 0) { - selectedItem.title = model.name - selectedItem.asset.name = model.iconName - selectedItem.tagsModel = model.generatedModel - selectedItem.enabled = !model.isHeader - selectAccountType.derivedFromAddress = model.derivedfrom - } - } - } -} - - diff --git a/ui/app/AppLayouts/Wallet/popups/AddAccountModal.qml b/ui/app/AppLayouts/Wallet/popups/AddAccountModal.qml deleted file mode 100644 index 04f2821524..0000000000 --- a/ui/app/AppLayouts/Wallet/popups/AddAccountModal.qml +++ /dev/null @@ -1,352 +0,0 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQuick.Dialogs 1.3 -import QtQuick.Layouts 1.14 - -import utils 1.0 - -import StatusQ.Core 0.1 -import StatusQ.Core.Theme 0.1 -import StatusQ.Core.Utils 0.1 as StatusQUtils -import StatusQ.Controls 0.1 -import StatusQ.Controls.Validators 0.1 -import StatusQ.Popups 0.1 -import StatusQ.Components 0.1 - -import shared.controls 1.0 - -import "../stores" -import "../views" -import "../panels" - -StatusModal { - id: root - - readonly property int marginBetweenInputs: 38 - property var emojiPopup: null - - header.title: qsTr("Generate an account") - closePolicy: nextButton.loading? Popup.NoAutoClose : Popup.CloseOnEscape - hasCloseButton: !nextButton.loading - - signal afterAddAccount() - - Connections { - target: emojiPopup - enabled: root.opened - - function onEmojiSelected (emojiText, atCursor) { - accountNameInput.input.asset.emoji = emojiText - } - } - - Connections { - target: walletSectionAccounts - function onUserAuthenticationSuccess(password: string) { - validationError.text = "" - d.password = password - RootStore.loggedInUserAuthenticated = true - if (d.selectedAccountType === Constants.AddAccountType.ImportPrivateKey) { - d.generateNewAccount() - } - else { - if (!d.selectedKeyUidMigratedToKeycard) { - d.getDerivedAddressList() - } - } - } - function onUserAuthentiactionFail() { - d.password = "" - RootStore.loggedInUserAuthenticated = false - validationError.text = qsTr("An authentication failed") - nextButton.loading = false - } - } - - QtObject { - id: d - - readonly property int numOfItems: 100 - readonly property int pageNumber: 1 - - property string password: "" - property int selectedAccountType: Constants.AddAccountType.GenerateNew - property string selectedAccountDerivedFromAddress: "" - property string selectedKeyUid: RootStore.defaultSelectedKeyUid - property bool selectedKeyUidMigratedToKeycard: RootStore.defaultSelectedKeyUidMigratedToKeycard - property string selectedPath: "" - property string selectedAddress: "" - property bool selectedAddressAvailable: false - property bool useFullyCustomPath: false - - readonly property bool authenticationNeeded: d.selectedAccountType !== Constants.AddAccountType.WatchOnly && - d.password === "" - property string addAccountIcon: "" - - property bool isLoading: RootStore.derivedAddressesLoading - onIsLoadingChanged: { - if(!isLoading && nextButton.loading) { - d.generateNewAccount() - } - } - - function getDerivedAddressList() { - if (d.useFullyCustomPath) { - if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress - && (d.password.length > 0)) { - RootStore.getDerivedAddressList(d.password, d.selectedAccountDerivedFromAddress, - d.selectedPath, numOfItems, pageNumber, - !(d.selectedKeyUidMigratedToKeycard || userProfile.isKeycardUser)) - } - } else if(d.selectedAccountType === Constants.AddAccountType.ImportSeedPhrase - && !!advancedSelection.expandableItem.path - && !!advancedSelection.expandableItem.mnemonicText) { - RootStore.getDerivedAddressListForMnemonic(advancedSelection.expandableItem.mnemonicText, - advancedSelection.expandableItem.path, numOfItems, pageNumber) - } else if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress - && (d.password.length > 0)) { - RootStore.getDerivedAddress(d.password, d.selectedAccountDerivedFromAddress, d.selectedPath, - !(d.selectedKeyUidMigratedToKeycard || userProfile.isKeycardUser)) - } - } - - function generateNewAccount() { - // TODO the loading doesn't work because the function freezes the view. Might need to use threads - if (!advancedSelection.validate()) { - Global.playErrorSound() - return nextButton.loading = false - } - - let errMessage = "" - - switch(d.selectedAccountType) { - case Constants.AddAccountType.GenerateNew: - if (d.selectedKeyUidMigratedToKeycard) { - errMessage = RootStore.addNewWalletAccountGeneratedFromKeycard(Constants.generatedWalletType, - accountNameInput.text, - colorSelectionGrid.selectedColor, - accountNameInput.input.asset.emoji) - } - else { - let finalFullPath = advancedSelection.expandableItem.completePath - if (!d.useFullyCustomPath) { - finalFullPath = d.selectedPath - } - errMessage = RootStore.generateNewAccount(d.password, accountNameInput.text, colorSelectionGrid.selectedColor, - accountNameInput.input.asset.emoji, finalFullPath, - advancedSelection.expandableItem.derivedFromAddress) - } - break - case Constants.AddAccountType.ImportSeedPhrase: - errMessage = RootStore.addAccountsFromSeed(advancedSelection.expandableItem.mnemonicText, d.password, - accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji, - advancedSelection.expandableItem.completePath) - break - case Constants.AddAccountType.ImportPrivateKey: - errMessage = RootStore.addAccountsFromPrivateKey(advancedSelection.expandableItem.privateKey, d.password, - accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji) - break - case Constants.AddAccountType.WatchOnly: - errMessage = RootStore.addWatchOnlyAccount(advancedSelection.expandableItem.watchAddress, accountNameInput.text, - colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji) - break - } - - nextButton.loading = false - - if (errMessage) { - console.warn(`Unhandled error case. Status-go message: ${errMessage}`) - } else { - root.afterAddAccount() - root.close() - } - } - - function nextButtonClicked() { - nextButton.loading = true - if (d.authenticationNeeded) { - d.password = "" - if (d.selectedKeyUidMigratedToKeycard && - d.selectedAccountType === Constants.AddAccountType.GenerateNew) { - RootStore.authenticateUserAndDeriveAddressOnKeycardForPath(d.selectedKeyUid, d.selectedPath, true) - } - else { - RootStore.authenticateUser() - } - } - else { - d.generateNewAccount() - } - } - } - - onOpened: { - RootStore.loggedInUserAuthenticated = false - d.addAccountIcon = "password" - if (RootStore.loggedInUserUsesBiometricLogin()) { - d.addAccountIcon = "touch-id" - } - else if (RootStore.loggedInUserIsKeycardUser()) { - d.addAccountIcon = "keycard" - } - - accountNameInput.input.asset.emoji = StatusQUtils.Emoji.getRandomEmoji(StatusQUtils.Emoji.size.verySmall) - colorSelectionGrid.selectedColorIndex = Math.floor(Math.random() * colorSelectionGrid.model.length) - accountNameInput.input.edit.forceActiveFocus() - } - - onClosed: { - RootStore.loggedInUserAuthenticated = false - d.password = "" - validationError.text = "" - accountNameInput.reset() - advancedSelection.expanded = false - advancedSelection.reset() - } - - contentItem: StatusScrollView { - id: scroll - implicitWidth: root.width - implicitHeight: 400 - topPadding: Style.current.halfPadding - bottomPadding: Style.current.halfPadding - leftPadding: Style.current.padding - rightPadding: Style.current.padding - objectName: "AddAccountModalContent" - - Column { - property alias accountNameInput: accountNameInput - width: scroll.availableWidth - spacing: Style.current.halfPadding - topPadding: 20 - - StatusBaseText { - id: validationError - visible: text !== "" - width: parent.width - height: 16 - horizontalAlignment: Text.AlignHCenter - font.pixelSize: 12 - color: Style.current.danger - wrapMode: TextEdit.Wrap - } - - StatusInput { - id: accountNameInput - placeholderText: qsTr("Enter an account name...") - label: qsTr("Account name") - input.isIconSelectable: true - input.asset.color: colorSelectionGrid.selectedColor ? colorSelectionGrid.selectedColor : Theme.palette.directColor1 - input.leftPadding: Style.current.padding - onIconClicked: { - root.emojiPopup.open() - root.emojiPopup.emojiSize = StatusQUtils.Emoji.size.verySmall - root.emojiPopup.x = root.x + accountNameInput.x + Style.current.padding - root.emojiPopup.y = root.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding - } - validators: [ - StatusMinLengthValidator { - errorMessage: qsTr("You need to enter an account name") - minLength: 1 - } - ] - onKeyPressed: { - if(event.key === Qt.Key_Tab) { - if (nextButton.enabled) { - nextButton.forceActiveFocus(Qt.MouseFocusReason) - event.accepted = true - } - } - } - } - - StatusColorSelectorGrid { - id: colorSelectionGrid - anchors.horizontalCenter: parent.horizontalCenter - enabled: accountNameInput.valid - titleText: qsTr("color").toUpperCase() - } - - StatusExpandableItem { - id: advancedSelection - - property bool isValid: true - - function validate() { - return !!expandableItem && expandableItem.validate() - } - - function reset() { - return !!expandableItem && expandableItem.reset() - } - - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - - primaryText: qsTr("Advanced") - type: StatusExpandableItem.Type.Tertiary - expandable: true - expandableComponent: AdvancedAddAccountView { - width: parent.width - onCalculateDerivedPath: { - d.selectedAccountDerivedFromAddress = derivedFromAddress - d.selectedPath = path - if (d.selectedKeyUidMigratedToKeycard) { - d.password = "" - validationError.text = "" - RootStore.loggedInUserAuthenticated = false - } - else{ - d.getDerivedAddressList() - } - } - onEnterPressed: { - if (nextButton.enabled) { - nextButton.clicked(null) - return - } - } - - Component.onCompleted: { - d.selectedAccountType = Qt.binding(() => addAccountType) - d.selectedAccountDerivedFromAddress = Qt.binding(() => derivedFromAddress) - d.selectedKeyUid = Qt.binding(() => selectedKeyUid) - d.selectedKeyUidMigratedToKeycard = Qt.binding(() => selectedKeyUidMigratedToKeycard) - d.selectedPath = Qt.binding(() => path) - d.selectedAddress = Qt.binding(() => selectedAddress) - d.selectedAddressAvailable = Qt.binding(() => selectedAddressAvailable) - d.useFullyCustomPath = Qt.binding(() => useFullyCustomPath) - advancedSelection.isValid = Qt.binding(() => isValid) - } - } - } - } - } - - rightButtons: [ - StatusButton { - id: nextButton - - text: { - if (loading) { - return qsTr("Loading...") - } - return qsTr("Add account") - } - - enabled: { - if (!accountNameInput.valid || - loading || - ((root.authenticationNeeded && !d.useFullyCustomPath) && !d.selectedAddressAvailable)) { - return false - } - return advancedSelection.isValid - } - - icon.name: d.authenticationNeeded? d.addAccountIcon : "" - highlighted: focus - - onClicked : d.nextButtonClicked() - } - ] -} diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml index 359cc2adbd..8b651504d6 100644 --- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml @@ -18,7 +18,6 @@ QtObject { property string backButtonName: "" property var currentAccount: Constants.isCppApp ? walletSectionAccounts.currentAccount: walletSectionCurrent property var accounts: walletSectionAccounts.model - property var generatedAccounts: walletSectionAccounts.generated property var appSettings: localAppSettings property var accountSensitiveSettings: localAccountSensitiveSettings property bool hideSignPhraseModal: accountSensitiveSettings.hideSignPhraseModal @@ -55,10 +54,6 @@ QtObject { return d.chainColors[chainShortName] } - // Used for new wallet account generation - property var generatedAccountsViewModel: walletSectionAccounts.generatedAccounts - property var derivedAddressesList: walletSectionAccounts.derivedAddresses - property var layer1Networks: networksModule.layer1 property var layer2Networks: networksModule.layer2 property var testNetworks: networksModule.test @@ -114,9 +109,6 @@ QtObject { } } - property bool derivedAddressesLoading: walletSectionAccounts.derivedAddressesLoading - property string derivedAddressesError: walletSectionAccounts.derivedAddressesError - function setHideSignPhraseModal(value) { localAccountSensitiveSettings.hideSignPhraseModal = value; } @@ -143,26 +135,6 @@ QtObject { walletSection.switchAccountByAddress(address) } - function generateNewAccount(password, accountName, color, emoji, path, derivedFrom) { - return walletSectionAccounts.generateNewAccount(password, accountName, color, emoji, path, derivedFrom) - } - - function addNewWalletAccountGeneratedFromKeycard(accountType, accountName, color, emoji) { - return walletSectionAccounts.addNewWalletAccountGeneratedFromKeycard(accountType, accountName, color, emoji) - } - - function addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji) { - return walletSectionAccounts.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji) - } - - function addAccountsFromSeed(seedPhrase, password, accountName, color, emoji, path) { - return walletSectionAccounts.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji, path) - } - - function addWatchOnlyAccount(address, accountName,color, emoji) { - return walletSectionAccounts.addWatchOnlyAccount(address, accountName, color, emoji) - } - function deleteAccount(address) { return walletSectionAccounts.deleteAccount(address) } @@ -215,72 +187,4 @@ QtObject { function copyToClipboard(text) { globalUtils.copyToClipboard(text) } - - function getDerivedAddress(password, derivedFrom, path, hashPassword) { - walletSectionAccounts.getDerivedAddress(password, derivedFrom, path, hashPassword) - } - - function getDerivedAddressList(password, derivedFrom, path, pageSize, pageNumber, hashPassword) { - walletSectionAccounts.getDerivedAddressList(password, derivedFrom, path, pageSize, pageNumber, hashPassword) - } - - function getDerivedAddressData(index) { - return walletSectionAccounts.getDerivedAddressAtIndex(index) - } - - function getDerivedAddressPathData(index) { - return walletSectionAccounts.getDerivedAddressPathAtIndex(index) - } - - function getDerivedAddressHasActivityData(index) { - return walletSectionAccounts.getDerivedAddressHasActivityAtIndex(index) - } - - function getDerivedAddressAlreadyCreatedData(index) { - return walletSectionAccounts.getDerivedAddressAlreadyCreatedAtIndex(index) - } - - function getDerivedAddressListForMnemonic(mnemonic, path, pageSize , pageNumber) { - walletSectionAccounts.getDerivedAddressListForMnemonic(mnemonic, path, pageSize , pageNumber) - } - - function getDerivedAddressForPrivateKey(privateKey) { - walletSectionAccounts.getDerivedAddressForPrivateKey(privateKey) - } - - function resetDerivedAddressModel() { - walletSectionAccounts.resetDerivedAddressModel() - } - - function validSeedPhrase(mnemonic) { - return walletSectionAccounts.validSeedPhrase(mnemonic) - } - - function getNextSelectableDerivedAddressIndex() { - return walletSectionAccounts.getNextSelectableDerivedAddressIndex() - } - - function authenticateUser() { - walletSectionAccounts.authenticateUser() - } - - function loggedInUserUsesBiometricLogin() { - return userProfile.usingBiometricLogin - } - - function loggedInUserIsKeycardUser() { - return userProfile.isKeycardUser - } - - function createSharedKeycardModule() { - walletSectionAccounts.createSharedKeycardModule() - } - - function destroySharedKeycarModule() { - walletSectionAccounts.destroySharedKeycarModule() - } - - function authenticateUserAndDeriveAddressOnKeycardForPath(keyUid, derivationPath, searchForFirstAvailableAddress) { - walletSectionAccounts.authenticateUserAndDeriveAddressOnKeycardForPath(keyUid, derivationPath, searchForFirstAvailableAddress) - } } diff --git a/ui/app/AppLayouts/Wallet/views/AdvancedAddAccountView.qml b/ui/app/AppLayouts/Wallet/views/AdvancedAddAccountView.qml deleted file mode 100644 index 6b65e218c2..0000000000 --- a/ui/app/AppLayouts/Wallet/views/AdvancedAddAccountView.qml +++ /dev/null @@ -1,205 +0,0 @@ -import QtQuick 2.14 -import QtQuick.Controls 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.Popups 0.1 -import StatusQ.Components 0.1 -import StatusQ.Controls.Validators 0.1 - -import utils 1.0 -import "../stores" -import "../panels" - -ColumnLayout { - id: advancedSection - - readonly property alias useFullyCustomPath: fullyCustomPathCheckBox.checked - property int addAccountType: Constants.AddAccountType.GenerateNew - property string selectedKeyUid: RootStore.defaultSelectedKeyUid - property bool selectedKeyUidMigratedToKeycard: RootStore.defaultSelectedKeyUidMigratedToKeycard - property string selectedAddress: "" - property bool selectedAddressAvailable: false - property string enterPasswordIcon: "" - property string derivedFromAddress: "" - property string mnemonicText: "" - property alias privateKey: importPrivateKeyPanel.text - property string path: "" - property string pathSubFix: "" - property string completePath: path + "/" + pathSubFix - property alias watchAddress: addressInput.text - property bool isValid: addAccountType === Constants.AddAccountType.ImportSeedPhrase ? importSeedPhrasePanel.isValid : - addAccountType === Constants.AddAccountType.ImportPrivateKey ? (importPrivateKeyPanel.text !== "" && importPrivateKeyPanel.valid) : - addAccountType === Constants.AddAccountType.WatchOnly ? (addressInput.text !== "" && addressInput.valid) : true - - signal calculateDerivedPath() - signal enterPressed() - - objectName: "advancedAddAccountViewRoot" - - function reset() { - //reset selectGeneratedAccount - selectGeneratedAccount.resetMe() - - // reset privateKey - importPrivateKeyPanel.resetMe() - - // reset importSeedPhrasePanel - importSeedPhrasePanel.reset() - - // reset derivation path - derivationPathsPanel.reset() - - // reset derviedAccountsList - derivedAddressesPanel.reset() - - // reset watch only address input - addressInput.text = "" - addressInput.reset() - } - - function validate() { - if(addAccountType === Constants.AddAccountType.ImportSeedPhrase) { - // validate mnemonic - return importSeedPhrasePanel.validate() - } - else if(addAccountType === Constants.AddAccountType.ImportPrivateKey) { - // validate privateKey - return importPrivateKeyPanel.validateMe() - } - else if(addAccountType === Constants.AddAccountType.WatchOnly) { - return addressInput.valid - } - - return true - } - - onPathChanged: { - if(addAccountType === Constants.AddAccountType.ImportSeedPhrase) { - if(importSeedPhrasePanel.isValid) { - advancedSection.calculateDerivedPath() - } - } - else { - advancedSection.calculateDerivedPath() - } - } - - onDerivedFromAddressChanged: { - // reset derviedAccountsList - derivedAddressesPanel.reset() - - if(addAccountType === Constants.AddAccountType.ImportSeedPhrase) { - if(importSeedPhrasePanel.isValid) { - advancedSection.calculateDerivedPath() - } - } - else { - advancedSection.calculateDerivedPath() - } - } - - spacing: Style.current.padding - - SelectGeneratedAccount { - id: selectGeneratedAccount - objectName: "selectGeneratedAccount" - Component.onCompleted: { - advancedSection.addAccountType = Qt.binding(function() {return addAccountType}) - advancedSection.derivedFromAddress = Qt.binding(function() {return derivedFromAddress}) - advancedSection.selectedKeyUid = Qt.binding(function() {return selectedKeyUid}) - advancedSection.selectedKeyUidMigratedToKeycard = Qt.binding(function() {return selectedKeyUidMigratedToKeycard}) - } - } - - ImportPrivateKeyPanel { - id: importPrivateKeyPanel - visible: advancedSection.addAccountType === Constants.AddAccountType.ImportPrivateKey && advancedSection.visible - } - - ImportSeedPhrasePanel { - id: importSeedPhrasePanel - Layout.preferredWidth: parent.width - Layout.preferredHeight: visible ? importSeedPhrasePanel.preferredHeight: 0 - Layout.leftMargin: (Style.current.halfPadding/4) - visible: advancedSection.addAccountType === Constants.AddAccountType.ImportSeedPhrase && advancedSection.visible - onMnemonicStringChanged: { - advancedSection.mnemonicText = mnemonicString - if(isValid) { - calculateDerivedPath() - } - } - onEnterPressed: advancedSection.enterPressed() - } - - StatusInput { - id: addressInput - input.placeholder.objectName: "advancedAddAccountViewAddressInputPlaceholder" - input.objectName: "advancedAddAccountViewAddressInput" - visible: advancedSection.addAccountType === Constants.AddAccountType.WatchOnly && advancedSection.visible - placeholderText: qsTr("Enter address...") - label: qsTr("Account address") - validators: [ - StatusAddressValidator { - errorMessage: qsTr("This needs to be a valid address (starting with 0x)") - }, - StatusMinLengthValidator { - errorMessage: qsTr("You need to enter an address") - minLength: 1 - } - ] - } - - ColumnLayout { - Layout.preferredWidth: parent.width - spacing: 0 - - RowLayout { - Layout.preferredWidth: advancedSection.width - Layout.rightMargin: 2 - spacing: Style.current.bigPadding - visible: advancedSection.addAccountType !== Constants.AddAccountType.ImportPrivateKey && - advancedSection.addAccountType !== Constants.AddAccountType.WatchOnly - - readonly property int itemWidth: (advancedSection.width - Style.current.bigPadding) * 0.5 - - DerivationPathsPanel { - id: derivationPathsPanel - useFullyCustomPath: fullyCustomPathCheckBox.checked - Layout.preferredWidth: parent.itemWidth - Layout.alignment: Qt.AlignTop - Component.onCompleted: advancedSection.path = Qt.binding(function() { return derivationPathsPanel.path}) - } - DerivedAddressesPanel { - id: derivedAddressesPanel - Layout.preferredWidth: parent.itemWidth - Layout.alignment: Qt.AlignTop - - selectedAccountType: advancedSection.addAccountType - selectedKeyUid: advancedSection.selectedKeyUid - selectedKeyUidMigratedToKeycard: advancedSection.selectedKeyUidMigratedToKeycard - selectedPath: advancedSection.path - - Component.onCompleted: { - advancedSection.selectedAddress = Qt.binding(function() { return derivedAddressesPanel.selectedAddress}) - advancedSection.selectedAddressAvailable = Qt.binding(function() { return derivedAddressesPanel.selectedAddressAvailable}) - advancedSection.pathSubFix = Qt.binding(function() { return derivedAddressesPanel.pathSubFix}) - } - } - } - - StatusCheckBox { - id: fullyCustomPathCheckBox - objectName: "fullyCustomPathCheckBox" - visible: advancedSection.addAccountType === Constants.AddAccountType.GenerateNew - Layout.preferredWidth: advancedSection.width - text: qsTr("I acknowledge that by adding an account out of the default Status derivation path I will not be able to migrate a keypair to a Keycard") - onToggled: { - advancedSection.reset() - } - } - } -} - diff --git a/ui/app/AppLayouts/Wallet/views/LeftTabView.qml b/ui/app/AppLayouts/Wallet/views/LeftTabView.qml index 45d3427a34..7294b8c205 100644 --- a/ui/app/AppLayouts/Wallet/views/LeftTabView.qml +++ b/ui/app/AppLayouts/Wallet/views/LeftTabView.qml @@ -32,41 +32,8 @@ Rectangle { property var emojiPopup: null - function onAfterAddAccount () { - root.changeSelectedAccount(RootStore.accounts.rowCount() - 1) - } - color: Style.current.secondaryMenuBackground - Loader { - id: addAccountModal - active: false - asynchronous: true - - function open() { - if (!active) { - RootStore.createSharedKeycardModule() - active = true - } - item.open() - } - - function close() { - if (item) { - RootStore.destroySharedKeycarModule() - item.close() - } - active = false - } - - sourceComponent: AddAccountModal { - anchors.centerIn: parent - onAfterAddAccount: root.onAfterAddAccount() - emojiPopup: root.emojiPopup - onClosed: addAccountModal.close() - } - } - ColumnLayout { anchors.fill: parent spacing: Style.current.padding @@ -96,7 +63,6 @@ Rectangle { height: parent.height * 2 color: hovered || highlighted ? Theme.palette.primaryColor3 : "transparent" - onClicked: addAccountModal.open() } } diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 674d5fdaf8..43d031b81d 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -813,12 +813,6 @@ QtObject { NoError } - enum AddAccountType { - GenerateNew, - ImportSeedPhrase, - ImportPrivateKey, - WatchOnly - } readonly property QtObject walletSection: QtObject { readonly property string cancelledMessage: "cancelled"