From c47140a4064c9a6837df6ff2a4a56b54cf812003 Mon Sep 17 00:00:00 2001 From: Khushboo Mehta Date: Thu, 22 Jun 2023 12:32:43 +0200 Subject: [PATCH] feat(@desktop/wallet): Wallet accounts - Account List fixes #11189 --- .../wallet/accounts/controller.nim | 6 + .../wallet/accounts/module.nim | 26 ++++ .../profile_section/wallet/accounts/view.nim | 16 +++ .../profile_section/wallet/networks/item.nim | 16 ++- .../profile_section/wallet/networks/model.nim | 18 ++- .../profile_section/wallet/networks/view.nim | 7 +- src/app/modules/shared/keypairs.nim | 2 +- .../modules/shared_models/keypair_item.nim | 1 + .../modules/shared_models/keypair_model.nim | 8 +- storybook/PagesModel.qml | 4 + storybook/pages/ProfileAccountsPage.qml | 54 ++++++++ storybook/src/Models/WalletKeyPairModel.qml | 52 ++++++++ storybook/src/Models/qmldir | 1 + test/ui-test/src/screens/SettingsScreen.py | 8 +- .../global_shared/scripts/settings_names.py | 2 +- .../controls/WalletAccountDelegate.qml | 43 ++++-- .../controls/WalletKeyPairDelegate.qml | 93 +++++++++++++ ui/app/AppLayouts/Profile/controls/qmldir | 1 + .../AppLayouts/Profile/stores/WalletStore.qml | 7 + .../Profile/views/wallet/MainView.qml | 124 +++--------------- ui/imports/utils/Constants.qml | 3 + 21 files changed, 365 insertions(+), 127 deletions(-) create mode 100644 storybook/pages/ProfileAccountsPage.qml create mode 100644 storybook/src/Models/WalletKeyPairModel.qml create mode 100644 ui/app/AppLayouts/Profile/controls/WalletKeyPairDelegate.qml diff --git a/src/app/modules/main/profile_section/wallet/accounts/controller.nim b/src/app/modules/main/profile_section/wallet/accounts/controller.nim index 8694918ce1..9365fbc8d1 100644 --- a/src/app/modules/main/profile_section/wallet/accounts/controller.nim +++ b/src/app/modules/main/profile_section/wallet/accounts/controller.nim @@ -39,3 +39,9 @@ proc isKeycardAccount*(self: Controller, account: WalletAccountDto): bool = proc getWalletAccount*(self: Controller, address: string): WalletAccountDto = return self.walletAccountService.getAccountByAddress(address) + +proc getKeypairs*(self: Controller): seq[KeypairDto] = + return self.walletAccountService.getKeypairs() + +proc getAllKnownKeycardsGroupedByKeyUid*(self: Controller): seq[KeycardDto] = + return self.walletAccountService.getAllKnownKeycardsGroupedByKeyUid() diff --git a/src/app/modules/main/profile_section/wallet/accounts/module.nim b/src/app/modules/main/profile_section/wallet/accounts/module.nim index c814f8969c..1f53b5be99 100644 --- a/src/app/modules/main/profile_section/wallet/accounts/module.nim +++ b/src/app/modules/main/profile_section/wallet/accounts/module.nim @@ -3,6 +3,8 @@ import NimQml, sequtils, sugar, chronicles import ./io_interface, ./view, ./item, ./controller import ../io_interface as delegate_interface import ../../../../shared/wallet_utils +import ../../../../shared/keypairs +import ../../../../shared_models/keypair_item import ../../../../../global/global_singleton import ../../../../../core/eventemitter import ../../../../../../app_service/service/keycard/service as keycard_service @@ -44,6 +46,29 @@ method delete*(self: Module) = method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant +method convertWalletAccountDtoToKeyPairAccountItem(self: Module, account: WalletAccountDto): KeyPairAccountItem = + result = newKeyPairAccountItem( + name = account.name, + path = account.path, + address = account.address, + pubKey = account.walletType, + emoji = account.emoji, + colorId = account.colorId, + icon = "", + balance = 0, + balanceFetched = false) + +method createKeypairItems*(self: Module, walletAccounts: seq[WalletAccountDto]): seq[KeyPairItem] = + var keyPairItems = keypairs.buildKeyPairsList(self.controller.getKeypairs(), self.controller.getAllKnownKeycardsGroupedByKeyUid(), + excludeAlreadyMigratedPairs = false, excludePrivateKeyKeypairs = false) + + var item = newKeyPairItem() + item.setIcon("show") + item.setPairType(KeyPairType.WatchOnly.int) + item.setAccounts(walletAccounts.filter(a => a.walletType == WalletTypeWatch).map(x => self.convertWalletAccountDtoToKeyPairAccountItem(x))) + keyPairItems.add(item) + return keyPairItems + method refreshWalletAccounts*(self: Module) = let walletAccounts = self.controller.getWalletAccounts() @@ -52,6 +77,7 @@ method refreshWalletAccounts*(self: Module) = walletAccountToWalletSettingsAccountsItem(w, keycardAccount) )) + self.view.setKeyPairModelItems(self.createKeypairItems(walletAccounts)) self.view.setItems(items) method load*(self: Module) = diff --git a/src/app/modules/main/profile_section/wallet/accounts/view.nim b/src/app/modules/main/profile_section/wallet/accounts/view.nim index ba1885e3da..753f422027 100644 --- a/src/app/modules/main/profile_section/wallet/accounts/view.nim +++ b/src/app/modules/main/profile_section/wallet/accounts/view.nim @@ -3,6 +3,7 @@ import NimQml, sequtils, strutils, sugar import ./model import ./item import ./io_interface +import ../../../../shared_models/[keypair_model, keypair_item] QtObject: type @@ -10,10 +11,12 @@ QtObject: delegate: io_interface.AccessInterface accounts: Model accountsVariant: QVariant + keyPairModel: KeyPairModel proc delete*(self: View) = self.accounts.delete self.accountsVariant.delete + self.keyPairModel.delete self.QObject.delete proc newView*(delegate: io_interface.AccessInterface): View = @@ -22,6 +25,7 @@ QtObject: result.delegate = delegate result.accounts = newModel() result.accountsVariant = newQVariant(result.accounts) + result.keyPairModel = newKeyPairModel() proc load*(self: View) = self.delegate.viewDidLoad() @@ -43,6 +47,18 @@ QtObject: proc onUpdatedAccount*(self: View, account: Item) = self.accounts.onUpdatedAccount(account) + self.keyPairModel.onUpdatedAccount(account.keyUid, account.address, account.name, account.colorId, account.emoji) proc deleteAccount*(self: View, address: string) {.slot.} = self.delegate.deleteAccount(address) + + proc keyPairModelChanged*(self: View) {.signal.} + proc getKeyPairModel(self: View): QVariant {.slot.} = + return newQVariant(self.keyPairModel) + QtProperty[QVariant] keyPairModel: + read = getKeyPairModel + notify = keyPairModelChanged + + proc setKeyPairModelItems*(self: View, items: seq[KeyPairItem]) = + self.keyPairModel.setItems(items) + self.keyPairModelChanged() diff --git a/src/app/modules/main/profile_section/wallet/networks/item.nim b/src/app/modules/main/profile_section/wallet/networks/item.nim index f6aaa505be..9d182d4d0f 100644 --- a/src/app/modules/main/profile_section/wallet/networks/item.nim +++ b/src/app/modules/main/profile_section/wallet/networks/item.nim @@ -6,17 +6,23 @@ type layer: int chainName: string iconUrl: string + shortName: string + chainColor: string proc initItem*( chainId: int, layer: int, chainName: string, iconUrl: string, + shortName: string, + chainColor: string, ): Item = result.chainId = chainId result.layer = layer result.chainName = chainName result.iconUrl = iconUrl + result.shortName = shortName + result.chainColor = chainColor proc `$`*(self: Item): string = result = fmt"""NetworkItem( @@ -24,6 +30,8 @@ proc `$`*(self: Item): string = chainName: {self.chainName}, layer: {self.layer}, iconUrl:{self.iconUrl}, + shortName: {self.shortName}, + chainColor: {self.chainColor}, ]""" proc getChainId*(self: Item): int = @@ -36,4 +44,10 @@ proc getChainName*(self: Item): string = return self.chainName proc getIconURL*(self: Item): string = - return self.iconUrl \ No newline at end of file + return self.iconUrl + +proc getShortName*(self: Item): string = + return self.shortName + +proc getChainColor*(self: Item): string = + return self.chainColor diff --git a/src/app/modules/main/profile_section/wallet/networks/model.nim b/src/app/modules/main/profile_section/wallet/networks/model.nim index 47e353bea5..04446f3527 100644 --- a/src/app/modules/main/profile_section/wallet/networks/model.nim +++ b/src/app/modules/main/profile_section/wallet/networks/model.nim @@ -10,6 +10,8 @@ type Layer ChainName IconUrl + ShortName + ChainColor QtObject: type @@ -49,6 +51,8 @@ QtObject: ModelRole.Layer.int:"layer", ModelRole.ChainName.int:"chainName", ModelRole.IconUrl.int:"iconUrl", + ModelRole.ShortName.int:"shortName", + ModelRole.ChainColor.int:"chainColor", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -70,6 +74,10 @@ QtObject: result = newQVariant(item.getChainName()) of ModelRole.IconUrl: result = newQVariant(item.getIconURL()) + of ModelRole.ShortName: + result = newQVariant(item.getShortName()) + of ModelRole.ChainColor: + result = newQVariant(item.getChainColor()) proc rowData*(self: Model, index: int, column: string): string {.slot.} = if (index >= self.items.len): @@ -80,9 +88,17 @@ QtObject: of "layer": result = $item.getLayer() of "chainName": result = $item.getChainName() of "iconUrl": result = $item.getIconURL() + of "shortName": result = $item.getShortName() + of "chainColor": result = $item.getChainColor() proc setItems*(self: Model, items: seq[Item]) = self.beginResetModel() self.items = items self.endResetModel() - self.countChanged() \ No newline at end of file + self.countChanged() + + proc getAllNetworksSupportedPrefix*(self: Model): string = + var networkString = "" + for item in self.items: + networkString = networkString & item.getShortName() & ':' + return networkString diff --git a/src/app/modules/main/profile_section/wallet/networks/view.nim b/src/app/modules/main/profile_section/wallet/networks/view.nim index a1a80eb323..15f67b7c3b 100644 --- a/src/app/modules/main/profile_section/wallet/networks/view.nim +++ b/src/app/modules/main/profile_section/wallet/networks/view.nim @@ -59,7 +59,12 @@ QtObject: n.layer, n.chainName, n.iconUrl, + n.shortName, + n.chainColor )) self.networks.setItems(items) - self.delegate.viewDidLoad() \ No newline at end of file + self.delegate.viewDidLoad() + + proc getAllNetworksSupportedPrefix*(self: View): string {.slot.} = + return self.networks.getAllNetworksSupportedPrefix() diff --git a/src/app/modules/shared/keypairs.nim b/src/app/modules/shared/keypairs.nim index 91c8b4fefb..8e01882b1c 100644 --- a/src/app/modules/shared/keypairs.nim +++ b/src/app/modules/shared/keypairs.nim @@ -74,7 +74,7 @@ proc buildKeyPairsList*(keypairs: seq[KeypairDto], allMigratedKeypairs: seq[Keyc locked = false, name = kp.name, image = "", - icon = if keyPairMigrated(kp.keyUid): "keycard" else: "key_pair_private_key", + icon = if keyPairMigrated(kp.keyUid): "keycard" else: "objects", pairType = KeyPairType.PrivateKeyImport, derivedFrom = kp.derivedFrom, lastUsedDerivationIndex = kp.lastUsedDerivationIndex, diff --git a/src/app/modules/shared_models/keypair_item.nim b/src/app/modules/shared_models/keypair_item.nim index f729e5ccfd..fb90ddea80 100644 --- a/src/app/modules/shared_models/keypair_item.nim +++ b/src/app/modules/shared_models/keypair_item.nim @@ -9,6 +9,7 @@ type Profile SeedImport PrivateKeyImport + WatchOnly QtObject: type KeyPairItem* = ref object of QObject diff --git a/src/app/modules/shared_models/keypair_model.nim b/src/app/modules/shared_models/keypair_model.nim index f947491781..980ba575ce 100644 --- a/src/app/modules/shared_models/keypair_model.nim +++ b/src/app/modules/shared_models/keypair_model.nim @@ -73,4 +73,10 @@ QtObject: for i in 0 ..< self.items.len: if(self.items[i].getKeyUid() == keyUid): return self.items[i] - return nil \ No newline at end of file + return nil + + proc onUpdatedAccount*(self: KeyPairModel, keyUid, address, name, colorId, emoji: string) = + for item in self.items: + if keyUid == item.getKeyUid(): + item.getAccountsModel().updateDetailsForAddressIfTheyAreSet(address, name, colorId, emoji) + break diff --git a/storybook/PagesModel.qml b/storybook/PagesModel.qml index a4da81d218..158a86f8d3 100644 --- a/storybook/PagesModel.qml +++ b/storybook/PagesModel.qml @@ -389,4 +389,8 @@ ListModel { title: "ActivityFilterMenu" section: "Wallet" } + ListElement { + title: "ProfileAccounts" + section: "Wallet" + } } diff --git a/storybook/pages/ProfileAccountsPage.qml b/storybook/pages/ProfileAccountsPage.qml new file mode 100644 index 0000000000..5f8e077ef5 --- /dev/null +++ b/storybook/pages/ProfileAccountsPage.qml @@ -0,0 +1,54 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.14 + +import AppLayouts.Profile.controls 1.0 + +import StatusQ.Core 0.1 + +import utils 1.0 + +import Storybook 1.0 + +import Models 1.0 + +SplitView { + id: root + + Logs { id: logs } + + orientation: Qt.Vertical + + QtObject { + id: d + + readonly property QtObject walletStore: QtObject { + property string userProfilePublicKey: "zq3shfrgk6swgrrnc7wmwun1gvgact9iaevv9xwirumimhbyf" + + function getAllNetworksSupportedString(hovered) { + return hovered ? "" + "eth:" + "" + + "" + "opt:" + "" + + "" + "arb:" + "" : "eth:opt:arb:" + } + } + } + + Item { + SplitView.fillWidth: true + SplitView.fillHeight: true + + StatusListView { + width: 500 + height: parent.height + anchors.verticalCenterOffset: 20 + anchors.centerIn: parent + spacing: 24 + model: WalletKeyPairModel {} + delegate: WalletKeyPairDelegate { + width: parent.width + chainShortNames: d.walletStore.getAllNetworksSupportedString() + userProfilePublicKey: d.walletStore.userProfilePublicKey + onGoToAccountView: console.warn("onGoToAccountView ::") + } + } + } +} diff --git a/storybook/src/Models/WalletKeyPairModel.qml b/storybook/src/Models/WalletKeyPairModel.qml new file mode 100644 index 0000000000..19f8484be5 --- /dev/null +++ b/storybook/src/Models/WalletKeyPairModel.qml @@ -0,0 +1,52 @@ +import QtQuick 2.15 + +ListModel { + readonly property var data: [ + { + keyPair: { + keyUid: "", + pubKey: "zq3shfrgk6swgrrnc7wmwun1gvgact9iaevv9xwirumimhbyf", + name: "Mike", + image: "", + icon: "", + pairType: 0, + migratedToKeycard: false, + accounts: accountsList + } + }, + { + keyPair: { + keyUid: "", + pubKey: "", + name: "Seed Phrase", + image: "", + icon: "key_pair_private_key", + pairType: 1, + migratedToKeycard: true, + accounts: accountsList + } + }, + { + keyPair: { + keyUid: "", + pubKey: "", + name: "", + image: "", + icon: "show", + pairType: 3, + migratedToKeycard: false, + accounts: accountsList + } + } + ] + + property var accountsList: ListModel { + readonly property var data1: [ + {account: { name: "Test account", emoji: "😋", colorId: "primary", address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" }}, + {account: { name: "Another account", emoji: "🚗", colorId: "army", address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888"}} + ] + Component.onCompleted: append(data1) + } + + Component.onCompleted: append(data) +} diff --git a/storybook/src/Models/qmldir b/storybook/src/Models/qmldir index df3383540e..3828a51bee 100644 --- a/storybook/src/Models/qmldir +++ b/storybook/src/Models/qmldir @@ -14,3 +14,4 @@ singleton ModelsData 1.0 ModelsData.qml singleton NetworksModel 1.0 NetworksModel.qml singleton PermissionsModel 1.0 PermissionsModel.qml RecipientModel 1.0 RecipientModel.qml +WalletKeyPairModel 1.0 WalletKeyPairModel.qml diff --git a/test/ui-test/src/screens/SettingsScreen.py b/test/ui-test/src/screens/SettingsScreen.py index 722631a865..a26f75c757 100644 --- a/test/ui-test/src/screens/SettingsScreen.py +++ b/test/ui-test/src/screens/SettingsScreen.py @@ -168,7 +168,7 @@ class SettingsScreen: raise Exception("Account not found") accounts = get_obj(WalletSettingsScreen.GENERATED_ACCOUNTS.value) - click_obj(accounts.itemAtIndex(index)) + click_obj(accounts.itemAt(index)) click_obj_by_name(WalletSettingsScreen.DELETE_ACCOUNT.value) click_obj_by_name(WalletSettingsScreen.DELETE_ACCOUNT_CONFIRM.value) @@ -180,7 +180,7 @@ class SettingsScreen: def verify_address(self, address: str): accounts = get_obj(WalletSettingsScreen.GENERATED_ACCOUNTS.value) - verify_text_matching_insensitive(accounts.itemAtIndex(0).statusListItemSubTitle, address) + verify_text_matching_insensitive(accounts.itemAt(0).statusListItemSubTitle, address) # Post condition: Messaging Settings is visible (@see StatusMainScreen.open_settings) def open_messaging_settings(self): @@ -245,7 +245,7 @@ class SettingsScreen: def _find_account_index(self, account_name: str) -> int: accounts = get_obj(WalletSettingsScreen.GENERATED_ACCOUNTS.value) for index in range(accounts.count): - if (accounts.itemAtIndex(index).objectName == account_name): + if (accounts.itemAt(index).objectName == account_name): return index return -1 @@ -254,7 +254,7 @@ class SettingsScreen: def select_default_account(self): accounts = get_obj(WalletSettingsScreen.GENERATED_ACCOUNTS.value) - click_obj(accounts.itemAtIndex(0)) + click_obj(accounts.itemAt(0)) click_obj_by_name(WalletSettingsScreen.EDIT_ACCOUNT_BUTTON.value) def edit_account(self, account_name: str, account_color: str): diff --git a/test/ui-test/testSuites/global_shared/scripts/settings_names.py b/test/ui-test/testSuites/global_shared/scripts/settings_names.py index 50ebfbbc1d..aad6c77e71 100644 --- a/test/ui-test/testSuites/global_shared/scripts/settings_names.py +++ b/test/ui-test/testSuites/global_shared/scripts/settings_names.py @@ -91,7 +91,7 @@ edit_TextEdit = {"container": statusDesktop_mainWindow_overlay, "type": "TextEdi mainWallet_Saved_Addreses_More_Edit = {"container": statusDesktop_mainWindow, "objectName": "editroot", "type": "StatusMenuItem"} mainWallet_Saved_Addreses_More_Delete = {"container": statusDesktop_mainWindow, "objectName": "deleteSavedAddress", "type": "StatusMenuItem"} mainWallet_Saved_Addreses_More_Confirm_Delete = {"container": statusDesktop_mainWindow, "objectName": "confirmDeleteSavedAddress", "type": "StatusButton"} -settings_Wallet_MainView_GeneratedAccounts = {"container": statusDesktop_mainWindow, "objectName": 'generatedAccounts', "type": 'ListView'} +settings_Wallet_MainView_GeneratedAccounts = {"container": statusDesktop_mainWindow, "objectName": 'generatedAccounts', "type": 'Repeater'} settings_Wallet_AccountView_DeleteAccount = {"container": statusDesktop_mainWindow, "type": "StatusButton", "objectName": "deleteAccountButton"} settings_Wallet_AccountView_DeleteAccount_Confirm = {"container": statusDesktop_mainWindow, "type": "StatusButton", "objectName": "confirmDeleteAccountButton"} mainWindow_ScrollView_2 = {"container": statusDesktop_mainWindow, "occurrence": 2, "type": "StatusScrollView", "unnamed": 1, "visible": True} diff --git a/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml b/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml index 9d1545210a..60a5c20fe1 100644 --- a/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml +++ b/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml @@ -1,6 +1,11 @@ +import QtQuick 2.14 + import StatusQ.Components 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Core 0.1 +import StatusQ.Core.Utils 0.1 as StatusQUtils + +import AppLayouts.Wallet 1.0 import utils 1.0 @@ -8,14 +13,18 @@ StatusListItem { id: root property var account - property bool showShevronIcon: true + property string chainShortNames + property int totalCount: 0 signal goToAccountView() - - title: account.name - subTitle: account.address + objectName: account.name - asset.color: Utils.getColorForId(account.colorId) + title: account.name + subTitle: { + const elidedAddress = StatusQUtils.Utils.elideText(account.address,6,4) + return sensor.containsMouse ? WalletUtils.colorizedChainPrefix(chainShortNames) + Utils.richColorText(elidedAddress, Theme.palette.directColor1) : elidedAddress + } + asset.color: !!account.colorId ? Utils.getColorForId(account.colorId): "" asset.emoji: account.emoji asset.name: !account.emoji ? "filled-account": "" asset.letterSize: 14 @@ -24,16 +33,22 @@ StatusListItem { asset.width: 40 asset.height: 40 - components: !showShevronIcon ? [] : [ shevronIcon ] - - onClicked: { - goToAccountView() - } - - StatusIcon { - id: shevronIcon - visible: root.showShevronIcon + components: StatusIcon { icon: "next" color: Theme.palette.baseColor1 } + + onClicked: goToAccountView() + + // This is used to give the first and last delgate rounded corners + Rectangle { + visible: totalCount > 1 + readonly property bool isLastOrFirstItem: index === 0 || index === (totalCount-1) + width: parent.width + height: isLastOrFirstItem? parent.height/2 : parent.height + anchors.top: !isLastOrFirstItem || index === (totalCount-1) ? parent.top: undefined + anchors.bottom: index === 0 ? parent.bottom: undefined + color: parent.color + z: parent.z - 10 + } } diff --git a/ui/app/AppLayouts/Profile/controls/WalletKeyPairDelegate.qml b/ui/app/AppLayouts/Profile/controls/WalletKeyPairDelegate.qml new file mode 100644 index 0000000000..3ccfaaa175 --- /dev/null +++ b/ui/app/AppLayouts/Profile/controls/WalletKeyPairDelegate.qml @@ -0,0 +1,93 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Controls 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 + +import utils 1.0 + +Rectangle { + id: root + + property string chainShortNames + property string userProfilePublicKey + + signal goToAccountView(var account) + + QtObject { + id: d + readonly property var relatedAccounts: model.keyPair.accounts + readonly property bool isWatchOnly: model.keyPair.pairType === Constants.keycard.keyPairType.watchOnly + readonly property bool isPrivateKeyImport: model.keyPair.pairType === Constants.keycard.keyPairType.privateKeyImport + readonly property bool isProfileKeypair: model.keyPair.pairType === Constants.keycard.keyPairType.profile + readonly property string locationInfo: model.keyPair.migratedToKeycard ? qsTr("On Keycard"): qsTr("On device") + } + + implicitHeight: layout.height + color: Theme.palette.baseColor4 + radius: 8 + + ColumnLayout { + id: layout + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + StatusListItem { + Layout.fillWidth: true + title: d.isWatchOnly ? qsTr("Watch only") : model.keyPair.name + statusListItemSubTitle.textFormat: Qt.RichText + titleTextIcon: model.keyPair.migratedToKeycard ? "keycard": "" + subTitle: d.isWatchOnly ? "" : d.isProfileKeypair ? + Utils.getElidedCompressedPk(model.keyPair.pubKey) + Constants.settingsSection.dotSepString + d.locationInfo : d.locationInfo + color: Theme.palette.transparent + ringSettings { + ringSpecModel: d.isProfileKeypair ? Utils.getColorHashAsJson(root.userProfilePublicKey) : [] + ringPxSize: Math.max(asset.width / 24.0) + } + asset { + width: model.keyPair.icon ? 24 : 40 + height: model.keyPair.icon ? 24 : 40 + name: model.keyPair.image ? model.keyPair.image : model.keyPair.icon + isImage: !!model.keyPair.image + color: d.isProfileKeypair ? Utils.colorForPubkey(root.userProfilePublicKey) : Theme.palette.primaryColor1 + letterSize: Math.max(4, asset.width / 2.4) + charactersLen: 2 + isLetterIdenticon: !model.keyPair.icon && !asset.name.toString() + } + components: [ + StatusFlatRoundButton { + icon.name: "more" + icon.color: Theme.palette.directColor1 + visible: !d.isWatchOnly + }, + StatusBaseText { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Include in total balance") + visible: d.isWatchOnly + }, + StatusSwitch { + visible: d.isWatchOnly + // To-do connect in different task +// checked: false +// onCheckedChanged: {} + } + ] + } + StatusListView { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + Layout.leftMargin: 16 + Layout.rightMargin: 16 + spacing: 1 + model: d.relatedAccounts + delegate: WalletAccountDelegate { + width: ListView.view.width + account: model.account + totalCount: ListView.view.count + chainShortNames: root.chainShortNames + onGoToAccountView: root.goToAccountView(model.account) + } + } + } +} diff --git a/ui/app/AppLayouts/Profile/controls/qmldir b/ui/app/AppLayouts/Profile/controls/qmldir index e936041715..e890fa52a0 100644 --- a/ui/app/AppLayouts/Profile/controls/qmldir +++ b/ui/app/AppLayouts/Profile/controls/qmldir @@ -4,3 +4,4 @@ AccountShowcaseDelegate 1.0 AccountShowcaseDelegate.qml AssetShowcaseDelegate 1.0 AssetShowcaseDelegate.qml WalletAccountDelegate 1.0 WalletAccountDelegate.qml StaticSocialLinkInput 1.0 StaticSocialLinkInput.qml +WalletKeyPairDelegate 1.0 WalletKeyPairDelegate.qml diff --git a/ui/app/AppLayouts/Profile/stores/WalletStore.qml b/ui/app/AppLayouts/Profile/stores/WalletStore.qml index 54aea5d968..d51925878b 100644 --- a/ui/app/AppLayouts/Profile/stores/WalletStore.qml +++ b/ui/app/AppLayouts/Profile/stores/WalletStore.qml @@ -22,6 +22,9 @@ QtObject { property var flatCollectibles: Global.appIsReady ? walletSectionCollectibles.model : null property var assets: walletSectionAssets.assets property var accounts: Global.appIsReady? accountsModule.accounts : null + property var originModel: accountsModule.keyPairModel + + property string userProfilePublicKey: userProfile.pubKey function deleteAccount(address) { return accountsModule.deleteAccount(address) @@ -48,4 +51,8 @@ QtObject { function loadDapps() { dappPermissionsModule.loadDapps() } + + function getAllNetworksSupportedPrefix() { + return networksModule.getAllNetworksSupportedPrefix() + } } diff --git a/ui/app/AppLayouts/Profile/views/wallet/MainView.qml b/ui/app/AppLayouts/Profile/views/wallet/MainView.qml index 750b97f408..5da96dd942 100644 --- a/ui/app/AppLayouts/Profile/views/wallet/MainView.qml +++ b/ui/app/AppLayouts/Profile/views/wallet/MainView.qml @@ -27,9 +27,9 @@ Column { root.walletStore.loadDapps() } - Separator { - height: 17 - } + spacing: 8 + + Separator {} StatusListItem { title: qsTr("DApp Permissions") @@ -45,9 +45,7 @@ Column { ] } - Separator { - height: 17 - } + Separator {} StatusListItem { objectName: "networksItem" @@ -63,105 +61,25 @@ Column { ] } - Separator { - height: 17 - } + Separator {} - StatusDescriptionListItem { - height: 64 - subTitle: qsTr("Accounts") - } - - StatusSectionHeadline { - text: qsTr("Generated from Your Seed Phrase") - leftPadding: Style.current.padding - topPadding: Style.current.halfPadding - bottomPadding: Style.current.halfPadding/2 - } - - ListView { - width: parent.width - height: childrenRect.height - objectName: "generatedAccounts" - model: SortFilterProxyModel { - sourceModel: walletStore.accounts - filters: ExpressionFilter { - expression: { - return model.walletType === "generated" || model.walletType === "" - } - } - } - delegate: WalletAccountDelegate { - width: ListView.view.width - account: model - onGoToAccountView: { - root.goToAccountView(model) - } - } - } - - SortFilterProxyModel { - id: importedAccounts - sourceModel: walletStore.accounts - filters: ExpressionFilter { - expression: { - return model.walletType !== "generated" && model.walletType !== "watch" && model.walletType !== "" - } - } - } - - StatusSectionHeadline { - text: qsTr("Imported") - leftPadding: Style.current.padding - topPadding: Style.current.halfPadding - bottomPadding: Style.current.halfPadding/2 - visible: importedAccounts.count > 0 - } - - Repeater { - width: parent.width - model: importedAccounts - delegate: WalletAccountDelegate { - width: parent.width - account: model - onGoToAccountView: { - root.goToAccountView(model) - } - } - } - - SortFilterProxyModel { - id: watchOnlyAccounts - sourceModel: walletStore.accounts - filters: ValueFilter { - roleName: "walletType" - value: "watch" - } - } - - StatusSectionHeadline { - text: qsTr("Watch-Only") - leftPadding: Style.current.padding - topPadding: Style.current.halfPadding - bottomPadding: Style.current.halfPadding/2 - visible: watchOnlyAccounts.count > 0 - } - - Repeater { - width: parent.width - model: watchOnlyAccounts - delegate: WalletAccountDelegate { - width: parent.width - account: model - onGoToAccountView: { - root.goToAccountView(model) - } - } - } - - // Adding padding to the end so that when the view is scrolled to the end there is some gap left Item { - height: Style.current.bigPadding width: parent.width + height: 8 + } + + Column { + width: parent.width + spacing: 24 + Repeater { + objectName: "generatedAccounts" + model: walletStore.originModel + delegate: WalletKeyPairDelegate { + width: parent.width + chainShortNames: walletStore.getAllNetworksSupportedPrefix() + userProfilePublicKey: walletStore.userProfilePublicKey + onGoToAccountView: root.goToAccountView(account) + } + } } } diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index d1ae7e6e81..e7ccc4164a 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -545,6 +545,8 @@ QtObject { readonly property int oneToOneChat: 1 readonly property int groupChat: 2 } + + property string dotSepString: '' } readonly property QtObject ephemeralNotificationType: QtObject { @@ -601,6 +603,7 @@ QtObject { readonly property int profile: 0 readonly property int seedImport: 1 readonly property int privateKeyImport: 2 + readonly property int watchOnly: 3 } readonly property QtObject shared: QtObject {