mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-11 06:06:30 +00:00
feat(@desktop/wallet): Move the Account Selector logic to show selected token balance on a sepcific network to a dedicated WalletAccountsSelectorAdaptor
fixes #16705
This commit is contained in:
parent
37a06fc3be
commit
0d4d1b0ba7
@ -7,48 +7,205 @@ import Models 1.0
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import shared.controls 1.0
|
||||
import shared.stores 1.0
|
||||
|
||||
Item {
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 16
|
||||
anchors.centerIn: parent
|
||||
implicitWidth: 150
|
||||
orientation: Qt.Vertical
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
WalletAccountsModel {
|
||||
id: accountsModel
|
||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||
readonly property var assetsStore: WalletAssetsStore {
|
||||
id: thisWalletAssetStore
|
||||
walletTokensStore: TokensStore {
|
||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||
}
|
||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Default style"
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
readonly property var currencyStore: CurrenciesStore{}
|
||||
readonly property var nonWatchWalletAcounts: SortFilterProxyModel {
|
||||
sourceModel: walletAccountsModel
|
||||
filters: ValueFilter { roleName: "canSend"; value: true }
|
||||
}
|
||||
AccountSelector {
|
||||
id: accountSelector
|
||||
Layout.fillWidth: true
|
||||
model: WalletAccountsModel {}
|
||||
onCurrentAccountAddressChanged: {
|
||||
accountSelector2.selectedAddress = currentAccountAddress
|
||||
|
||||
readonly property var filteredFlatNetworksModel: SortFilterProxyModel {
|
||||
sourceModel: d.flatNetworks
|
||||
filters: ValueFilter { roleName: "isTest"; value: true }
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: walletAccountsModel
|
||||
readonly property var data: [
|
||||
{
|
||||
name: "helloworld",
|
||||
address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
|
||||
emoji: "😋",
|
||||
colorId: Constants.walletAccountColors.primary,
|
||||
walletType: "",
|
||||
canSend: true,
|
||||
position: 0,
|
||||
currencyBalance: ({amount: 1.25,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: true
|
||||
},
|
||||
{
|
||||
name: "Hot wallet (generated)",
|
||||
emoji: "🚗",
|
||||
colorId: Constants.walletAccountColors.army,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
|
||||
walletType: Constants.generatedWalletType,
|
||||
canSend: true,
|
||||
position: 3,
|
||||
currencyBalance: ({amount: 10,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Family (seed)",
|
||||
emoji: "🎨",
|
||||
colorId: Constants.walletAccountColors.magenta,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882",
|
||||
walletType: Constants.seedWalletType,
|
||||
canSend: true,
|
||||
position: 1,
|
||||
currencyBalance: ({amount: 110.05,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Tag Heuer (watch)",
|
||||
emoji: "⌚",
|
||||
colorId: Constants.walletAccountColors.copper,
|
||||
color: "#CB6256",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8883",
|
||||
walletType: Constants.watchWalletType,
|
||||
canSend: false,
|
||||
position: 2,
|
||||
currencyBalance: ({amount: 3,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Fab (key)",
|
||||
emoji: "🔑",
|
||||
colorId: Constants.walletAccountColors.camel,
|
||||
color: "#C78F67",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8884",
|
||||
walletType: Constants.keyWalletType,
|
||||
canSend: true,
|
||||
position: 4,
|
||||
currencyBalance: ({amount: 999,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: append(data)
|
||||
}
|
||||
|
||||
WalletAccountsSelectorAdaptor {
|
||||
id: walletAccountsSelectorAdaptor
|
||||
|
||||
accounts: walletAccountsModel
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
tokensBySymbolModel: d.assetsStore.walletTokensStore.plainTokensBySymbolModel
|
||||
filteredFlatNetworksModel: d.filteredFlatNetworksModel
|
||||
|
||||
selectedTokenKey: selectedTokenComboBox.currentValue
|
||||
selectedNetworkChainId: networksComboBox.currentValue
|
||||
|
||||
fnFormatCurrencyAmountFromBigInt: function(balance, symbol, decimals, options = null) {
|
||||
return d.currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
SplitView.preferredWidth: 150
|
||||
SplitView.fillHeight: true
|
||||
ColumnLayout {
|
||||
spacing: 16
|
||||
width: 150
|
||||
|
||||
WalletAccountsModel {
|
||||
id: accountsModel
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Default style"
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
AccountSelector {
|
||||
id: accountSelector
|
||||
Layout.fillWidth: true
|
||||
model: WalletAccountsModel {}
|
||||
onCurrentAccountAddressChanged: {
|
||||
accountSelector2.selectedAddress = currentAccountAddress
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Header style"
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
AccountSelectorHeader {
|
||||
id: accountSelector2
|
||||
model: walletAccountsSelectorAdaptor.processedWalletAccounts
|
||||
onCurrentAccountAddressChanged: {
|
||||
accountSelector.selectedAddress = currentAccountAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Header style"
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
AccountSelectorHeader {
|
||||
id: accountSelector2
|
||||
model: accountSelector.model
|
||||
onCurrentAccountAddressChanged: {
|
||||
accountSelector.selectedAddress = currentAccountAddress
|
||||
}
|
||||
|
||||
Item {
|
||||
SplitView.preferredWidth: 300
|
||||
SplitView.preferredHeight: childrenRect.height
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
Label { text: "Selected Token" }
|
||||
ComboBox {
|
||||
id: selectedTokenComboBox
|
||||
textRole: "name"
|
||||
valueRole: "key"
|
||||
model: d.assetsStore.walletTokensStore.plainTokensBySymbolModel
|
||||
currentIndex: -1
|
||||
}
|
||||
|
||||
Label { text: "Selected Network" }
|
||||
ComboBox {
|
||||
id: networksComboBox
|
||||
textRole: "chainName"
|
||||
valueRole: "chainId"
|
||||
model: d.filteredFlatNetworksModel
|
||||
currentIndex: -1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Components
|
||||
|
@ -1,11 +1,12 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Core.Backpressure 0.1
|
||||
|
||||
import Models 1.0
|
||||
@ -32,6 +33,10 @@ SplitView {
|
||||
|
||||
readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore {
|
||||
assetsWithFilteredBalances: groupedAccountsAssetsModel
|
||||
walletTokensStore: TokensStore {
|
||||
plainTokensBySymbolModel: TokensBySymbolModel{}
|
||||
getDisplayAssetsBelowBalanceThresholdDisplayAmount: () => 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var walletAccountsModel: WalletAccountsModel{}
|
||||
@ -67,6 +72,14 @@ SplitView {
|
||||
simpleSend.estimatedFiatFees = "1.45 EUR"
|
||||
simpleSend.estimatedCryptoFees = "0.0007 ETH"
|
||||
})
|
||||
|
||||
function formatCurrencyAmount(amount, symbol, options = null, locale = null) {
|
||||
if (isNaN(amount)) {
|
||||
return "N/A"
|
||||
}
|
||||
var currencyAmount = d.getCurrencyAmount(amount, symbol)
|
||||
return LocaleUtils.currencyAmountToLocaleString(currencyAmount, options, locale)
|
||||
}
|
||||
}
|
||||
|
||||
PopupBackground {
|
||||
@ -96,7 +109,7 @@ SplitView {
|
||||
|
||||
interactive: interactiveCheckbox.checked
|
||||
|
||||
accountsModel: d.walletAccountsModel
|
||||
accountsModel: accountsSelectorAdaptor.processedWalletAccounts
|
||||
assetsModel: assetsSelectorViewAdaptor.outputAssetsModel
|
||||
collectiblesModel: collectiblesSelectionAdaptor.model
|
||||
networksModel: d.filteredNetworksModel
|
||||
@ -105,13 +118,7 @@ SplitView {
|
||||
recentRecipientsModel: WalletTransactionsModel{}
|
||||
|
||||
currentCurrency: "USD"
|
||||
fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) {
|
||||
if (isNaN(amount)) {
|
||||
return "N/A"
|
||||
}
|
||||
var currencyAmount = d.getCurrencyAmount(amount, symbol)
|
||||
return LocaleUtils.currencyAmountToLocaleString(currencyAmount, options, locale)
|
||||
}
|
||||
fnFormatCurrencyAmount: d.formatCurrencyAmount
|
||||
|
||||
fnResolveENS: Backpressure.debounce(root, 500, function (ensName, uuid) {
|
||||
if (!!ensName && ensName.endsWith(".eth")) {
|
||||
@ -146,6 +153,24 @@ SplitView {
|
||||
}
|
||||
}
|
||||
|
||||
WalletAccountsSelectorAdaptor {
|
||||
id: accountsSelectorAdaptor
|
||||
|
||||
accounts: d.walletAccountsModel
|
||||
assetsModel: GroupedAccountsAssetsModel {}
|
||||
tokensBySymbolModel: d.walletAssetStore.walletTokensStore.plainTokensBySymbolModel
|
||||
filteredFlatNetworksModel: d.filteredNetworksModel
|
||||
|
||||
selectedTokenKey: simpleSend.selectedTokenKey
|
||||
selectedNetworkChainId: simpleSend.selectedChainId
|
||||
|
||||
fnFormatCurrencyAmountFromBigInt: function(balance, symbol, decimals, options = null) {
|
||||
let bigIntBalance = AmountsArithmetic.fromString(balance)
|
||||
let decimalBalance = AmountsArithmetic.toNumber(bigIntBalance, decimals)
|
||||
return d.formatCurrencyAmount(decimalBalance, symbol, options)
|
||||
}
|
||||
}
|
||||
|
||||
TokenSelectorViewAdaptor {
|
||||
id: assetsSelectorViewAdaptor
|
||||
|
||||
|
187
storybook/pages/WalletAccountsSelectorAdaptorPage.qml
Normal file
187
storybook/pages/WalletAccountsSelectorAdaptorPage.qml
Normal file
@ -0,0 +1,187 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
ListModel {
|
||||
id: walletAccountsModel
|
||||
readonly property var data: [
|
||||
{
|
||||
name: "helloworld",
|
||||
address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
|
||||
emoji: "😋",
|
||||
colorId: Constants.walletAccountColors.primary,
|
||||
walletType: "",
|
||||
canSend: true,
|
||||
position: 0,
|
||||
currencyBalance: ({amount: 1.25,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: true
|
||||
},
|
||||
{
|
||||
name: "Hot wallet (generated)",
|
||||
emoji: "🚗",
|
||||
colorId: Constants.walletAccountColors.army,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
|
||||
walletType: Constants.generatedWalletType,
|
||||
canSend: true,
|
||||
position: 3,
|
||||
currencyBalance: ({amount: 10,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Family (seed)",
|
||||
emoji: "🎨",
|
||||
colorId: Constants.walletAccountColors.magenta,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882",
|
||||
walletType: Constants.seedWalletType,
|
||||
canSend: true,
|
||||
position: 1,
|
||||
currencyBalance: ({amount: 110.05,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Tag Heuer (watch)",
|
||||
emoji: "⌚",
|
||||
colorId: Constants.walletAccountColors.copper,
|
||||
color: "#CB6256",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8883",
|
||||
walletType: Constants.watchWalletType,
|
||||
canSend: false,
|
||||
position: 2,
|
||||
currencyBalance: ({amount: 3,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Fab (key)",
|
||||
emoji: "🔑",
|
||||
colorId: Constants.walletAccountColors.camel,
|
||||
color: "#C78F67",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8884",
|
||||
walletType: Constants.keyWalletType,
|
||||
canSend: true,
|
||||
position: 4,
|
||||
currencyBalance: ({amount: 999,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: append(data)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property var assetsStore: WalletAssetsStore {
|
||||
id: thisWalletAssetStore
|
||||
walletTokensStore: TokensStore {
|
||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||
}
|
||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||
}
|
||||
readonly property var currencyStore: CurrenciesStore{}
|
||||
}
|
||||
|
||||
WalletAccountsSelectorAdaptor {
|
||||
id: adaptor
|
||||
accounts: walletAccountsModel
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
tokensBySymbolModel: d.assetsStore.walletTokensStore.plainTokensBySymbolModel
|
||||
filteredFlatNetworksModel: SortFilterProxyModel {
|
||||
sourceModel: NetworksModel.flatNetworks
|
||||
filters: ValueFilter { roleName: "isTest"; value: true }
|
||||
}
|
||||
|
||||
fnFormatCurrencyAmountFromBigInt: function(balance, symbol, decimals, options = null) {
|
||||
return d.currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
|
||||
}
|
||||
|
||||
selectedTokenKey: selectedTokenComboBox.currentValue
|
||||
selectedNetworkChainId: networksComboBox.currentValue
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Label { text: "Selected Token" }
|
||||
ComboBox {
|
||||
id: selectedTokenComboBox
|
||||
textRole: "name"
|
||||
valueRole: "key"
|
||||
model: d.assetsStore.walletTokensStore.plainTokensBySymbolModel
|
||||
currentIndex: 0
|
||||
onCountChanged: currentIndex = 0
|
||||
}
|
||||
|
||||
Label { text: "Selected Network" }
|
||||
ComboBox {
|
||||
id: networksComboBox
|
||||
textRole: "chainName"
|
||||
valueRole: "chainId"
|
||||
model: adaptor.filteredFlatNetworksModel
|
||||
currentIndex: 0
|
||||
onCountChanged: currentIndex = 0
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
GenericListView {
|
||||
label: "Input Accounts model"
|
||||
|
||||
model: walletAccountsModel
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
roles: ["name", "address", "currencyBalance", "position", "canSend"]
|
||||
|
||||
skipEmptyRoles: true
|
||||
}
|
||||
|
||||
GenericListView {
|
||||
label: "Adapter's output model"
|
||||
|
||||
model: adaptor.processedWalletAccounts
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
roles: ["name", "address", "currencyBalance", "position", "canSend", "accountBalance", "currencyBalanceDouble"]
|
||||
|
||||
skipEmptyRoles: true
|
||||
|
||||
insetComponent: Label {
|
||||
text: "balance " + (model ? model.accountBalance.formattedBalance: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Adaptors
|
@ -171,26 +171,28 @@ Item {
|
||||
|
||||
function test_floating_header_default_account() {
|
||||
verify(!!controlUnderTest)
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
/* using a for loop set different accounts as default index and
|
||||
check if the correct values are displayed in the floating header*/
|
||||
for (let i = 0; i< swapAdaptor.nonWatchAccounts.count; i++) {
|
||||
const nonWatchAccount = swapAdaptor.nonWatchAccounts.get(i)
|
||||
root.swapFormData.selectedAccountAddress = nonWatchAccount.address
|
||||
for (let i = 0; i< walletAccounts.count; i++) {
|
||||
const accountToTest = walletAccounts.get(i)
|
||||
root.swapFormData.selectedAccountAddress = accountToTest.address
|
||||
|
||||
// Launch popup
|
||||
launchAndVerfyModal()
|
||||
|
||||
const floatingHeaderBackground = findChild(controlUnderTest, "headerBackground")
|
||||
verify(!!floatingHeaderBackground)
|
||||
compare(floatingHeaderBackground.color.toString().toUpperCase(), Utils.getColorForId(nonWatchAccount.colorId).toString().toUpperCase())
|
||||
compare(floatingHeaderBackground.color.toString().toUpperCase(), Utils.getColorForId(accountToTest.colorId).toString().toUpperCase())
|
||||
|
||||
const headerContentItemText = findChild(controlUnderTest, "textContent")
|
||||
verify(!!headerContentItemText)
|
||||
compare(headerContentItemText.text, nonWatchAccount.name)
|
||||
compare(headerContentItemText.text, accountToTest.name)
|
||||
|
||||
const headerContentItemEmoji = findChild(controlUnderTest, "assetContent")
|
||||
verify(!!headerContentItemEmoji)
|
||||
compare(headerContentItemEmoji.asset.emoji, nonWatchAccount.emoji)
|
||||
compare(headerContentItemEmoji.asset.emoji, accountToTest.emoji)
|
||||
}
|
||||
closeAndVerfyModal()
|
||||
}
|
||||
@ -228,6 +230,7 @@ Item {
|
||||
launchAndVerfyModal()
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
launchAccountSelectionPopup(accountsModalHeader)
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
const comboBoxList = findChild(controlUnderTest, "accountSelectorList")
|
||||
verify(!!comboBoxList)
|
||||
@ -235,7 +238,7 @@ Item {
|
||||
|
||||
for(let i =0; i< comboBoxList.model.count; i++) {
|
||||
let delegateUnderTest = comboBoxList.itemAtIndex(i)
|
||||
let accountToBeTested = swapAdaptor.nonWatchAccounts.get(i)
|
||||
let accountToBeTested = walletAccounts.get(i)
|
||||
let elidedAddress = SQUtils.Utils.elideAndFormatWalletAddress(accountToBeTested.address)
|
||||
compare(delegateUnderTest.title, accountToBeTested.name)
|
||||
compare(delegateUnderTest.subTitle, elidedAddress)
|
||||
@ -302,7 +305,6 @@ Item {
|
||||
|
||||
for(let i =0; i< comboBoxList.model.count; i++) {
|
||||
let delegateUnderTest = comboBoxList.itemAtIndex(i)
|
||||
verify(!!delegateUnderTest.model.fromToken)
|
||||
verify(!!delegateUnderTest.model.accountBalance)
|
||||
compare(delegateUnderTest.inlineTagModel, 1)
|
||||
|
||||
@ -315,9 +317,9 @@ Item {
|
||||
compare(inlineTagDelegate_0.asset.color.toString().toUpperCase(), delegateUnderTest.model.accountBalance.chainColor.toString().toUpperCase())
|
||||
compare(inlineTagDelegate_0.titleText.color, balance === "0" ? Theme.palette.baseColor1 : Theme.palette.directColor1)
|
||||
|
||||
let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(balance, delegateUnderTest.model.fromToken.decimals)
|
||||
compare(inlineTagDelegate_0.title, balance === "0" ? "0 %1".arg(delegateUnderTest.model.fromToken.symbol)
|
||||
: root.swapAdaptor.formatCurrencyAmount(bigIntBalance, delegateUnderTest.model.fromToken.symbol))
|
||||
let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(balance, controlUnderTest.swapAdaptor.fromToken.decimals)
|
||||
compare(inlineTagDelegate_0.title, balance === "0" ? "0 %1".arg(controlUnderTest.swapAdaptor.fromToken.symbol)
|
||||
: root.swapAdaptor.currencyStore.formatCurrencyAmount(bigIntBalance, controlUnderTest.swapAdaptor.fromToken.symbol))
|
||||
}
|
||||
|
||||
closeAndVerfyModal()
|
||||
@ -327,13 +329,16 @@ Item {
|
||||
// Launch popup
|
||||
launchAndVerfyModal()
|
||||
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
const payPanel = findChild(controlUnderTest, "payPanel")
|
||||
verify(!!payPanel)
|
||||
const amountToSendInput = findChild(payPanel, "amountToSendInput")
|
||||
verify(!!amountToSendInput)
|
||||
verify(amountToSendInput.cursorVisible)
|
||||
|
||||
for(let i =0; i< swapAdaptor.nonWatchAccounts.count; i++) {
|
||||
for(let i =0; i< walletAccounts.count; i++) {
|
||||
// launch account selection dropdown
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
launchAccountSelectionPopup(accountsModalHeader)
|
||||
@ -348,20 +353,20 @@ Item {
|
||||
verify(accountsModalHeader.control.popup.closed)
|
||||
|
||||
// The input params form's slected Index should be updated as per this selection
|
||||
compare(root.swapFormData.selectedAccountAddress, swapAdaptor.nonWatchAccounts.get(i).address)
|
||||
compare(root.swapFormData.selectedAccountAddress, walletAccounts.get(i).address)
|
||||
|
||||
// The comboBox item should reflect chosen account
|
||||
const floatingHeaderBackground = findChild(accountsModalHeader, "headerBackground")
|
||||
verify(!!floatingHeaderBackground)
|
||||
compare(floatingHeaderBackground.color.toString().toUpperCase(), swapAdaptor.nonWatchAccounts.get(i).color.toString().toUpperCase())
|
||||
compare(floatingHeaderBackground.color.toString().toUpperCase(), walletAccounts.get(i).color.toString().toUpperCase())
|
||||
|
||||
const headerContentItemText = findChild(accountsModalHeader, "textContent")
|
||||
verify(!!headerContentItemText)
|
||||
compare(headerContentItemText.text, swapAdaptor.nonWatchAccounts.get(i).name)
|
||||
compare(headerContentItemText.text, walletAccounts.get(i).name)
|
||||
|
||||
const headerContentItemEmoji = findChild(accountsModalHeader, "assetContent")
|
||||
verify(!!headerContentItemEmoji)
|
||||
compare(headerContentItemEmoji.asset.emoji, swapAdaptor.nonWatchAccounts.get(i).emoji)
|
||||
compare(headerContentItemEmoji.asset.emoji, walletAccounts.get(i).emoji)
|
||||
|
||||
waitForRendering(amountToSendInput)
|
||||
|
||||
@ -477,7 +482,7 @@ Item {
|
||||
verify(!!fromToken)
|
||||
let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(accountBalance.balance, fromToken.decimals)
|
||||
compare(inlineTagDelegate_0.title, bigIntBalance === 0 ? "0 %1".arg(fromToken.symbol)
|
||||
: root.swapAdaptor.formatCurrencyAmount(bigIntBalance, fromToken.symbol))
|
||||
: root.swapAdaptor.currencyStore.formatCurrencyAmount(bigIntBalance, fromToken.symbol))
|
||||
}
|
||||
// close account selection dropdown
|
||||
accountsModalHeader.control.popup.close()
|
||||
@ -918,7 +923,11 @@ Item {
|
||||
// try setting value before popup is launched and check values
|
||||
let valueToExchange = 0.001
|
||||
let valueToExchangeString = valueToExchange.toString()
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address
|
||||
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.fromTokensKey = "ETH"
|
||||
root.swapFormData.fromTokenAmount = valueToExchangeString
|
||||
@ -968,11 +977,14 @@ Item {
|
||||
}
|
||||
|
||||
function test_modal_pay_input_wrong_value_1() {
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
let invalidValues = ["ABC", "0.0.010201", "12PASA", "100,9.01"]
|
||||
for (let i =0; i<invalidValues.length; i++) {
|
||||
let invalidValue = invalidValues[i]
|
||||
// try setting value before popup is launched and check values
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.fromTokensKey =
|
||||
root.swapFormData.fromTokenAmount = invalidValue
|
||||
@ -1013,10 +1025,13 @@ Item {
|
||||
}
|
||||
|
||||
function test_modal_pay_input_wrong_value_2() {
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
// try setting value before popup is launched and check values
|
||||
let valueToExchange = 100
|
||||
let valueToExchangeString = valueToExchange.toString()
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.fromTokensKey = "ETH"
|
||||
root.swapFormData.fromTokenAmount = valueToExchangeString
|
||||
@ -1103,10 +1118,13 @@ Item {
|
||||
}
|
||||
|
||||
function test_modal_receive_input_presetValues() {
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
let valueToReceive = 0.001
|
||||
let valueToReceiveString = valueToReceive.toString()
|
||||
// try setting value before popup is launched and check values
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.toTokenKey = "STT"
|
||||
root.swapFormData.toTokenAmount = valueToReceiveString
|
||||
@ -1164,12 +1182,15 @@ Item {
|
||||
root.swapFormData.fromTokenAmount = valueToExchangeString
|
||||
root.swapFormData.toTokenKey = "STT"
|
||||
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
formValuesChanged.wait()
|
||||
|
||||
// Launch popup
|
||||
launchAndVerfyModal()
|
||||
// The default is the first account. Setting the second account to test switching accounts
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(1).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(1).address
|
||||
|
||||
waitForItemPolished(controlUnderTest.contentItem)
|
||||
|
||||
@ -1215,13 +1236,17 @@ Item {
|
||||
function test_modal_max_button_click_with_no_preset_pay_value() {
|
||||
// Launch popup
|
||||
launchAndVerfyModal()
|
||||
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
// The default is the first account. Setting the second account to test switching accounts
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(1).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(1).address
|
||||
formValuesChanged.clear()
|
||||
|
||||
// try setting value before popup is launched and check values
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.fromTokensKey = "ETH"
|
||||
root.swapFormData.toTokenKey = "STT"
|
||||
|
||||
@ -1266,6 +1291,10 @@ Item {
|
||||
}
|
||||
|
||||
function test_modal_pay_input_switching_accounts() {
|
||||
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
// test with pay value being set and not set
|
||||
let payValuesToTestWith = ["", "0.2"]
|
||||
|
||||
@ -1275,7 +1304,7 @@ Item {
|
||||
|
||||
// Asset chosen but no pay value set state -------------------------------------------------------------------------------
|
||||
root.swapFormData.fromTokenAmount = valueToExchangeString
|
||||
root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.fromTokensKey = "ETH"
|
||||
|
||||
@ -1292,8 +1321,8 @@ Item {
|
||||
const errorTag = findChild(controlUnderTest, "errorTag")
|
||||
verify(!!errorTag)
|
||||
|
||||
for (let i=0; i< root.swapAdaptor.nonWatchAccounts.count; i++) {
|
||||
root.swapFormData.selectedAccountAddress = root.swapAdaptor.nonWatchAccounts.get(i).address
|
||||
for (let i=0; i< walletAccounts.count; i++) {
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(i).address
|
||||
|
||||
waitForItemPolished(controlUnderTest.contentItem)
|
||||
|
||||
@ -1382,11 +1411,14 @@ Item {
|
||||
const receiveBottomItemText = findChild(receivePanel, "bottomItemText")
|
||||
verify(!!receiveBottomItemText)
|
||||
|
||||
const accountsModalHeader = getAndVerifyAccountsModalHeader()
|
||||
let walletAccounts = accountsModalHeader.model
|
||||
|
||||
root.swapAdaptor.reset()
|
||||
|
||||
// set network and address by default same
|
||||
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
|
||||
root.swapFormData.selectedAccountAddress = root.swapAdaptor.nonWatchAccounts.get(0).address
|
||||
root.swapFormData.selectedAccountAddress = walletAccounts.get(0).address
|
||||
root.swapFormData.fromTokensKey = data.fromToken
|
||||
root.swapFormData.fromTokenAmount = data.fromTokenAmount
|
||||
root.swapFormData.toTokenKey = data.toToken
|
||||
|
208
storybook/qmlTests/tests/tst_WalletAccountsSelectorAdaptor.qml
Normal file
208
storybook/qmlTests/tests/tst_WalletAccountsSelectorAdaptor.qml
Normal file
@ -0,0 +1,208 @@
|
||||
import QtQuick 2.15
|
||||
import QtTest 1.15
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
import Models 1.0
|
||||
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
ListModel {
|
||||
id: walletAccountsModel
|
||||
readonly property var data: [
|
||||
{
|
||||
name: "helloworld",
|
||||
address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
|
||||
emoji: "😋",
|
||||
colorId: Constants.walletAccountColors.primary,
|
||||
walletType: "",
|
||||
canSend: true,
|
||||
position: 0,
|
||||
currencyBalance: ({amount: 1.25,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: true
|
||||
},
|
||||
{
|
||||
name: "Hot wallet (generated)",
|
||||
emoji: "🚗",
|
||||
colorId: Constants.walletAccountColors.army,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
|
||||
walletType: Constants.generatedWalletType,
|
||||
canSend: true,
|
||||
position: 3,
|
||||
currencyBalance: ({amount: 10,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Family (seed)",
|
||||
emoji: "🎨",
|
||||
colorId: Constants.walletAccountColors.magenta,
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882",
|
||||
walletType: Constants.seedWalletType,
|
||||
canSend: true,
|
||||
position: 1,
|
||||
currencyBalance: ({amount: 110.05,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Tag Heuer (watch)",
|
||||
emoji: "⌚",
|
||||
colorId: Constants.walletAccountColors.copper,
|
||||
color: "#CB6256",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8883",
|
||||
walletType: Constants.watchWalletType,
|
||||
canSend: false,
|
||||
position: 2,
|
||||
currencyBalance: ({amount: 3,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
},
|
||||
{
|
||||
name: "Fab (key)",
|
||||
emoji: "🔑",
|
||||
colorId: Constants.walletAccountColors.camel,
|
||||
color: "#C78F67",
|
||||
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8884",
|
||||
walletType: Constants.keyWalletType,
|
||||
canSend: true,
|
||||
position: 4,
|
||||
currencyBalance: ({amount: 999,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false}),
|
||||
migratedToKeycard: false
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: append(data)
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||
readonly property var assetsStore: WalletAssetsStore {
|
||||
id: thisWalletAssetStore
|
||||
walletTokensStore: TokensStore {
|
||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||
}
|
||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||
}
|
||||
|
||||
readonly property var currencyStore: CurrenciesStore{}
|
||||
readonly property var nonWatchWalletAcounts: SortFilterProxyModel {
|
||||
sourceModel: walletAccountsModel
|
||||
filters: ValueFilter { roleName: "canSend"; value: true }
|
||||
}
|
||||
|
||||
readonly property var filteredFlatNetworksModel: SortFilterProxyModel {
|
||||
sourceModel: d.flatNetworks
|
||||
filters: ValueFilter { roleName: "isTest"; value: true }
|
||||
}
|
||||
|
||||
readonly property ObjectProxyModel filteredBalancesModel: ObjectProxyModel {
|
||||
sourceModel: d.assetsStore.groupedAccountAssetsModel
|
||||
|
||||
delegate: SortFilterProxyModel {
|
||||
readonly property var balances: this
|
||||
|
||||
sourceModel: LeftJoinModel {
|
||||
leftModel: model.balances
|
||||
rightModel: d.filteredFlatNetworksModel
|
||||
|
||||
joinRole: "chainId"
|
||||
}
|
||||
|
||||
filters: ValueFilter {
|
||||
roleName: "chainId"
|
||||
value: d.selectedNetworkChainId
|
||||
}
|
||||
}
|
||||
|
||||
expectedRoles: "balances"
|
||||
exposedRoles: "balances"
|
||||
}
|
||||
|
||||
property string selectedTokenKey: "ETH"
|
||||
property int selectedNetworkChainId: 11155111
|
||||
}
|
||||
|
||||
Component {
|
||||
id: componentUnderTest
|
||||
WalletAccountsSelectorAdaptor {
|
||||
accounts: walletAccountsModel
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
tokensBySymbolModel: d.assetsStore.walletTokensStore.plainTokensBySymbolModel
|
||||
filteredFlatNetworksModel: d.filteredFlatNetworksModel
|
||||
|
||||
selectedTokenKey: d.selectedTokenKey
|
||||
selectedNetworkChainId: d.selectedNetworkChainId
|
||||
|
||||
fnFormatCurrencyAmountFromBigInt: function(balance, symbol, decimals, options = null) {
|
||||
return d.currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property WalletAccountsSelectorAdaptor controlUnderTest: null
|
||||
|
||||
TestCase {
|
||||
name: "WalletAccountsSelectorAdaptor"
|
||||
when: windowShown
|
||||
|
||||
function init() {
|
||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||
}
|
||||
|
||||
function test_no_watchOnly_account() {
|
||||
verify(!!controlUnderTest)
|
||||
compare(controlUnderTest.processedWalletAccounts.count, d.nonWatchWalletAcounts.count)
|
||||
}
|
||||
|
||||
function test_accountBalance_data() {
|
||||
return [
|
||||
{selectedTokenKey: "ETH", chainId: 11155111},
|
||||
{selectedTokenKey: "STT", chainId: 11155111},
|
||||
{selectedTokenKey: "ETH", chainId: 11155420},
|
||||
{selectedTokenKey: "STT", chainId: 11155420}
|
||||
]
|
||||
}
|
||||
|
||||
function test_accountBalance(data) {
|
||||
verify(!!controlUnderTest)
|
||||
d.selectedTokenKey = data.selectedTokenKey
|
||||
d.selectedNetworkChainId = data.chainId
|
||||
let processedAccounts = controlUnderTest.processedWalletAccounts
|
||||
for (let i = 0; i < processedAccounts.count; i++) {
|
||||
let accountAddress = processedAccounts.get(i).address
|
||||
let selectedTokenBalancesModel = ModelUtils.getByKey(d.filteredBalancesModel, "tokensKey", d.selectedTokenKey).balances
|
||||
let tokenBalanceForSelectedAccount = ModelUtils.getByKey(selectedTokenBalancesModel, "account", accountAddress) ?? 0
|
||||
let tokenBalanceForAccount = !!tokenBalanceForSelectedAccount ? tokenBalanceForSelectedAccount.balance: "0"
|
||||
|
||||
compare(tokenBalanceForAccount, processedAccounts.get(i).accountBalance.balance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
import QtQuick 2.15
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
/**
|
||||
Transforms and prepares the wallet accounts model to display
|
||||
selected token on selected network
|
||||
|
||||
When no token or network is selected, only currency balance for account is shown.
|
||||
*/
|
||||
QObject {
|
||||
id: root
|
||||
|
||||
// input api
|
||||
|
||||
/** Expected accounts model structure:
|
||||
- name: name of the account
|
||||
- address: address of the account,
|
||||
- colorId: color id for the account,
|
||||
- canSend: can send from acount ,
|
||||
- position: position set by user in settings,
|
||||
- currencyBalance: total currency balance in CurrencyAmount type,
|
||||
- migratedToKeycard: if account is migrated to keycard.
|
||||
*/
|
||||
required property var accounts
|
||||
/** Expected assets model structure:
|
||||
- tokensKey: string -> unique string ID of the token (asset); e.g. "ETH" or contract address
|
||||
- name: string -> user visible token name (e.g. "Ethereum")
|
||||
- symbol: string -> user visible token symbol (e.g. "ETH")
|
||||
- decimals: int -> number of decimal places
|
||||
- communityId: string -> optional; ID of the community this token belongs to, if any
|
||||
- marketDetails: var -> object containing props like `currencyPrice` for the computed values below
|
||||
- balances: submodel -> [ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
|
||||
*/
|
||||
required property var assetsModel
|
||||
/** Expected token by symbol model structure:
|
||||
- key: id for the token,
|
||||
- name: name of the token,
|
||||
- symbol: symbol of the token,
|
||||
- decimals: decimals for the token
|
||||
*/
|
||||
required property var tokensBySymbolModel
|
||||
/** Expected networks model structure:
|
||||
- chainId: chain Id for network,
|
||||
- chainName: name of network,
|
||||
- iconUrl: icon representing the network,
|
||||
*/
|
||||
required property var filteredFlatNetworksModel
|
||||
/** selectedTokenKey:
|
||||
the selected token key
|
||||
*/
|
||||
required property string selectedTokenKey
|
||||
/** selectedNetworkChainId:
|
||||
the selected network chainId
|
||||
*/
|
||||
required property int selectedNetworkChainId
|
||||
|
||||
/** function to calculate token balance from BigInt:
|
||||
the selected network chainId
|
||||
*/
|
||||
required property var fnFormatCurrencyAmountFromBigInt
|
||||
|
||||
/** output model
|
||||
Computed processedWalletAccounts model addon values:
|
||||
- accountBalance: balance of selected token on selected network along with network information
|
||||
- filters out account that cant be used to send
|
||||
*/
|
||||
readonly property var processedWalletAccounts: SortFilterProxyModel {
|
||||
sourceModel: root.accounts
|
||||
delayed: true // Delayed to allow `processAccountBalance` dependencies to be resolved
|
||||
filters: ValueFilter {
|
||||
roleName: "canSend"
|
||||
value: true
|
||||
}
|
||||
sorters: [
|
||||
RoleSorter { roleName: "currencyBalanceDouble"; sortOrder: Qt.DescendingOrder },
|
||||
RoleSorter { roleName: "position"; sortOrder: Qt.AscendingOrder }
|
||||
]
|
||||
proxyRoles: [
|
||||
FastExpressionRole {
|
||||
name: "accountBalance"
|
||||
expression: {
|
||||
// dependencies
|
||||
root.selectedTokenKey
|
||||
root.selectedNetworkChainId
|
||||
return d.processAccountBalance(model.address)
|
||||
}
|
||||
expectedRoles: ["address"]
|
||||
},
|
||||
FastExpressionRole {
|
||||
name: "currencyBalanceDouble"
|
||||
expression: model.currencyBalance.amount
|
||||
expectedRoles: ["currencyBalance"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property ObjectProxyModel filteredBalancesModel: ObjectProxyModel {
|
||||
sourceModel: root.assetsModel
|
||||
|
||||
delegate: SortFilterProxyModel {
|
||||
readonly property var balances: this
|
||||
|
||||
sourceModel: LeftJoinModel {
|
||||
leftModel: model.balances
|
||||
rightModel: root.filteredFlatNetworksModel
|
||||
|
||||
joinRole: "chainId"
|
||||
}
|
||||
|
||||
filters: ValueFilter {
|
||||
roleName: "chainId"
|
||||
value: root.selectedNetworkChainId
|
||||
}
|
||||
}
|
||||
|
||||
expectedRoles: "balances"
|
||||
exposedRoles: "balances"
|
||||
}
|
||||
|
||||
function processAccountBalance(address) {
|
||||
let selectedToken = ModelUtils.getByKey(root.tokensBySymbolModel, "key", root.selectedTokenKey)
|
||||
if (!selectedToken) {
|
||||
return null
|
||||
}
|
||||
|
||||
let network = ModelUtils.getByKey(root.filteredFlatNetworksModel, "chainId", root.selectedNetworkChainId)
|
||||
if (!network) {
|
||||
return null
|
||||
}
|
||||
|
||||
let balancesModel = ModelUtils.getByKey(filteredBalancesModel, "tokensKey", root.selectedTokenKey, "balances")
|
||||
let accountBalance = ModelUtils.getByKey(balancesModel, "account", address)
|
||||
if(accountBalance && accountBalance.balance !== "0") {
|
||||
accountBalance.formattedBalance = root.fnFormatCurrencyAmountFromBigInt(accountBalance.balance, selectedToken.symbol, selectedToken.decimals)
|
||||
return accountBalance
|
||||
}
|
||||
|
||||
return {
|
||||
balance: "0",
|
||||
iconUrl: network.iconUrl,
|
||||
chainColor: network.chainColor,
|
||||
formattedBalance: "0 %1".arg(selectedToken.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
CollectiblesSelectionAdaptor 1.0 CollectiblesSelectionAdaptor.qml
|
||||
TokenSelectorViewAdaptor 1.0 TokenSelectorViewAdaptor.qml
|
||||
WalletAccountsSelectorAdaptor 1.0 WalletAccountsSelectorAdaptor.qml
|
||||
|
@ -23,9 +23,6 @@ StatusDialog {
|
||||
id: root
|
||||
|
||||
/**
|
||||
TODO: use the newly defined WalletAccountsSelectorAdaptor
|
||||
in https://github.com/status-im/status-desktop/pull/16834
|
||||
This will also remove watch only accounts from the list
|
||||
Expected model structure:
|
||||
- name: name of account
|
||||
- address: wallet address
|
||||
|
@ -1,9 +1,11 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Backpressure 0.1
|
||||
@ -18,6 +20,7 @@ import shared.panels 1.0
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
import AppLayouts.Wallet.popups.buy 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
StatusDialog {
|
||||
id: root
|
||||
@ -58,11 +61,37 @@ StatusDialog {
|
||||
selectedTokenKey: root.swapInputParamsForm.fromTokensKey
|
||||
}
|
||||
|
||||
readonly property WalletAccountsSelectorAdaptor accountsSelectorAdaptor : WalletAccountsSelectorAdaptor {
|
||||
accounts: root.swapAdaptor.swapStore.accounts
|
||||
assetsModel: root.swapAdaptor.walletAssetsStore.baseGroupedAccountAssetModel
|
||||
tokensBySymbolModel: root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel
|
||||
filteredFlatNetworksModel: SortFilterProxyModel {
|
||||
sourceModel: root.swapAdaptor.swapStore.flatNetworks
|
||||
filters: ValueFilter { roleName: "isTest"; value: root.swapAdaptor.swapStore.areTestNetworksEnabled }
|
||||
}
|
||||
|
||||
selectedTokenKey: root.swapInputParamsForm.fromTokensKey
|
||||
selectedNetworkChainId: root.swapInputParamsForm.selectedNetworkChainId
|
||||
|
||||
fnFormatCurrencyAmountFromBigInt: function(balance, symbol, decimals, options = null) {
|
||||
return root.swapAdaptor.currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var selectedAccount: selectedAccountEntry.item
|
||||
|
||||
function addMetricsEvent(subEventName) {
|
||||
Global.addCentralizedMetricIfEnabled("swap", {subEvent: subEventName})
|
||||
}
|
||||
}
|
||||
|
||||
ModelEntry {
|
||||
id: selectedAccountEntry
|
||||
sourceModel: d.accountsSelectorAdaptor.processedWalletAccounts
|
||||
key: "address"
|
||||
value: root.swapInputParamsForm.selectedAccountAddress
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.swapInputParamsForm
|
||||
function onFormValuesChanged() {
|
||||
@ -109,7 +138,7 @@ StatusDialog {
|
||||
AccountSelectorHeader {
|
||||
id: selector
|
||||
control.popup.width: 512
|
||||
model: root.swapAdaptor.nonWatchAccounts
|
||||
model: d.accountsSelectorAdaptor.processedWalletAccounts
|
||||
selectedAddress: root.swapInputParamsForm.selectedAccountAddress
|
||||
onCurrentAccountAddressChanged: {
|
||||
if (currentAccountAddress !== "" && currentAccountAddress !== root.swapInputParamsForm.selectedAccountAddress) {
|
||||
@ -409,7 +438,7 @@ StatusDialog {
|
||||
objectName: "signButton"
|
||||
readonly property string fromTokenSymbol: !!root.swapAdaptor.fromToken ? root.swapAdaptor.fromToken.symbol ?? "" : ""
|
||||
loadingWithText: root.swapAdaptor.approvalPending
|
||||
icon.name: root.swapAdaptor.selectedAccount.migratedToKeycard ? Constants.authenticationIconByType[Constants.LoginType.Keycard]
|
||||
icon.name: d.selectedAccount.migratedToKeycard ? Constants.authenticationIconByType[Constants.LoginType.Keycard]
|
||||
: Constants.authenticationIconByType[root.loginType]
|
||||
text: {
|
||||
if(root.swapAdaptor.validSwapProposalReceived) {
|
||||
@ -461,7 +490,7 @@ StatusDialog {
|
||||
|
||||
formatBigNumber: (number, symbol, noSymbolOption) => root.swapAdaptor.currencyStore.formatBigNumber(number, symbol, noSymbolOption)
|
||||
|
||||
loginType: root.swapAdaptor.selectedAccount.migratedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
loginType: d.selectedAccount.migratedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
feesLoading: root.swapAdaptor.swapProposalLoading
|
||||
|
||||
fromTokenSymbol: root.swapAdaptor.fromToken.symbol
|
||||
@ -470,11 +499,11 @@ StatusDialog {
|
||||
"chainId", root.swapInputParamsForm.selectedNetworkChainId,
|
||||
"address")
|
||||
|
||||
accountName: root.swapAdaptor.selectedAccount.name
|
||||
accountAddress: root.swapAdaptor.selectedAccount.address
|
||||
accountEmoji: root.swapAdaptor.selectedAccount.emoji
|
||||
accountColor: Utils.getColorForId(root.swapAdaptor.selectedAccount.colorId)
|
||||
accountBalanceFormatted: root.swapAdaptor.selectedAccount.accountBalance.formattedBalance
|
||||
accountName: d.selectedAccount.name
|
||||
accountAddress: d.selectedAccount.address
|
||||
accountEmoji: d.selectedAccount.emoji
|
||||
accountColor: Utils.getColorForId(d.selectedAccount.colorId)
|
||||
accountBalanceFormatted: d.selectedAccount.accountBalance.formattedBalance
|
||||
|
||||
networkShortName: networkFilter.singleSelectionItemData.shortName
|
||||
networkName: networkFilter.singleSelectionItemData.chainName
|
||||
@ -513,7 +542,7 @@ StatusDialog {
|
||||
|
||||
formatBigNumber: (number, symbol, noSymbolOption) => root.swapAdaptor.currencyStore.formatBigNumber(number, symbol, noSymbolOption)
|
||||
|
||||
loginType: root.swapAdaptor.selectedAccount.migratedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
loginType: d.selectedAccount.migratedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
feesLoading: root.swapAdaptor.swapProposalLoading
|
||||
|
||||
fromTokenSymbol: root.swapAdaptor.fromToken.symbol
|
||||
@ -528,10 +557,10 @@ StatusDialog {
|
||||
"chainId", root.swapInputParamsForm.selectedNetworkChainId,
|
||||
"address")
|
||||
|
||||
accountName: root.swapAdaptor.selectedAccount.name
|
||||
accountAddress: root.swapAdaptor.selectedAccount.address
|
||||
accountEmoji: root.swapAdaptor.selectedAccount.emoji
|
||||
accountColor: Utils.getColorForId(root.swapAdaptor.selectedAccount.colorId)
|
||||
accountName: d.selectedAccount.name
|
||||
accountAddress: d.selectedAccount.address
|
||||
accountEmoji: d.selectedAccount.emoji
|
||||
accountColor: Utils.getColorForId(d.selectedAccount.colorId)
|
||||
|
||||
networkShortName: networkFilter.singleSelectionItemData.shortName
|
||||
networkName: networkFilter.singleSelectionItemData.chainName
|
||||
|
@ -33,51 +33,9 @@ QObject {
|
||||
// To expose the selected from and to Token from the SwapModal
|
||||
readonly property var fromToken: fromTokenEntry.item
|
||||
readonly property var toToken: toTokenEntry.item
|
||||
readonly property var selectedAccount: selectedAccountEntry.item
|
||||
|
||||
readonly property string uuid: d.uuid
|
||||
|
||||
// TO REVIEW: Handle this in a separate `WalletAccountsAdaptor.qml` file.
|
||||
// Probably this data transformation should live there since they have common base.
|
||||
readonly property var nonWatchAccounts: SortFilterProxyModel {
|
||||
sourceModel: root.swapStore.accounts
|
||||
delayed: true // Delayed to allow `processAccountBalance` dependencies to be resolved
|
||||
filters: ValueFilter {
|
||||
roleName: "canSend"
|
||||
value: true
|
||||
}
|
||||
sorters: [
|
||||
RoleSorter { roleName: "currencyBalanceDouble"; sortOrder: Qt.DescendingOrder },
|
||||
RoleSorter { roleName: "position"; sortOrder: Qt.AscendingOrder }
|
||||
]
|
||||
proxyRoles: [
|
||||
FastExpressionRole {
|
||||
name: "accountBalance"
|
||||
expression: {
|
||||
// dependencies
|
||||
root.swapFormData.fromTokensKey
|
||||
root.fromToken
|
||||
root.fromToken.symbol
|
||||
root.fromToken.decimals
|
||||
root.swapFormData.selectedNetworkChainId
|
||||
root.swapFormData.fromTokensKey
|
||||
|
||||
return d.processAccountBalance(model.address)
|
||||
}
|
||||
expectedRoles: ["address"]
|
||||
},
|
||||
FastExpressionRole {
|
||||
name: "currencyBalanceDouble"
|
||||
expression: model.currencyBalance.amount
|
||||
expectedRoles: ["currencyBalance"]
|
||||
},
|
||||
FastExpressionRole {
|
||||
name: "fromToken"
|
||||
expression: root.fromToken
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
readonly property SortFilterProxyModel filteredFlatNetworksModel: SortFilterProxyModel {
|
||||
sourceModel: root.swapStore.flatNetworks
|
||||
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
|
||||
@ -94,55 +52,6 @@ QObject {
|
||||
// storing txHash to verify against tx completed event
|
||||
property string txHash
|
||||
|
||||
readonly property ObjectProxyModel filteredBalancesModel: ObjectProxyModel {
|
||||
sourceModel: root.walletAssetsStore.baseGroupedAccountAssetModel
|
||||
|
||||
delegate: SortFilterProxyModel {
|
||||
readonly property var balances: this
|
||||
|
||||
sourceModel: LeftJoinModel {
|
||||
leftModel: model.balances
|
||||
rightModel: root.swapStore.flatNetworks
|
||||
|
||||
joinRole: "chainId"
|
||||
}
|
||||
|
||||
filters: ValueFilter {
|
||||
roleName: "chainId"
|
||||
value: root.swapFormData.selectedNetworkChainId
|
||||
}
|
||||
}
|
||||
|
||||
expectedRoles: "balances"
|
||||
exposedRoles: "balances"
|
||||
}
|
||||
|
||||
function processAccountBalance(address) {
|
||||
if (!root.swapFormData.fromTokensKey || !root.fromToken) {
|
||||
return null
|
||||
}
|
||||
|
||||
let network = ModelUtils.getByKey(root.filteredFlatNetworksModel, "chainId", root.swapFormData.selectedNetworkChainId)
|
||||
|
||||
if (!network) {
|
||||
return null
|
||||
}
|
||||
|
||||
let balancesModel = ModelUtils.getByKey(filteredBalancesModel, "tokensKey", root.swapFormData.fromTokensKey, "balances")
|
||||
let accountBalance = ModelUtils.getByKey(balancesModel, "account", address)
|
||||
if(accountBalance && accountBalance.balance !== "0") {
|
||||
accountBalance.formattedBalance = root.formatCurrencyAmountFromBigInt(accountBalance.balance, root.fromToken.symbol, root.fromToken.decimals)
|
||||
return accountBalance
|
||||
}
|
||||
|
||||
return {
|
||||
balance: "0",
|
||||
iconUrl: network.iconUrl,
|
||||
chainColor: network.chainColor,
|
||||
formattedBalance: "0 %1".arg(root.fromToken.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
// Properties to handle error states
|
||||
readonly property bool isRouteEthBalanceInsufficient: root.validSwapProposalReceived && root.swapOutputData.errCode === Constants.routerErrorCodes.router.errNotEnoughNativeBalance
|
||||
|
||||
@ -209,13 +118,6 @@ QObject {
|
||||
value: root.swapFormData.toTokenKey
|
||||
}
|
||||
|
||||
ModelEntry {
|
||||
id: selectedAccountEntry
|
||||
sourceModel: root.nonWatchAccounts
|
||||
key: "address"
|
||||
value: root.swapFormData.selectedAccountAddress
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.swapStore
|
||||
function onSuggestedRoutesReady(txRoutes, errCode, errDescription) {
|
||||
@ -284,14 +186,6 @@ QObject {
|
||||
d.txHash = ""
|
||||
}
|
||||
|
||||
function formatCurrencyAmount(balance, symbol, options = null, locale = null) {
|
||||
return root.currencyStore.formatCurrencyAmount(balance, symbol, options, locale)
|
||||
}
|
||||
|
||||
function formatCurrencyAmountFromBigInt(balance, symbol, decimals, options = null) {
|
||||
return root.currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
|
||||
}
|
||||
|
||||
function getDisabledChainIds(enabledChainId) {
|
||||
let disabledChainIds = []
|
||||
let chainIds = ModelUtils.modelToFlatArray(root.filteredFlatNetworksModel, "chainId")
|
||||
|
@ -668,21 +668,22 @@ Item {
|
||||
flatNetworksModel: WalletStores.RootStore.flatNetworks
|
||||
areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled
|
||||
groupedAccountAssetsModel: appMain.walletAssetsStore.groupedAccountAssetsModel
|
||||
currentCurrency: appMain.currencyStore.currentCurrency
|
||||
plainTokensBySymbolModel: appMain.tokensStore.plainTokensBySymbolModel
|
||||
showCommunityAssetsInSend: appMain.tokensStore.showCommunityAssetsInSend
|
||||
collectiblesBySymbolModel: WalletStores.RootStore.collectiblesStore.jointCollectiblesBySymbolModel
|
||||
tokenBySymbolModel: appMain.tokensStore.plainTokensBySymbolModel
|
||||
fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) {
|
||||
return appMain.currencyStore.formatCurrencyAmount(amount, symbol)
|
||||
}
|
||||
savedAddressesModel: WalletStores.RootStore.savedAddresses
|
||||
recentRecipientsModel: appMain.transactionStore.tempActivityController1Model
|
||||
|
||||
currentCurrency: appMain.currencyStore.currentCurrency
|
||||
fnFormatCurrencyAmount: appMain.currencyStore.formatCurrencyAmount
|
||||
fnFormatCurrencyAmountFromBigInt: appMain.currencyStore.formatCurrencyAmountFromBigInt
|
||||
|
||||
// TODO remove this call to mainModule under #16919
|
||||
fnResolveENS: function(ensName, uuid) {
|
||||
mainModule.resolveENS(name, uuid)
|
||||
}
|
||||
|
||||
savedAddressesModel: WalletStores.RootStore.savedAddresses
|
||||
recentRecipientsModel: appMain.transactionStore.tempActivityController1Model
|
||||
|
||||
Component.onCompleted: {
|
||||
// It's requested from many nested places, so as a workaround we use
|
||||
// Global to shorten the path via global signal.
|
||||
|
@ -41,8 +41,6 @@ QtObject {
|
||||
|
||||
/** For simple send modal flows, decoupling from transaction store **/
|
||||
|
||||
/** curently selected fiat currency symbol **/
|
||||
required property string currentCurrency
|
||||
/** Expected model structure:
|
||||
- name: name of account
|
||||
- address: wallet address
|
||||
@ -62,6 +60,13 @@ QtObject {
|
||||
- balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
|
||||
**/
|
||||
required property var groupedAccountAssetsModel
|
||||
/** Expected token by symbol model structure:
|
||||
- key: id for the token,
|
||||
- name: name of the token,
|
||||
- symbol: symbol of the token,
|
||||
- decimals: decimals for the token
|
||||
*/
|
||||
required property var plainTokensBySymbolModel
|
||||
/** Expected model structure:
|
||||
- symbol [string] - unique identifier of a collectible
|
||||
- collectionUid [string] - unique identifier of a collection
|
||||
@ -96,8 +101,6 @@ QtObject {
|
||||
/** whether community tokens are shown in send modal
|
||||
based on a global setting **/
|
||||
required property bool showCommunityAssetsInSend
|
||||
/** required function to format currency amount to locale string **/
|
||||
required property var fnFormatCurrencyAmount
|
||||
|
||||
required property var savedAddressesModel
|
||||
required property var recentRecipientsModel
|
||||
@ -107,6 +110,13 @@ QtObject {
|
||||
/** required signal to receive resolved ens name address **/
|
||||
signal ensNameResolved(string resolvedPubKey, string resolvedAddress, string uuid)
|
||||
|
||||
/** curently selected fiat currency symbol **/
|
||||
required property string currentCurrency
|
||||
/** required function to format currency amount to locale string **/
|
||||
required property var fnFormatCurrencyAmount
|
||||
/** required function to format to currency amount from big int **/
|
||||
required property var fnFormatCurrencyAmountFromBigInt
|
||||
|
||||
function openSend(params = {}) {
|
||||
// TODO remove once simple send is feature complete
|
||||
let sendModalCmp = root.simpleSendEnabled ? simpleSendModalComponent: sendModalComponent
|
||||
@ -243,14 +253,13 @@ QtObject {
|
||||
SimpleSendModal {
|
||||
id: simpleSendModal
|
||||
|
||||
/** TODO: use the newly defined WalletAccountsSelectorAdaptor
|
||||
in https://github.com/status-im/status-desktop/pull/16834 **/
|
||||
accountsModel: root.walletAccountsModel
|
||||
accountsModel: backendHandler.accountsSelectorAdaptor.processedWalletAccounts
|
||||
assetsModel: backendHandler.assetsSelectorViewAdaptor.outputAssetsModel
|
||||
collectiblesModel: backendHandler.collectiblesSelectionAdaptor.model
|
||||
networksModel: backendHandler.filteredFlatNetworksModel
|
||||
savedAddressesModel: root.savedAddressesModel
|
||||
recentRecipientsModel: root.recentRecipientsModel
|
||||
|
||||
currentCurrency: root.currentCurrency
|
||||
fnFormatCurrencyAmount: root.fnFormatCurrencyAmount
|
||||
fnResolveENS: root.fnResolveENS
|
||||
@ -315,6 +324,18 @@ QtObject {
|
||||
close()
|
||||
}
|
||||
|
||||
readonly property var accountsSelectorAdaptor: WalletAccountsSelectorAdaptor {
|
||||
accounts: root.walletAccountsModel
|
||||
assetsModel: root.groupedAccountAssetsModel
|
||||
tokensBySymbolModel: root.plainTokensBySymbolModel
|
||||
filteredFlatNetworksModel: backendHandler.filteredFlatNetworksModel
|
||||
|
||||
selectedTokenKey: simpleSendModal.selectedTokenKey
|
||||
selectedNetworkChainId: simpleSendModal.selectedChainId
|
||||
|
||||
fnFormatCurrencyAmountFromBigInt: root.fnFormatCurrencyAmountFromBigInt
|
||||
}
|
||||
|
||||
readonly property var assetsSelectorViewAdaptor: TokenSelectorViewAdaptor {
|
||||
// TODO: remove all store dependecies and add specific properties to the handler instead
|
||||
assetsModel: root.groupedAccountAssetsModel
|
||||
|
Loading…
x
Reference in New Issue
Block a user