feat(@desktop/wallet): Adding features of Account, Network and Token Selection to the popup

fixes #16820, #16835, #16878
This commit is contained in:
Khushboo Mehta 2024-12-05 12:08:25 +01:00
parent 017cf6ca7e
commit 04e273d017
8 changed files with 282 additions and 36 deletions

View File

@ -10,6 +10,7 @@ import AppLayouts.Wallet.controls 1.0
import AppLayouts.Wallet.adaptors 1.0
import utils 1.0
import Models 1.0
import Storybook 1.0
import SortFilterProxyModel 0.2
@ -24,6 +25,8 @@ Pane {
// collection 2
{
tokenId: "id_3",
symbol: "abc",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 1",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
@ -43,6 +46,8 @@ Pane {
},
{
tokenId: "id_4",
symbol: "def",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 2",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
@ -62,6 +67,8 @@ Pane {
},
{
tokenId: "id_5",
symbol: "ghi",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 3",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
@ -82,6 +89,8 @@ Pane {
// collection 1
{
tokenId: "id_1",
symbol: "jkl",
chainId: NetworksModel.mainnetChainId,
name: "Genesis",
contractAddress: "contract_1",
collectionName: "ERC-1155 Faucet",
@ -106,6 +115,8 @@ Pane {
},
{
tokenId: "id_2",
symbol: "mno",
chainId: NetworksModel.mainnetChainId,
name: "QAERC1155",
contractAddress: "contract_1",
collectionName: "ERC-1155 Faucet",
@ -126,6 +137,8 @@ Pane {
// collection 3, community token
{
tokenId: "id_6",
symbol: "pqr",
chainId: NetworksModel.optChainId,
name: "My Token",
contractAddress: "contract_3",
collectionName: "My Token",
@ -145,6 +158,8 @@ Pane {
},
{
tokenId: "id_7",
symbol: "stu",
chainId: NetworksModel.optChainId,
name: "My Token",
contractAddress: "contract_3",
collectionName: "My Token",
@ -164,6 +179,8 @@ Pane {
},
{
tokenId: "id_8",
symbol: "vwx",
chainId: NetworksModel.optChainId,
name: "My Token",
contractAddress: "contract_3",
collectionName: "My Token",
@ -183,6 +200,8 @@ Pane {
},
{
tokenId: "id_9",
symbol: "yz1",
chainId: NetworksModel.optChainId,
name: "My Other Token",
contractAddress: "contract_4",
collectionName: "My Other Token",
@ -202,6 +221,8 @@ Pane {
},
{
tokenId: "id_10",
symbol: "234",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
@ -221,6 +242,8 @@ Pane {
},
{
tokenId: "id_11",
symbol: "567",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
@ -240,6 +263,8 @@ Pane {
},
{
tokenId: "id_11",
symbol: "8910",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
@ -259,6 +284,8 @@ Pane {
},
{
tokenId: "id_12",
symbol: "111213",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
@ -278,6 +305,8 @@ Pane {
},
{
tokenId: "id_13",
symbol: "141516",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
@ -312,6 +341,8 @@ Pane {
CollectiblesSelectionAdaptor {
id: adaptor
networksModel: NetworksModel.flatNetworks
enabledChainIds: [networksCombobox.currentValue]
collectiblesModel: listModel
accountKey: accountsSelector.selection
}
@ -333,6 +364,18 @@ Pane {
}
}
RowLayout {
Label { text: "Enabled Networks:" }
ComboBox {
id: networksCombobox
model: NetworksModel.flatNetworks
textRole: "chainName"
valueRole: "chainId"
currentIndex: 0
}
}
RowLayout {
GenericListView {
label: "Input model"

View File

@ -1,8 +1,11 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import SortFilterProxyModel 0.2
import StatusQ 0.1
import Models 1.0
import Storybook 1.0
@ -61,19 +64,28 @@ SplitView {
assetsModel: assetsSelectorViewAdaptor.outputAssetsModel
collectiblesModel: collectiblesSelectionAdaptor.model
networksModel: d.filteredNetworksModel
Component.onCompleted: simpleSend.open()
Binding on selectedAccountAddress {
value: accountsCombobox.currentValue ?? ""
}
Binding on selectedChainId {
value: networksCombobox.currentValue ?? 0
}
Binding on selectedTokenKey {
value: tokensCombobox.currentValue ?? ""
}
}
TokenSelectorViewAdaptor {
id: assetsSelectorViewAdaptor
assetsModel: d.walletAssetStore.groupedAccountAssetsModel
flatNetworksModel: NetworksModel.flatNetworks
currentCurrency: "USD"
accountAddress: simpleSend.selectedAccountAddress
showCommunityAssets: true
accountAddress: simpleSend.selectedAccountAddress
enabledChainIds: [simpleSend.selectedChainId]
}
@ -81,6 +93,7 @@ SplitView {
id: collectiblesSelectionAdaptor
accountKey: simpleSend.selectedAccountAddress
enabledChainIds: [simpleSend.selectedChainId]
networksModel: d.filteredNetworksModel
collectiblesModel: collectiblesBySymbolModel
@ -95,7 +108,7 @@ SplitView {
tokenId: "id_3",
symbol: "abc",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 1",
name: "Multi-seq NFT 1",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
collectionUid: "collection_2",
@ -116,7 +129,7 @@ SplitView {
tokenId: "id_4",
symbol: "def",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 2",
name: "Multi-seq NFT 2",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
collectionUid: "collection_2",
@ -137,7 +150,7 @@ SplitView {
tokenId: "id_5",
symbol: "ghi",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 3",
name: "Multi-seq NFT 3",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
collectionUid: "collection_2",
@ -402,10 +415,93 @@ SplitView {
LogsAndControlsPanel {
SplitView.minimumHeight: 100
SplitView.minimumWidth: 300
SplitView.maximumWidth: 380
CheckBox {
id: testNetworksCheckbox
text: "are test networks enabled"
ColumnLayout {
spacing: 20
Text {
text: "Values to set before popup is launched"
}
Text {
text: "Accounts Selection"
}
ComboBox {
id: accountsCombobox
model: SortFilterProxyModel {
sourceModel: d.walletAccountsModel
filters: ValueFilter {
roleName: "walletType"
value: Constants.watchWalletType
inverted: true
}
}
textRole: "name"
valueRole: "address"
currentIndex: 0
}
Text {
text: "account selected is: \n"
+ simpleSend.selectedAccountAddress
}
CheckBox {
id: testNetworksCheckbox
text: "are test networks enabled"
}
Text {
text: "Networks Selection"
}
ComboBox {
id: networksCombobox
model: d.filteredNetworksModel
textRole: "chainName"
valueRole: "chainId"
currentIndex: 0
}
Text {
text: "network selected is: " + simpleSend.selectedChainId
}
Text {
text: "Tokens selection"
}
ComboBox {
id: tokensCombobox
model: ConcatModel {
sources: [
SourceModel {
model: assetsSelectorViewAdaptor.outputAssetsModel
markerRoleValue: "first_model"
},
SourceModel {
model: collectiblesKeyModel
markerRoleValue: "second_model"
}
]
markerRoleName: "which_model"
expectedRoles: ["tokensKey", "name"]
}
textRole: "name"
valueRole: "tokensKey"
}
Text {
text: "token selected is: " + simpleSend.selectedTokenKey
}
RolesRenamingModel {
id: collectiblesKeyModel
sourceModel: collectiblesSelectionAdaptor.model
mapping: [
RoleRename {
from: "symbol"
to: "tokensKey"
}
]
}
}
}
}

View File

@ -46,6 +46,7 @@ QObject {
Expected model structure:
symbol [string] - unique identifier of a collectible
chainId [int] - unique identifier of a network
collectionUid [string] - unique identifier of a collection
contractAddress [string] - collectible's contract address
name [string] - collectible's name e.g. "Magicat"
@ -74,6 +75,9 @@ QObject {
**/
readonly property alias model: communityGroupsGrouppedByCollection
// In case collectibles are to be shown only on specific networks
property var enabledChainIds: []
LeftJoinModel {
id: jointCollectiblesByNwChainId
leftModel: collectiblesModel ?? null
@ -126,10 +130,18 @@ QObject {
exposedRoles: ["balance", "groupingValue", "icon", "key"]
}
filters: RangeFilter { /* 5 */
roleName: "balance"
minimumValue: 1
}
filters: [
RangeFilter { /* 5 */
roleName: "balance"
minimumValue: 1
},
// remove tokens not available on selected network(s)
FastExpressionFilter {
expression: root.enabledChainIds.includes(model.chainId)
expectedRoles: ["chainId"]
enabled: root.enabledChainIds.length
}
]
sorters: [ /* 6 */
RoleSorter {

View File

@ -34,10 +34,15 @@ Control {
property alias currentTab: tokenSelectorPanel.currentTab
function setSelection(name: string, icon: url, key: string) {
tokenSelectorButton.selected = true
tokenSelectorButton.name = name
tokenSelectorButton.icon = icon
tokenSelectorPanel.highlightedKey = key ?? ""
// reset token selector in case of empty call
if (!key && !name && !icon) {
tokenSelectorButton.selected = false
} else {
tokenSelectorButton.selected = true
tokenSelectorButton.name = name
tokenSelectorButton.icon = icon
tokenSelectorPanel.highlightedKey = key ?? ""
}
}
QObject {

View File

@ -7,6 +7,8 @@ import StatusQ.Core.Theme 0.1
import AppLayouts.Wallet.controls 1.0
import utils 1.0
RowLayout {
id: root
@ -53,8 +55,12 @@ RowLayout {
/** input property holds if the header is the sticky header **/
property bool isStickyHeader
/** property that exposes the selected network **/
readonly property int selectedNetworkChainId: selectedNetworkEntry.item.chainId
/** input property for programatic selection of network **/
property int selectedChainId
/** input property for programatic selection of token
(asset/collectible/collection) **/
property string selectedTokenKey
/** signal to propagate that an asset was selected **/
signal assetSelected(string key)
@ -62,6 +68,36 @@ RowLayout {
signal collectionSelected(string key)
/** signal to propagate that a collectible was selected **/
signal collectibleSelected(string key)
/** signal to propagate that a network was selected **/
signal networkSelected(string chainId)
QtObject {
id: d
readonly property bool selectedTokenNotAvailableOnAssetsOrCollectiblesList: !selectedAssetEntry.available && !selectedCollectibleEntry.available
onSelectedTokenNotAvailableOnAssetsOrCollectiblesListChanged: {
if(selectedTokenNotAvailableOnAssetsOrCollectiblesList) {
// reset token selector in case selected tokens doesnt exist in either models
tokenSelector.setSelection("", "", "")
}
}
function updateAssetInTokenSelector(available, item) {
if(available) {
tokenSelector.setSelection(item.symbol,
Constants.tokenIcon(item.symbol),
item.tokensKey)
}
}
function updateCollectibleInTokenSelector(available, item) {
if(available) {
const id = item.communityId ? item.collectionUid : item.uid
tokenSelector.setSelection(item.name,
item.imageUrl || item.mediaUrl,
id)
}
}
}
implicitHeight: sendModalTitleText.height
@ -133,12 +169,34 @@ RowLayout {
showSelectionIndicator: false
showTitle: false
Binding on selection {
value: [root.selectedChainId]
when: root.selectedChainId !== 0
}
onSelectionChanged: {
if (root.selectedChainId !== selection[0]) {
root.networkSelected(selection[0])
}
}
onToggleNetwork: root.networkSelected(chainId)
}
ModelEntry {
id: selectedNetworkEntry
sourceModel: root.networksModel
key: "chainId"
value: networkFilter.selection[0]
id: selectedAssetEntry
sourceModel: root.assetsModel
key: "tokensKey"
value: root.selectedTokenKey
onAvailableChanged: d.updateAssetInTokenSelector(available, item)
onItemChanged: d.updateAssetInTokenSelector(available, item)
}
ModelEntry {
id: selectedCollectibleEntry
sourceModel: root.collectiblesModel
key: "symbol"
value: root.selectedTokenKey
onAvailableChanged: d.updateCollectibleInTokenSelector(available, item)
onItemChanged: d.updateCollectibleInTokenSelector(available, item)
}
}

View File

@ -50,8 +50,12 @@ Rectangle {
**/
property bool isScrolling
/** property that exposes the selected network **/
readonly property int selectedNetworkChainId: sendModalHeader.selectedNetworkChainId
/** input property for programatic selection of network **/
property int selectedChainId: -1
/** input property for programatic selection of token
(asset/collectible/collection) **/
property string selectedTokenKey
/** signal to propagate that an asset was selected **/
signal assetSelected(string key)
@ -59,6 +63,8 @@ Rectangle {
signal collectionSelected(string key)
/** signal to propagate that a collectible was selected **/
signal collectibleSelected(string key)
/** signal to propagate that a network was selected **/
signal networkSelected(string chainId)
enabled: root.isScrolling
color: Theme.palette.baseColor3
@ -107,9 +113,13 @@ Rectangle {
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
selectedChainId: root.selectedChainId
selectedTokenKey: root.selectedTokenKey
onCollectibleSelected: root.collectibleSelected(key)
onCollectionSelected: root.collectionSelected(key)
onAssetSelected: root.assetSelected(key)
onNetworkSelected: root.networkSelected(chainId)
}
StatusDialogDivider {

View File

@ -65,10 +65,14 @@ StatusDialog {
**/
required property var networksModel
/** TODO: rethink property definitions needed to pre set values +
expose values to outside world **/
property int selectedChainId: sendModalHeader.selectedNetworkChainId
property string selectedAccountAddress: accountSelector.currentAccountAddress
/** property to set and expose currently selected account **/
property string selectedAccountAddress
/** property to set and expose currently selected network **/
property int selectedChainId
/** property to set and expose currently selected token key **/
property string selectedTokenKey
QtObject {
id: d
@ -106,6 +110,13 @@ StatusDialog {
anchors.leftMargin: -Theme.xlPadding
model: root.accountsModel
selectedAddress: root.selectedAccountAddress
onCurrentAccountAddressChanged: {
if(currentAccountAddress !== root.selectedAccountAddress) {
root.selectedAccountAddress = currentAccountAddress
}
}
}
// Sticky header only visible when scrolling
@ -117,14 +128,19 @@ StatusDialog {
anchors.leftMargin: -Theme.xlPadding
z: 1
isScrolling: d.isScrolling
networksModel: root.networksModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
isScrolling: d.isScrolling
onCollectibleSelected: console.log("collectible selected:", key)
onCollectionSelected: console.log("collection selected:", key)
onAssetSelected: console.log("asset selected:", key)
selectedChainId: root.selectedChainId
selectedTokenKey: root.selectedTokenKey
onCollectibleSelected: root.selectedTokenKey = key
onCollectionSelected: root.selectedTokenKey = key
onAssetSelected: root.selectedTokenKey = key
onNetworkSelected: root.selectedChainId = chainId
}
// Main scrollable Layout
@ -162,9 +178,13 @@ StatusDialog {
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
onCollectibleSelected: console.log("collectible selected:", key)
onCollectionSelected: console.log("collection selected:", key)
onAssetSelected: console.log("asset selected:", key)
selectedChainId: root.selectedChainId
selectedTokenKey: root.selectedTokenKey
onCollectibleSelected: root.selectedTokenKey = key
onCollectionSelected: root.selectedTokenKey = key
onAssetSelected: root.selectedTokenKey = key
onNetworkSelected: root.selectedChainId = chainId
}
// TODO: Remove these Dummy items added only to test dialog resizing

View File

@ -211,6 +211,7 @@ QtObject {
readonly property Component simpleSendModalComponent: Component {
SimpleSendModal {
id: simpleSendModal
/** TODO: use the newly defined WalletAccountsSelectorAdaptor
in https://github.com/status-im/status-desktop/pull/16834 **/
accountsModel: root.walletAccountsModel
@ -237,6 +238,7 @@ QtObject {
id: collectiblesSelectionAdaptor
accountKey: simpleSendModal.selectedAccountAddress
enabledChainIds: [simpleSendModal.selectedChainId]
networksModel: root.filteredFlatNetworksModel
collectiblesModel: root.collectiblesBySymbolModel