feat(@desktop/wallet): edit account reusing new "Add Account" popup

Closes: #9847
This commit is contained in:
Sale Djenic 2023-03-30 15:00:55 +02:00 committed by saledjenic
parent 3325241b0f
commit ea53fce030
24 changed files with 358 additions and 43 deletions

View File

@ -114,14 +114,17 @@ proc getSeedPhrase*(self: Controller): string =
proc closeAddAccountPopup*(self: Controller) =
self.delegate.closeAddAccountPopup()
proc getWalletAccount*(self: Controller, address: string): WalletAccountDto =
return self.walletAccountService.getAccountByAddress(address)
proc getWalletAccounts*(self: Controller): seq[WalletAccountDto] =
return self.walletAccountService.fetchAccounts()
proc getAllMigratedKeyPairs*(self: Controller): seq[KeyPairDto] =
return self.walletAccountService.getAllMigratedKeyPairs()
proc addAccount*(self: Controller) =
self.delegate.addAccount()
proc finalizeAction*(self: Controller) =
self.delegate.finalizeAction()
proc authenticateOrigin*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_WALLET_SECTION_ADD_ACCOUNTS_MODULE_IDENTIFIER,
@ -182,6 +185,9 @@ proc addNewSeedPhraseAccount*(self: Controller, seedPhrase: string, doPasswordHa
return false
return true
proc updateAccount*(self: Controller, address: string, accountName: string, color: string, emoji: string): bool =
return self.walletAccountService.updateWalletAccount(address, accountName, color, emoji)
proc getKeyUidForSeedPhrase*(self: Controller, seedPhrase: string): string =
let acc = self.accountsService.createAccountFromMnemonic(seedPhrase)
return acc.keyUid

View File

@ -9,7 +9,7 @@ proc delete*(self: MainState) =
self.State.delete
method executePrePrimaryStateCommand*(self: MainState, controller: Controller) =
controller.addAccount()
controller.finalizeAction()
method getNextSecondaryState*(self: MainState, controller: Controller): State =
return createState(StateType.SelectMasterKey, self)

View File

@ -10,7 +10,10 @@ type
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface, addingWatchOnlyAccount: bool) {.base.} =
method loadForAddingAccount*(self: AccessInterface, addingWatchOnlyAccount: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method loadForEditingAccount*(self: AccessInterface, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method closeAddAccountPopup*(self: AccessInterface, switchToAccWithAddress: string = "") {.base.} =
@ -40,7 +43,7 @@ method onQuaternaryActionClicked*(self: AccessInterface) {.base.} =
method onCancelActionClicked*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method addAccount*(self: AccessInterface) {.base.} =
method finalizeAction*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method authenticateForEditingDerivationPath*(self: AccessInterface) {.base.} =

View File

@ -20,6 +20,7 @@ import ../../../../../app_service/service/keycard/service as keycard_service
export io_interface
const Label_NewWatchOnlyAccount = "LABEL-NEW-WATCH-ONLY-ACCOUNT"
const Label_WatchOnlyAccount = "LABEL-WATCH-ONLY-ACCOUNT"
const Label_Existing = "LABEL-EXISTING"
const Label_ImportNew = "LABEL-IMPORT-NEW"
const Label_OptionAddNewMasterKey = "LABEL-OPTION-ADD-NEW-MASTER-KEY"
@ -50,7 +51,7 @@ type
authenticationReason: AuthenticationReason
## Forward declaration
proc doAddingAccount[T](self: Module[T])
proc doAddAccount[T](self: Module[T])
proc newModule*[T](delegate: T,
events: EventEmitter,
@ -72,8 +73,9 @@ method delete*[T](self: Module[T]) =
self.viewVariant.delete
self.controller.delete
method load*[T](self: Module[T], addingWatchOnlyAccount: bool) =
method loadForAddingAccount*[T](self: Module[T], addingWatchOnlyAccount: bool) =
self.controller.init()
self.view.setEditMode(false)
self.view.setCurrentState(newMainState(nil))
var items = keypairs.buildKeyPairsList(self.controller.getWalletAccounts(), self.controller.getAllMigratedKeyPairs(),
@ -102,6 +104,62 @@ method load*[T](self: Module[T], addingWatchOnlyAccount: bool) =
self.changeSelectedOrigin(items[0].getKeyUid())
self.delegate.onAddAccountModuleLoaded()
method loadForEditingAccount*[T](self: Module[T], address: string) =
self.controller.init()
self.view.setEditMode(true)
self.view.setCurrentState(newMainState(nil))
let accountDto = self.controller.getWalletAccount(address)
var addressDetailsItem = newDerivedAddressItem(order = 0,
address = accountDto.address,
path = accountDto.path,
alreadyCreated = true,
hasActivity = false,
loaded = true)
self.view.setDisablePopup(false)
self.view.setStoredAccountName(accountDto.name)
self.view.setStoredSelectedColor(accountDto.color)
self.view.setStoredSelectedEmoji(accountDto.emoji)
self.view.setAccountName(accountDto.name)
self.view.setSelectedColor(accountDto.color)
self.view.setSelectedEmoji(accountDto.emoji)
if accountDto.walletType == WalletTypeWatch:
var item = newKeyPairItem(keyUid = Label_OptionAddWatchOnlyAcc)
item.setName(Label_WatchOnlyAccount)
item.setIcon("show")
self.view.setSelectedOrigin(item)
self.view.setWatchOnlyAccAddress(addressDetailsItem)
else:
var items = keypairs.buildKeyPairsList(self.controller.getWalletAccounts(), self.controller.getAllMigratedKeyPairs(),
excludeAlreadyMigratedPairs = false, excludePrivateKeyKeypairs = false)
if items.len == 0:
error "list of identified keypairs is empty, but it must have at least a profile keypair"
return
var selectedOrigin: KeyPairItem
for item in items:
if item.containsAccountAddress(address):
selectedOrigin = item
break
if selectedOrigin.isNil or selectedOrigin.getKeyUid().len == 0:
error "selected address for editing is not known among identified keypairs", address=address
return
if selectedOrigin.getPairType() == KeyPairType.Profile.int or
selectedOrigin.getPairType() == KeyPairType.SeedImport.int:
self.view.setSelectedDerivedAddress(addressDetailsItem)
elif selectedOrigin.getPairType() == KeyPairType.PrivateKeyImport.int:
self.view.setPrivateKeyAccAddress(addressDetailsItem)
self.view.setOriginModelItems(items)
self.view.setDerivationPath(accountDto.path)
self.view.setSelectedOrigin(selectedOrigin)
self.delegate.onAddAccountModuleLoaded()
proc tryKeycardSync[T](self: Module[T]) =
if self.controller.getPin().len == 0:
return
@ -112,7 +170,8 @@ proc tryKeycardSync[T](self: Module[T]) =
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC, dataForKeycardToSync)
method closeAddAccountPopup*[T](self: Module[T], switchToAccWithAddress: string = "") =
self.tryKeycardSync()
if not self.view.getEditMode():
self.tryKeycardSync()
self.delegate.destroyAddAccountPopup(switchToAccWithAddress)
method getModuleAsVariant*[T](self: Module[T]): QVariant =
@ -260,7 +319,7 @@ method onUserAuthenticated*[T](self: Module[T], pin: string, password: string, k
self.view.setDisablePopup(true)
let selectedOrigin = self.view.getSelectedOrigin()
if selectedOrigin.getPairType() == KeyPairType.PrivateKeyImport.int:
self.doAddingAccount() # we're sure that we need to add an account from priv key from here, cause derivation is not possible for imported priv key
self.doAddAccount() # we're sure that we need to add an account from priv key from here, cause derivation is not possible for imported priv key
return
self.fetchAddressForDerivationPath()
return
@ -410,7 +469,7 @@ method onDerivedAddressesFetched*[T](self: Module[T], derivedAddresses: seq[Deri
return
self.setDerivedAddresses(derivedAddresses)
if self.authenticationReason == AuthenticationReason.AddingAccount:
self.doAddingAccount()
self.doAddAccount()
method onAddressesFromNotImportedMnemonicFetched*[T](self: Module[T], derivations: Table[string, DerivedAccountDetails], error: string) =
if error.len > 0:
@ -430,7 +489,7 @@ method onAddressesFromNotImportedMnemonicFetched*[T](self: Module[T], derivation
)
self.setDerivedAddresses(derivedAddresses)
if self.authenticationReason == AuthenticationReason.AddingAccount:
self.doAddingAccount()
self.doAddAccount()
method onDerivedAddressesFromKeycardFetched*[T](self: Module[T], keycardFlowType: string, keycardEvent: KeycardEvent,
paths: seq[string]) =
@ -453,7 +512,7 @@ method onDerivedAddressesFromKeycardFetched*[T](self: Module[T], keycardFlowType
return
self.setDerivedAddresses(derivedAddresses)
if self.authenticationReason == AuthenticationReason.AddingAccount:
self.doAddingAccount()
self.doAddAccount()
method onAddressDetailsFetched*[T](self: Module[T], derivedAddresses: seq[DerivedAddressDto], error: string) =
if not self.view.getScanningForActivityIsOngoing():
@ -503,7 +562,7 @@ method startScanningForActivity*[T](self: Module[T]) =
method authenticateForEditingDerivationPath*[T](self: Module[T]) =
self.authenticateSelectedOrigin(AuthenticationReason.EditingDerivationPath)
proc doAddingAccount[T](self: Module[T]) =
proc doAddAccount[T](self: Module[T]) =
self.view.setDisablePopup(true)
let
selectedOrigin = self.view.getSelectedOrigin()
@ -608,11 +667,36 @@ proc doAddingAccount[T](self: Module[T]) =
else:
self.closeAddAccountPopup()
method addAccount*[T](self: Module[T]) =
proc doEditAccount[T](self: Module[T]) =
self.view.setDisablePopup(true)
let selectedOrigin = self.view.getSelectedOrigin()
var address = self.view.getWatchOnlyAccAddress().getAddress()
if selectedOrigin.getPairType() == KeyPairType.Profile.int or
selectedOrigin.getPairType() == KeyPairType.SeedImport.int:
let selectedAddrItem = self.view.getSelectedDerivedAddress()
address = selectedAddrItem.getAddress()
elif selectedOrigin.getPairType() == KeyPairType.PrivateKeyImport.int:
let selectedAddrItem = self.view.getPrivateKeyAccAddress()
address = selectedAddrItem.getAddress()
if self.controller.updateAccount(
address = address,
accountName = self.view.getAccountName(),
color = self.view.getSelectedColor(),
emoji = self.view.getSelectedEmoji()):
self.closeAddAccountPopup(address)
else:
self.closeAddAccountPopup()
method finalizeAction*[T](self: Module[T]) =
if self.view.getEditMode():
self.doEditAccount()
return
if self.isAuthenticationNeededForSelectedOrigin():
self.authenticateSelectedOrigin(AuthenticationReason.AddingAccount)
return
self.doAddingAccount()
self.doAddAccount()
method buildNewPrivateKeyKeypairAndAddItToOrigin*[T](self: Module[T]) =
let genAcc = self.controller.getGeneratedAccount()

View File

@ -26,10 +26,14 @@ QtObject:
newKeyPairName: string
selectedEmoji: string
selectedColor: string
storedAccountName: string # used only in edit mode
storedSelectedEmoji: string # used only in edit mode
storedSelectedColor: string # used only in edit mode
derivationPath: string
suggestedDerivationPath: string
actionAuthenticated: bool
scanningForActivityIsOngoing: bool
editMode: bool
disablePopup: bool # unables user to interact with the popup (action buttons are disabled as well as close popup button)
proc delete*(self: View) =
@ -69,6 +73,7 @@ QtObject:
result.privateKeyAccAddressVariant = newQVariant(result.privateKeyAccAddress)
result.actionAuthenticated = false
result.scanningForActivityIsOngoing = false
result.editMode = false
result.disablePopup = false
signalConnect(result.currentState, "backActionClicked()", result, "onBackActionClicked()", 2)
@ -88,6 +93,16 @@ QtObject:
QtProperty[QVariant] currentState:
read = getCurrentState
proc editModeChanged*(self: View) {.signal.}
proc getEditMode*(self: View): bool {.slot.} =
return self.editMode
QtProperty[bool] editMode:
read = getEditMode
notify = editModeChanged
proc setEditMode*(self: View, value: bool) =
self.editMode = value
self.editModeChanged()
proc disablePopupChanged*(self: View) {.signal.}
proc getDisablePopup*(self: View): bool {.slot.} =
return self.disablePopup
@ -271,6 +286,21 @@ QtObject:
write = setSelectedColor
notify = selectedColorChanged
proc getStoredAccountName*(self: View): string {.slot.} =
return self.storedAccountName
proc setStoredAccountName*(self: View, value: string) =
self.storedAccountName = value
proc getStoredSelectedEmoji*(self: View): string {.slot.} =
return self.storedSelectedEmoji
proc setStoredSelectedEmoji*(self: View, value: string) =
self.storedSelectedEmoji = value
proc getStoredSelectedColor*(self: View): string {.slot.} =
return self.storedSelectedColor
proc setStoredSelectedColor*(self: View, value: string) =
self.storedSelectedColor = value
proc derivationPathChanged*(self: View) {.signal.}
proc getDerivationPath*(self: View): string {.slot.} =
return self.derivationPath

View File

@ -37,7 +37,7 @@ proc getWalletAccount*(self: Controller, accountIndex: int): wallet_account_serv
return self.walletAccountService.getWalletAccount(accountIndex)
proc update*(self: Controller, address: string, accountName: string, color: string, emoji: string) =
self.walletAccountService.updateWalletAccount(address, accountName, color, emoji)
discard self.walletAccountService.updateWalletAccount(address, accountName, color, emoji)
method findTokenSymbolByAddress*(self: Controller, address: string): string =
return self.walletAccountService.findTokenSymbolByAddress(address)

View File

@ -61,6 +61,9 @@ method buySellCryptoModuleDidLoad*(self: AccessInterface) {.base.} =
method runAddAccountPopup*(self: AccessInterface, addingWatchOnlyAccount: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method runEditAccountPopup*(self: AccessInterface, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getAddAccountModule*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -218,7 +218,13 @@ method runAddAccountPopup*(self: Module, addingWatchOnlyAccount: bool) =
self.destroyAddAccountPopup()
self.addAccountModule = add_account_module.newModule(self, self.events, self.keycardService, self.accountsService,
self.walletAccountService)
self.addAccountModule.load(addingWatchOnlyAccount)
self.addAccountModule.loadForAddingAccount(addingWatchOnlyAccount)
method runEditAccountPopup*(self: Module, address: string) =
self.destroyAddAccountPopup()
self.addAccountModule = add_account_module.newModule(self, self.events, self.keycardService, self.accountsService,
self.walletAccountService)
self.addAccountModule.loadForEditingAccount(address)
method getAddAccountModule*(self: Module): QVariant =
if self.addAccountModule.isNil:

View File

@ -101,6 +101,9 @@ QtObject:
proc runAddAccountPopup*(self: View, addingWatchOnlyAccount: bool) {.slot.} =
self.delegate.runAddAccountPopup(addingWatchOnlyAccount)
proc runEditAccountPopup*(self: View, address: string) {.slot.} =
self.delegate.runEditAccountPopup(address)
proc getAddAccountModule(self: View): QVariant {.slot.} =
return self.delegate.getAddAccountModule()
QtProperty[QVariant] addAccountModule:

View File

@ -445,23 +445,25 @@ QtObject:
self.checkRecentHistory()
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
proc updateWalletAccount*(self: Service, address: string, accountName: string, color: string, emoji: string) =
proc updateWalletAccount*(self: Service, address: string, accountName: string, color: string, emoji: string): bool =
if not self.walletAccountsContainsAddress(address):
error "account's address is not among known addresses: ", address=address
return
return false
try:
var account = self.getAccountByAddress(address)
let response = status_go_accounts.updateAccount(accountName, account.keyPairName, account.address, account.path, account.lastUsedDerivationIndex,
account.derivedfrom, account.publicKey, account.keyUid, account.walletType, color, emoji, account.isWallet, account.isChat)
if not response.error.isNil:
error "status-go error", procName="updateWalletAccount", errCode=response.error.code, errDesription=response.error.message
return
return false
account.name = accountName
account.color = color
account.emoji = emoji
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
return true
except Exception as e:
error "error: ", procName="updateWalletAccount", errName=e.name, errDesription=e.msg
return false
proc fetchDerivedAddresses*(self: Service, password: string, derivedFrom: string, paths: seq[string], hashPassword: bool)=
let arg = FetchDerivedAddressesTaskArg(

View File

@ -1,10 +1,10 @@
<svg width="19" height="14" viewBox="0 0 19 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.523438 1.35162C0.523438 0.929285 0.859224 0.586914 1.27344 0.586914H8.02344C8.43765 0.586914 8.77344 0.929285 8.77344 1.35162C8.77344 1.77396 8.43765 2.11633 8.02344 2.11633H1.27344C0.859224 2.11633 0.523438 1.77396 0.523438 1.35162Z" fill="#4360DF"/>
<path d="M10.5234 1.35162C10.5234 0.929285 10.8592 0.586914 11.2734 0.586914H17.7734C18.1877 0.586914 18.5234 0.929285 18.5234 1.35162C18.5234 1.77396 18.1877 2.11633 17.7734 2.11633H11.2734C10.8592 2.11633 10.5234 1.77396 10.5234 1.35162Z" fill="#4360DF"/>
<path d="M13.5234 5.17515C13.5234 4.75281 13.8592 4.41044 14.2734 4.41044H17.7734C18.1876 4.41044 18.5234 4.75281 18.5234 5.17515C18.5234 5.59749 18.1876 5.93986 17.7734 5.93986H14.2734C13.8592 5.93986 13.5234 5.59749 13.5234 5.17515Z" fill="#4360DF"/>
<path d="M5.52344 8.99868C5.52344 8.57634 5.18765 8.23397 4.77344 8.23397H1.27344C0.859229 8.23397 0.523442 8.57634 0.523442 8.99868C0.523442 9.42101 0.859229 9.76339 1.27344 9.76339H4.77344C5.18765 9.76339 5.52344 9.42101 5.52344 8.99868Z" fill="#4360DF"/>
<path d="M0.523438 5.17515C0.523438 4.75281 0.859224 4.41044 1.27344 4.41044H11.0234C11.4377 4.41044 11.7734 4.75281 11.7734 5.17515C11.7734 5.59749 11.4377 5.93986 11.0234 5.93986H1.27344C0.859224 5.93986 0.523438 5.59749 0.523438 5.17515Z" fill="#4360DF"/>
<path d="M18.5234 8.99868C18.5234 8.57634 18.1877 8.23397 17.7734 8.23397H8.02344C7.60922 8.23397 7.27344 8.57634 7.27344 8.99868C7.27344 9.42101 7.60922 9.76339 8.02344 9.76339H17.7734C18.1877 9.76339 18.5234 9.42101 18.5234 8.99868Z" fill="#4360DF"/>
<path d="M0.523438 12.8222C0.523438 12.3999 0.859224 12.0575 1.27344 12.0575H8.02344C8.43765 12.0575 8.77344 12.3999 8.77344 12.8222C8.77344 13.2445 8.43765 13.5869 8.02344 13.5869H1.27344C0.859224 13.5869 0.523438 13.2445 0.523438 12.8222Z" fill="#4360DF"/>
<path d="M10.5234 12.8222C10.5234 12.3999 10.8592 12.0575 11.2734 12.0575H17.7734C18.1877 12.0575 18.5234 12.3999 18.5234 12.8222C18.5234 13.2445 18.1877 13.5869 17.7734 13.5869H11.2734C10.8592 13.5869 10.5234 13.2445 10.5234 12.8222Z" fill="#4360DF"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 6.26471C3 5.84237 3.33579 5.5 3.75 5.5H10.5C10.9142 5.5 11.25 5.84237 11.25 6.26471C11.25 6.68704 10.9142 7.02941 10.5 7.02941H3.75C3.33579 7.02941 3 6.68704 3 6.26471Z" fill="black"/>
<path d="M13 6.26471C13 5.84237 13.3358 5.5 13.75 5.5H20.25C20.6642 5.5 21 5.84237 21 6.26471C21 6.68704 20.6642 7.02941 20.25 7.02941H13.75C13.3358 7.02941 13 6.68704 13 6.26471Z" fill="black"/>
<path d="M16 10.0882C16 9.6659 16.3358 9.32353 16.75 9.32353H20.25C20.6642 9.32353 21 9.6659 21 10.0882C21 10.5106 20.6642 10.8529 20.25 10.8529H16.75C16.3358 10.8529 16 10.5106 16 10.0882Z" fill="black"/>
<path d="M8 13.9118C8 13.4894 7.66421 13.1471 7.25 13.1471H3.75C3.33579 13.1471 3 13.4894 3 13.9118C3 14.3341 3.33579 14.6765 3.75 14.6765H7.25C7.66421 14.6765 8 14.3341 8 13.9118Z" fill="black"/>
<path d="M3 10.0882C3 9.6659 3.33579 9.32353 3.75 9.32353H13.5C13.9142 9.32353 14.25 9.6659 14.25 10.0882C14.25 10.5106 13.9142 10.8529 13.5 10.8529H3.75C3.33579 10.8529 3 10.5106 3 10.0882Z" fill="black"/>
<path d="M21 13.9118C21 13.4894 20.6642 13.1471 20.25 13.1471H10.5C10.0858 13.1471 9.75 13.4894 9.75 13.9118C9.75 14.3341 10.0858 14.6765 10.5 14.6765H20.25C20.6642 14.6765 21 14.3341 21 13.9118Z" fill="black"/>
<path d="M3 17.7353C3 17.313 3.33579 16.9706 3.75 16.9706H10.5C10.9142 16.9706 11.25 17.313 11.25 17.7353C11.25 18.1576 10.9142 18.5 10.5 18.5H3.75C3.33579 18.5 3 18.1576 3 17.7353Z" fill="black"/>
<path d="M13 17.7353C13 17.313 13.3358 16.9706 13.75 16.9706H20.25C20.6642 16.9706 21 17.313 21 17.7353C21 18.1576 20.6642 18.5 20.25 18.5H13.75C13.3358 18.5 13 18.1576 13 17.7353Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,4 +1,10 @@
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.52344 16.3369C1.10922 16.3369 0.773438 16.6727 0.773438 17.0869C0.773438 17.5011 1.10922 17.8369 1.52344 17.8369H17.5234C17.9377 17.8369 18.2734 17.5011 18.2734 17.0869C18.2734 16.6727 17.9377 16.3369 17.5234 16.3369H1.52344Z" fill="#4360DF"/>
<path d="M10.2734 1.08691C10.2734 0.672701 9.93765 0.336914 9.52344 0.336914C9.10922 0.336914 8.77344 0.672701 8.77344 1.08691V5.61134C8.77344 5.92031 8.496 6.15533 8.19124 6.10454L3.64674 5.34712C3.23816 5.27902 2.85174 5.55504 2.78364 5.96361C2.71555 6.37219 2.99156 6.75861 3.40014 6.82671L7.6022 7.52705C7.9486 7.58479 8.12912 7.97227 7.95046 8.27462L5.62774 12.2054C5.41702 12.562 5.53528 13.0219 5.89189 13.2326C6.2485 13.4433 6.70841 13.3251 6.91913 12.9685L9.09297 9.28965C9.2865 8.96214 9.76037 8.96214 9.9539 9.28965L12.1277 12.9685C12.3385 13.3251 12.7984 13.4433 13.155 13.2326C13.5116 13.0219 13.6299 12.562 13.4191 12.2054L11.0964 8.27462C10.9178 7.97227 11.0983 7.58479 11.4447 7.52705L15.6467 6.82671C16.0553 6.75861 16.3313 6.37219 16.2632 5.96361C16.1951 5.55504 15.8087 5.27902 15.4001 5.34712L10.8556 6.10454C10.5509 6.15533 10.2734 5.92031 10.2734 5.61134V1.08691Z" fill="#4360DF"/>
<svg width="19" height="14" viewBox="0 0 19 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.523438 1.35162C0.523438 0.929285 0.859224 0.586914 1.27344 0.586914H8.02344C8.43765 0.586914 8.77344 0.929285 8.77344 1.35162C8.77344 1.77396 8.43765 2.11633 8.02344 2.11633H1.27344C0.859224 2.11633 0.523438 1.77396 0.523438 1.35162Z" fill="#4360DF"/>
<path d="M10.5234 1.35162C10.5234 0.929285 10.8592 0.586914 11.2734 0.586914H17.7734C18.1877 0.586914 18.5234 0.929285 18.5234 1.35162C18.5234 1.77396 18.1877 2.11633 17.7734 2.11633H11.2734C10.8592 2.11633 10.5234 1.77396 10.5234 1.35162Z" fill="#4360DF"/>
<path d="M13.5234 5.17515C13.5234 4.75281 13.8592 4.41044 14.2734 4.41044H17.7734C18.1876 4.41044 18.5234 4.75281 18.5234 5.17515C18.5234 5.59749 18.1876 5.93986 17.7734 5.93986H14.2734C13.8592 5.93986 13.5234 5.59749 13.5234 5.17515Z" fill="#4360DF"/>
<path d="M5.52344 8.99868C5.52344 8.57634 5.18765 8.23397 4.77344 8.23397H1.27344C0.859229 8.23397 0.523442 8.57634 0.523442 8.99868C0.523442 9.42101 0.859229 9.76339 1.27344 9.76339H4.77344C5.18765 9.76339 5.52344 9.42101 5.52344 8.99868Z" fill="#4360DF"/>
<path d="M0.523438 5.17515C0.523438 4.75281 0.859224 4.41044 1.27344 4.41044H11.0234C11.4377 4.41044 11.7734 4.75281 11.7734 5.17515C11.7734 5.59749 11.4377 5.93986 11.0234 5.93986H1.27344C0.859224 5.93986 0.523438 5.59749 0.523438 5.17515Z" fill="#4360DF"/>
<path d="M18.5234 8.99868C18.5234 8.57634 18.1877 8.23397 17.7734 8.23397H8.02344C7.60922 8.23397 7.27344 8.57634 7.27344 8.99868C7.27344 9.42101 7.60922 9.76339 8.02344 9.76339H17.7734C18.1877 9.76339 18.5234 9.42101 18.5234 8.99868Z" fill="#4360DF"/>
<path d="M0.523438 12.8222C0.523438 12.3999 0.859224 12.0575 1.27344 12.0575H8.02344C8.43765 12.0575 8.77344 12.3999 8.77344 12.8222C8.77344 13.2445 8.43765 13.5869 8.02344 13.5869H1.27344C0.859224 13.5869 0.523438 13.2445 0.523438 12.8222Z" fill="#4360DF"/>
<path d="M10.5234 12.8222C10.5234 12.3999 10.8592 12.0575 11.2734 12.0575H17.7734C18.1877 12.0575 18.5234 12.3999 18.5234 12.8222C18.5234 13.2445 18.1877 13.5869 17.7734 13.5869H11.2734C10.8592 13.5869 10.5234 13.2445 10.5234 12.8222Z" fill="#4360DF"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -24,7 +24,7 @@ StatusModal {
closePolicy: root.store.disablePopup? Popup.NoAutoClose : Popup.CloseOnEscape | Popup.CloseOnPressOutside
hasCloseButton: !root.store.disablePopup
header.title: qsTr("Add a new account")
header.title: root.store.editMode? qsTr("Edit account") : qsTr("Add a new account")
onOpened: {
root.store.resetStoreValues()
@ -203,6 +203,10 @@ StatusModal {
StatusBaseButton.Type.Normal
height: Constants.addAccountPopup.footerButtonsHeight
text: {
if (root.store.editMode) {
return qsTr("Save changes")
}
switch (root.store.currentState.stateType) {
case Constants.addAccountPopup.state.main:
@ -226,6 +230,10 @@ StatusModal {
enabled: root.store.primaryPopupButtonEnabled
icon.name: {
if (root.store.editMode) {
return ""
}
if (root.store.currentState.stateType === Constants.addAccountPopup.state.enterPrivateKey ||
root.store.currentState.stateType === Constants.addAccountPopup.state.enterSeedPhrase ||
root.store.currentState.stateType === Constants.addAccountPopup.state.confirmAddingNewMasterKey ||

View File

@ -6,30 +6,41 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import utils 1.0
import shared.controls 1.0
Column {
id: root
property string addressText: ""
property string addressColor: Theme.palette.directColor1
property var addressDetailsItem
property bool addressResolved: true
property bool displayDetails: true
property bool displayCopyButton: true
spacing: Style.current.halfPadding
StatusBaseText {
text: qsTr("Public address of private key")
text: root.addressText
font.pixelSize: Constants.addAccountPopup.labelFontSize1
}
StatusInput {
width: parent.width
input.edit.enabled: false
text: root.addressDetailsItem.address
input.edit.enabled: false
input.edit.color: root.addressColor
input.background.color: "transparent"
input.background.border.color: Theme.palette.baseColor2
input.rightComponent: CopyButton {
visible: root.displayCopyButton
textToCopy: root.addressDetailsItem.address
}
}
AddressDetails {
width: parent.width
visible: root.displayDetails
addressDetailsItem: root.addressDetailsItem
defaultMessage: ""
defaultMessageCondition: !root.addressResolved

View File

@ -0,0 +1,91 @@
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.Core.Utils 0.1 as StatusQUtils
import StatusQ.Controls 0.1
import utils 1.0
import shared.controls 1.0
import "../stores"
GridLayout {
id: root
property AddAccountStore store
columns: 2
columnSpacing: Style.current.padding
rowSpacing: Style.current.halfPadding
QtObject {
id: d
readonly property int oneHalfWidth: (root.width - root.columnSpacing) * 0.5
}
component ReadonlyInputWithCopyButton: StatusInput {
id: comp
required property string textToCopy
input.edit.enabled: false
input.edit.color: Theme.palette.baseColor1
input.background.color: "transparent"
input.background.border.color: Theme.palette.baseColor2
input.rightComponent: CopyButton {
textToCopy: comp.textToCopy
}
}
StatusBaseText {
Layout.fillWidth: true
font.pixelSize: Constants.addAccountPopup.labelFontSize1
text: qsTr("Derivation Path")
}
StatusBaseText {
Layout.preferredWidth: d.oneHalfWidth
font.pixelSize: Constants.addAccountPopup.labelFontSize1
text: qsTr("Account")
}
ReadonlyInputWithCopyButton {
Layout.preferredWidth: d.oneHalfWidth
text: root.store.addAccountModule.derivationPath
textToCopy: root.store.addAccountModule.derivationPath
}
ReadonlyInputWithCopyButton {
Layout.preferredWidth: d.oneHalfWidth
text: StatusQUtils.Utils.elideText(root.store.selectedDerivedAddress.address, 6, 8)
textToCopy: root.store.selectedDerivedAddress.address
}
StatusBaseText {
Layout.preferredWidth: d.oneHalfWidth
font.pixelSize: Constants.addAccountPopup.labelFontSize2
color: Theme.palette.baseColor1
text: {
if (root.store.addAccountModule.derivationPath.startsWith(Constants.addAccountPopup.predefinedPaths.ethereum)) {
root.store.selectedRootPath = Constants.addAccountPopup.predefinedPaths.ethereum
}
else if (root.store.addAccountModule.derivationPath.startsWith(Constants.addAccountPopup.predefinedPaths.ethereumRopsten)) {
root.store.selectedRootPath = Constants.addAccountPopup.predefinedPaths.ethereumRopsten
}
else if (root.store.addAccountModule.derivationPath.startsWith(Constants.addAccountPopup.predefinedPaths.ethereumLedger)) {
root.store.selectedRootPath = Constants.addAccountPopup.predefinedPaths.ethereumLedger
}
else if (root.store.addAccountModule.derivationPath.startsWith(Constants.addAccountPopup.predefinedPaths.ethereumLedgerLive)) {
root.store.selectedRootPath = Constants.addAccountPopup.predefinedPaths.ethereumLedgerLive
}
else {
root.store.selectedRootPath = Constants.addAccountPopup.predefinedPaths.custom
}
return root.store.translation(root.store.selectedRootPath, true)
}
}
}

View File

@ -16,7 +16,13 @@ Column {
property AddAccountStore store
padding: Style.current.padding
state: root.store.addAccountModule.actionAuthenticated? d.expandedState : d.collapsedState
state: {
if (root.store.editMode) {
return d.expandedState
}
root.store.addAccountModule.actionAuthenticated? d.expandedState : d.collapsedState
}
QtObject {
id: d
@ -28,6 +34,7 @@ Column {
RowLayout {
width: parent.width - 2 * root.padding
height: 64
visible: !root.store.editMode
StatusBaseText {
font.pixelSize: Constants.addAccountPopup.labelFontSize1
@ -90,6 +97,14 @@ Column {
DerivationPath {
id: derivationPathContent
visible: !root.store.editMode
width: parent.width - 2 * root.padding
store: root.store
}
DerivationPathDisplay {
visible: root.store.editMode
width: parent.width - 2 * root.padding
store: root.store
@ -99,7 +114,7 @@ Column {
State {
name: d.expandedState
PropertyChanges {target: expandImage; icon: "chevron-up"}
PropertyChanges {target: derivationPathContent; visible: true}
PropertyChanges {target: derivationPathContent; visible: !root.store.editMode}
},
State {
name: d.collapsedState

View File

@ -24,6 +24,7 @@ StatusSelect {
selectedItemComponent: StatusListItem {
title: Utils.appTranslation(root.selectedOrigin.name)
statusListItemTitle.color: Theme.palette.directColor1
border.width: 1
border.color: Theme.palette.baseColor2

View File

@ -130,8 +130,10 @@ Item {
spacing: Style.current.halfPadding
visible: d.addressResolved
addressText: qsTr("Public address of private key")
addressDetailsItem: root.store.privateKeyAccAddress
addressResolved: d.addressResolved
displayCopyButton: false
}
StatusModalDivider {

View File

@ -148,8 +148,10 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
userProfilePublicKey: root.store.userProfilePublicKey
originModel: root.store.originModel
originModel: root.store.editMode? [] : root.store.originModel
selectedOrigin: root.store.selectedOrigin
caretVisible: !root.store.editMode
enabled: !root.store.editMode
onOriginSelected: {
if (keyUid === Constants.appTranslatableConstants.addAccountLabelOptionAddNewMasterKey) {
@ -164,7 +166,8 @@ Item {
width: parent.width - 2 * Style.current.padding
anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.current.padding
visible: root.store.selectedOrigin.pairType === Constants.addAccountPopup.keyPairType.unknown &&
visible: !root.store.editMode &&
root.store.selectedOrigin.pairType === Constants.addAccountPopup.keyPairType.unknown &&
root.store.selectedOrigin.keyUid === Constants.appTranslatableConstants.addAccountLabelOptionAddWatchOnlyAcc
store: root.store
@ -194,9 +197,18 @@ Item {
Layout.fillWidth: true
Layout.margins: Style.current.padding
spacing: Style.current.halfPadding
visible: root.store.selectedOrigin.pairType === Constants.addAccountPopup.keyPairType.privateKeyImport
visible: root.store.selectedOrigin.pairType === Constants.addAccountPopup.keyPairType.privateKeyImport ||
root.store.editMode &&
root.store.selectedOrigin.pairType === Constants.addAccountPopup.keyPairType.unknown &&
root.store.selectedOrigin.keyUid === Constants.appTranslatableConstants.addAccountLabelOptionAddWatchOnlyAcc
addressDetailsItem: root.store.privateKeyAccAddress
addressText: root.store.editMode? qsTr("Account") : qsTr("Public address of private key")
addressDetailsItem: root.store.selectedOrigin.pairType === Constants.addAccountPopup.keyPairType.privateKeyImport?
root.store.privateKeyAccAddress
: root.store.watchOnlyAccAddress
displayDetails: !root.store.editMode
displayCopyButton: root.store.editMode
addressColor: root.store.editMode? Theme.palette.baseColor1 : Theme.palette.directColor1
}
Loader {

View File

@ -20,6 +20,7 @@ QtObject {
property var selectedDerivedAddress: root.addAccountModule.selectedDerivedAddress
property var watchOnlyAccAddress: root.addAccountModule.watchOnlyAccAddress
property var privateKeyAccAddress: root.addAccountModule.privateKeyAccAddress
property bool editMode: root.addAccountModule.editMode
property bool disablePopup: root.addAccountModule.disablePopup
property bool enteredSeedPhraseIsValid: false
@ -62,8 +63,22 @@ QtObject {
root.derivationPathOutOfTheDefaultStatusDerivationTreeConfirmed = false
root.selectedRootPath = Constants.addAccountPopup.predefinedPaths.ethereum
root.cleanPrivateKey()
root.cleanSeedPhrase()
if (!root.editMode) {
root.cleanPrivateKey()
root.cleanSeedPhrase()
}
}
function getStoredAccountName() {
return root.addAccountModule.getStoredAccountName()
}
function getStoredSelectedEmoji() {
return root.addAccountModule.getStoredSelectedEmoji()
}
function getStoredSelectedColor() {
return root.addAccountModule.getStoredSelectedColor()
}
function submitAddAccount(event) {
@ -179,6 +194,15 @@ QtObject {
return false
}
if (root.editMode) {
return root.addAccountModule.accountName !== "" &&
root.addAccountModule.accountName !== root.getStoredAccountName() ||
root.addAccountModule.selectedColor !== "" &&
root.addAccountModule.selectedColor !== root.getStoredSelectedColor() ||
root.addAccountModule.selectedEmoji !== "" &&
root.addAccountModule.selectedEmoji !== root.getStoredSelectedEmoji()
}
let valid = root.addAccountModule.accountName !== "" &&
root.addAccountModule.selectedColor !== "" &&
root.addAccountModule.selectedEmoji !== ""

View File

@ -196,4 +196,8 @@ QtObject {
function runAddWatchOnlyAccountPopup() {
walletSection.runAddAccountPopup(true)
}
function runEditAccountPopup(address) {
walletSection.runEditAccountPopup(address)
}
}

View File

@ -284,6 +284,7 @@ Rectangle {
account: model
onEditAccountClicked: {
RootStore.runEditAccountPopup(model.address)
}
onDeleteAccountClicked: {

View File

@ -894,6 +894,7 @@ QtObject {
readonly property string loginAccountsListAddExistingUser: "LOGIN-ACCOUNTS-LIST-ADD-EXISTING-USER"
readonly property string loginAccountsListLostKeycard: "LOGIN-ACCOUNTS-LIST-LOST-KEYCARD"
readonly property string addAccountLabelNewWatchOnlyAccount: "LABEL-NEW-WATCH-ONLY-ACCOUNT"
readonly property string addAccountLabelWatchOnlyAccount: "LABEL-WATCH-ONLY-ACCOUNT"
readonly property string addAccountLabelExisting: "LABEL-EXISTING"
readonly property string addAccountLabelImportNew: "LABEL-IMPORT-NEW"
readonly property string addAccountLabelOptionAddNewMasterKey: "LABEL-OPTION-ADD-NEW-MASTER-KEY"

View File

@ -639,6 +639,8 @@ QtObject {
return qsTr("Lost Keycard")
case Constants.appTranslatableConstants.addAccountLabelNewWatchOnlyAccount:
return qsTr("New watch-only account")
case Constants.appTranslatableConstants.addAccountLabelWatchOnlyAccount:
return qsTr("Watch-only account")
case Constants.appTranslatableConstants.addAccountLabelExisting:
return qsTr("Existing")
case Constants.appTranslatableConstants.addAccountLabelImportNew: