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:
Khushboo Mehta 2024-11-28 12:42:31 +01:00 committed by Khushboo-dev-cpp
parent 37a06fc3be
commit 0d4d1b0ba7
12 changed files with 906 additions and 202 deletions

View File

@ -7,48 +7,205 @@ import Models 1.0
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import shared.controls 1.0 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 id: root
ColumnLayout { orientation: Qt.Vertical
spacing: 16
anchors.centerIn: parent
implicitWidth: 150
QtObject {
id: d
WalletAccountsModel { readonly property var flatNetworks: NetworksModel.flatNetworks
id: accountsModel readonly property var assetsStore: WalletAssetsStore {
id: thisWalletAssetStore
walletTokensStore: TokensStore {
plainTokensBySymbolModel: TokensBySymbolModel {}
}
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
} }
Label { readonly property var currencyStore: CurrenciesStore{}
text: "Default style" readonly property var nonWatchWalletAcounts: SortFilterProxyModel {
font.bold: true sourceModel: walletAccountsModel
Layout.fillWidth: true filters: ValueFilter { roleName: "canSend"; value: true }
} }
AccountSelector {
id: accountSelector readonly property var filteredFlatNetworksModel: SortFilterProxyModel {
Layout.fillWidth: true sourceModel: d.flatNetworks
model: WalletAccountsModel {} filters: ValueFilter { roleName: "isTest"; value: true }
onCurrentAccountAddressChanged: { }
accountSelector2.selectedAddress = currentAccountAddress }
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 Item {
Layout.fillWidth: true SplitView.preferredWidth: 300
} SplitView.preferredHeight: childrenRect.height
AccountSelectorHeader {
id: accountSelector2 ColumnLayout {
model: accountSelector.model
onCurrentAccountAddressChanged: { Label { text: "Selected Token" }
accountSelector.selectedAddress = currentAccountAddress 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 // category: Components

View File

@ -1,11 +1,12 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import StatusQ 0.1 import StatusQ 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Core.Backpressure 0.1 import StatusQ.Core.Backpressure 0.1
import Models 1.0 import Models 1.0
@ -32,6 +33,10 @@ SplitView {
readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore { readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore {
assetsWithFilteredBalances: groupedAccountsAssetsModel assetsWithFilteredBalances: groupedAccountsAssetsModel
walletTokensStore: TokensStore {
plainTokensBySymbolModel: TokensBySymbolModel{}
getDisplayAssetsBelowBalanceThresholdDisplayAmount: () => 0
}
} }
readonly property var walletAccountsModel: WalletAccountsModel{} readonly property var walletAccountsModel: WalletAccountsModel{}
@ -67,6 +72,14 @@ SplitView {
simpleSend.estimatedFiatFees = "1.45 EUR" simpleSend.estimatedFiatFees = "1.45 EUR"
simpleSend.estimatedCryptoFees = "0.0007 ETH" 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 { PopupBackground {
@ -96,7 +109,7 @@ SplitView {
interactive: interactiveCheckbox.checked interactive: interactiveCheckbox.checked
accountsModel: d.walletAccountsModel accountsModel: accountsSelectorAdaptor.processedWalletAccounts
assetsModel: assetsSelectorViewAdaptor.outputAssetsModel assetsModel: assetsSelectorViewAdaptor.outputAssetsModel
collectiblesModel: collectiblesSelectionAdaptor.model collectiblesModel: collectiblesSelectionAdaptor.model
networksModel: d.filteredNetworksModel networksModel: d.filteredNetworksModel
@ -105,13 +118,7 @@ SplitView {
recentRecipientsModel: WalletTransactionsModel{} recentRecipientsModel: WalletTransactionsModel{}
currentCurrency: "USD" currentCurrency: "USD"
fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) { fnFormatCurrencyAmount: d.formatCurrencyAmount
if (isNaN(amount)) {
return "N/A"
}
var currencyAmount = d.getCurrencyAmount(amount, symbol)
return LocaleUtils.currencyAmountToLocaleString(currencyAmount, options, locale)
}
fnResolveENS: Backpressure.debounce(root, 500, function (ensName, uuid) { fnResolveENS: Backpressure.debounce(root, 500, function (ensName, uuid) {
if (!!ensName && ensName.endsWith(".eth")) { 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 { TokenSelectorViewAdaptor {
id: assetsSelectorViewAdaptor id: assetsSelectorViewAdaptor

View 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

View File

@ -171,26 +171,28 @@ Item {
function test_floating_header_default_account() { function test_floating_header_default_account() {
verify(!!controlUnderTest) verify(!!controlUnderTest)
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
/* using a for loop set different accounts as default index and /* using a for loop set different accounts as default index and
check if the correct values are displayed in the floating header*/ check if the correct values are displayed in the floating header*/
for (let i = 0; i< swapAdaptor.nonWatchAccounts.count; i++) { for (let i = 0; i< walletAccounts.count; i++) {
const nonWatchAccount = swapAdaptor.nonWatchAccounts.get(i) const accountToTest = walletAccounts.get(i)
root.swapFormData.selectedAccountAddress = nonWatchAccount.address root.swapFormData.selectedAccountAddress = accountToTest.address
// Launch popup // Launch popup
launchAndVerfyModal() launchAndVerfyModal()
const floatingHeaderBackground = findChild(controlUnderTest, "headerBackground") const floatingHeaderBackground = findChild(controlUnderTest, "headerBackground")
verify(!!floatingHeaderBackground) 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") const headerContentItemText = findChild(controlUnderTest, "textContent")
verify(!!headerContentItemText) verify(!!headerContentItemText)
compare(headerContentItemText.text, nonWatchAccount.name) compare(headerContentItemText.text, accountToTest.name)
const headerContentItemEmoji = findChild(controlUnderTest, "assetContent") const headerContentItemEmoji = findChild(controlUnderTest, "assetContent")
verify(!!headerContentItemEmoji) verify(!!headerContentItemEmoji)
compare(headerContentItemEmoji.asset.emoji, nonWatchAccount.emoji) compare(headerContentItemEmoji.asset.emoji, accountToTest.emoji)
} }
closeAndVerfyModal() closeAndVerfyModal()
} }
@ -228,6 +230,7 @@ Item {
launchAndVerfyModal() launchAndVerfyModal()
const accountsModalHeader = getAndVerifyAccountsModalHeader() const accountsModalHeader = getAndVerifyAccountsModalHeader()
launchAccountSelectionPopup(accountsModalHeader) launchAccountSelectionPopup(accountsModalHeader)
let walletAccounts = accountsModalHeader.model
const comboBoxList = findChild(controlUnderTest, "accountSelectorList") const comboBoxList = findChild(controlUnderTest, "accountSelectorList")
verify(!!comboBoxList) verify(!!comboBoxList)
@ -235,7 +238,7 @@ Item {
for(let i =0; i< comboBoxList.model.count; i++) { for(let i =0; i< comboBoxList.model.count; i++) {
let delegateUnderTest = comboBoxList.itemAtIndex(i) let delegateUnderTest = comboBoxList.itemAtIndex(i)
let accountToBeTested = swapAdaptor.nonWatchAccounts.get(i) let accountToBeTested = walletAccounts.get(i)
let elidedAddress = SQUtils.Utils.elideAndFormatWalletAddress(accountToBeTested.address) let elidedAddress = SQUtils.Utils.elideAndFormatWalletAddress(accountToBeTested.address)
compare(delegateUnderTest.title, accountToBeTested.name) compare(delegateUnderTest.title, accountToBeTested.name)
compare(delegateUnderTest.subTitle, elidedAddress) compare(delegateUnderTest.subTitle, elidedAddress)
@ -302,7 +305,6 @@ Item {
for(let i =0; i< comboBoxList.model.count; i++) { for(let i =0; i< comboBoxList.model.count; i++) {
let delegateUnderTest = comboBoxList.itemAtIndex(i) let delegateUnderTest = comboBoxList.itemAtIndex(i)
verify(!!delegateUnderTest.model.fromToken)
verify(!!delegateUnderTest.model.accountBalance) verify(!!delegateUnderTest.model.accountBalance)
compare(delegateUnderTest.inlineTagModel, 1) 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.asset.color.toString().toUpperCase(), delegateUnderTest.model.accountBalance.chainColor.toString().toUpperCase())
compare(inlineTagDelegate_0.titleText.color, balance === "0" ? Theme.palette.baseColor1 : Theme.palette.directColor1) compare(inlineTagDelegate_0.titleText.color, balance === "0" ? Theme.palette.baseColor1 : Theme.palette.directColor1)
let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(balance, delegateUnderTest.model.fromToken.decimals) let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(balance, controlUnderTest.swapAdaptor.fromToken.decimals)
compare(inlineTagDelegate_0.title, balance === "0" ? "0 %1".arg(delegateUnderTest.model.fromToken.symbol) compare(inlineTagDelegate_0.title, balance === "0" ? "0 %1".arg(controlUnderTest.swapAdaptor.fromToken.symbol)
: root.swapAdaptor.formatCurrencyAmount(bigIntBalance, delegateUnderTest.model.fromToken.symbol)) : root.swapAdaptor.currencyStore.formatCurrencyAmount(bigIntBalance, controlUnderTest.swapAdaptor.fromToken.symbol))
} }
closeAndVerfyModal() closeAndVerfyModal()
@ -327,13 +329,16 @@ Item {
// Launch popup // Launch popup
launchAndVerfyModal() launchAndVerfyModal()
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
const payPanel = findChild(controlUnderTest, "payPanel") const payPanel = findChild(controlUnderTest, "payPanel")
verify(!!payPanel) verify(!!payPanel)
const amountToSendInput = findChild(payPanel, "amountToSendInput") const amountToSendInput = findChild(payPanel, "amountToSendInput")
verify(!!amountToSendInput) verify(!!amountToSendInput)
verify(amountToSendInput.cursorVisible) verify(amountToSendInput.cursorVisible)
for(let i =0; i< swapAdaptor.nonWatchAccounts.count; i++) { for(let i =0; i< walletAccounts.count; i++) {
// launch account selection dropdown // launch account selection dropdown
const accountsModalHeader = getAndVerifyAccountsModalHeader() const accountsModalHeader = getAndVerifyAccountsModalHeader()
launchAccountSelectionPopup(accountsModalHeader) launchAccountSelectionPopup(accountsModalHeader)
@ -348,20 +353,20 @@ Item {
verify(accountsModalHeader.control.popup.closed) verify(accountsModalHeader.control.popup.closed)
// The input params form's slected Index should be updated as per this selection // 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 // The comboBox item should reflect chosen account
const floatingHeaderBackground = findChild(accountsModalHeader, "headerBackground") const floatingHeaderBackground = findChild(accountsModalHeader, "headerBackground")
verify(!!floatingHeaderBackground) 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") const headerContentItemText = findChild(accountsModalHeader, "textContent")
verify(!!headerContentItemText) verify(!!headerContentItemText)
compare(headerContentItemText.text, swapAdaptor.nonWatchAccounts.get(i).name) compare(headerContentItemText.text, walletAccounts.get(i).name)
const headerContentItemEmoji = findChild(accountsModalHeader, "assetContent") const headerContentItemEmoji = findChild(accountsModalHeader, "assetContent")
verify(!!headerContentItemEmoji) verify(!!headerContentItemEmoji)
compare(headerContentItemEmoji.asset.emoji, swapAdaptor.nonWatchAccounts.get(i).emoji) compare(headerContentItemEmoji.asset.emoji, walletAccounts.get(i).emoji)
waitForRendering(amountToSendInput) waitForRendering(amountToSendInput)
@ -477,7 +482,7 @@ Item {
verify(!!fromToken) verify(!!fromToken)
let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(accountBalance.balance, fromToken.decimals) let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(accountBalance.balance, fromToken.decimals)
compare(inlineTagDelegate_0.title, bigIntBalance === 0 ? "0 %1".arg(fromToken.symbol) 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 // close account selection dropdown
accountsModalHeader.control.popup.close() accountsModalHeader.control.popup.close()
@ -918,7 +923,11 @@ Item {
// try setting value before popup is launched and check values // try setting value before popup is launched and check values
let valueToExchange = 0.001 let valueToExchange = 0.001
let valueToExchangeString = valueToExchange.toString() 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.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
root.swapFormData.fromTokensKey = "ETH" root.swapFormData.fromTokensKey = "ETH"
root.swapFormData.fromTokenAmount = valueToExchangeString root.swapFormData.fromTokenAmount = valueToExchangeString
@ -968,11 +977,14 @@ Item {
} }
function test_modal_pay_input_wrong_value_1() { 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"] let invalidValues = ["ABC", "0.0.010201", "12PASA", "100,9.01"]
for (let i =0; i<invalidValues.length; i++) { for (let i =0; i<invalidValues.length; i++) {
let invalidValue = invalidValues[i] let invalidValue = invalidValues[i]
// try setting value before popup is launched and check values // 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.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
root.swapFormData.fromTokensKey = root.swapFormData.fromTokensKey =
root.swapFormData.fromTokenAmount = invalidValue root.swapFormData.fromTokenAmount = invalidValue
@ -1013,10 +1025,13 @@ Item {
} }
function test_modal_pay_input_wrong_value_2() { 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 // try setting value before popup is launched and check values
let valueToExchange = 100 let valueToExchange = 100
let valueToExchangeString = valueToExchange.toString() 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.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
root.swapFormData.fromTokensKey = "ETH" root.swapFormData.fromTokensKey = "ETH"
root.swapFormData.fromTokenAmount = valueToExchangeString root.swapFormData.fromTokenAmount = valueToExchangeString
@ -1103,10 +1118,13 @@ Item {
} }
function test_modal_receive_input_presetValues() { function test_modal_receive_input_presetValues() {
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
let valueToReceive = 0.001 let valueToReceive = 0.001
let valueToReceiveString = valueToReceive.toString() let valueToReceiveString = valueToReceive.toString()
// try setting value before popup is launched and check values // 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.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
root.swapFormData.toTokenKey = "STT" root.swapFormData.toTokenKey = "STT"
root.swapFormData.toTokenAmount = valueToReceiveString root.swapFormData.toTokenAmount = valueToReceiveString
@ -1164,12 +1182,15 @@ Item {
root.swapFormData.fromTokenAmount = valueToExchangeString root.swapFormData.fromTokenAmount = valueToExchangeString
root.swapFormData.toTokenKey = "STT" root.swapFormData.toTokenKey = "STT"
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
formValuesChanged.wait() formValuesChanged.wait()
// Launch popup // Launch popup
launchAndVerfyModal() launchAndVerfyModal()
// The default is the first account. Setting the second account to test switching accounts // 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) waitForItemPolished(controlUnderTest.contentItem)
@ -1215,13 +1236,17 @@ Item {
function test_modal_max_button_click_with_no_preset_pay_value() { function test_modal_max_button_click_with_no_preset_pay_value() {
// Launch popup // Launch popup
launchAndVerfyModal() launchAndVerfyModal()
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
// The default is the first account. Setting the second account to test switching accounts // 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() formValuesChanged.clear()
// try setting value before popup is launched and check values // try setting value before popup is launched and check values
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId 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.fromTokensKey = "ETH"
root.swapFormData.toTokenKey = "STT" root.swapFormData.toTokenKey = "STT"
@ -1266,6 +1291,10 @@ Item {
} }
function test_modal_pay_input_switching_accounts() { function test_modal_pay_input_switching_accounts() {
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
// test with pay value being set and not set // test with pay value being set and not set
let payValuesToTestWith = ["", "0.2"] let payValuesToTestWith = ["", "0.2"]
@ -1275,7 +1304,7 @@ Item {
// Asset chosen but no pay value set state ------------------------------------------------------------------------------- // Asset chosen but no pay value set state -------------------------------------------------------------------------------
root.swapFormData.fromTokenAmount = valueToExchangeString 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.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId
root.swapFormData.fromTokensKey = "ETH" root.swapFormData.fromTokensKey = "ETH"
@ -1292,8 +1321,8 @@ Item {
const errorTag = findChild(controlUnderTest, "errorTag") const errorTag = findChild(controlUnderTest, "errorTag")
verify(!!errorTag) verify(!!errorTag)
for (let i=0; i< root.swapAdaptor.nonWatchAccounts.count; i++) { for (let i=0; i< walletAccounts.count; i++) {
root.swapFormData.selectedAccountAddress = root.swapAdaptor.nonWatchAccounts.get(i).address root.swapFormData.selectedAccountAddress = walletAccounts.get(i).address
waitForItemPolished(controlUnderTest.contentItem) waitForItemPolished(controlUnderTest.contentItem)
@ -1382,11 +1411,14 @@ Item {
const receiveBottomItemText = findChild(receivePanel, "bottomItemText") const receiveBottomItemText = findChild(receivePanel, "bottomItemText")
verify(!!receiveBottomItemText) verify(!!receiveBottomItemText)
const accountsModalHeader = getAndVerifyAccountsModalHeader()
let walletAccounts = accountsModalHeader.model
root.swapAdaptor.reset() root.swapAdaptor.reset()
// set network and address by default same // set network and address by default same
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId 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.fromTokensKey = data.fromToken
root.swapFormData.fromTokenAmount = data.fromTokenAmount root.swapFormData.fromTokenAmount = data.fromTokenAmount
root.swapFormData.toTokenKey = data.toToken root.swapFormData.toTokenKey = data.toToken

View 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)
}
}
}
}

View File

@ -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)
}
}
}
}

View File

@ -1,2 +1,3 @@
CollectiblesSelectionAdaptor 1.0 CollectiblesSelectionAdaptor.qml CollectiblesSelectionAdaptor 1.0 CollectiblesSelectionAdaptor.qml
TokenSelectorViewAdaptor 1.0 TokenSelectorViewAdaptor.qml TokenSelectorViewAdaptor 1.0 TokenSelectorViewAdaptor.qml
WalletAccountsSelectorAdaptor 1.0 WalletAccountsSelectorAdaptor.qml

View File

@ -23,9 +23,6 @@ StatusDialog {
id: root 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: Expected model structure:
- name: name of account - name: name of account
- address: wallet address - address: wallet address

View File

@ -1,9 +1,11 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import QtQml.Models 2.15 import QtQml.Models 2.15
import SortFilterProxyModel 0.2
import utils 1.0 import utils 1.0
import StatusQ 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Backpressure 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.controls 1.0
import AppLayouts.Wallet.panels 1.0 import AppLayouts.Wallet.panels 1.0
import AppLayouts.Wallet.popups.buy 1.0 import AppLayouts.Wallet.popups.buy 1.0
import AppLayouts.Wallet.adaptors 1.0
StatusDialog { StatusDialog {
id: root id: root
@ -58,11 +61,37 @@ StatusDialog {
selectedTokenKey: root.swapInputParamsForm.fromTokensKey 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) { function addMetricsEvent(subEventName) {
Global.addCentralizedMetricIfEnabled("swap", {subEvent: subEventName}) Global.addCentralizedMetricIfEnabled("swap", {subEvent: subEventName})
} }
} }
ModelEntry {
id: selectedAccountEntry
sourceModel: d.accountsSelectorAdaptor.processedWalletAccounts
key: "address"
value: root.swapInputParamsForm.selectedAccountAddress
}
Connections { Connections {
target: root.swapInputParamsForm target: root.swapInputParamsForm
function onFormValuesChanged() { function onFormValuesChanged() {
@ -109,7 +138,7 @@ StatusDialog {
AccountSelectorHeader { AccountSelectorHeader {
id: selector id: selector
control.popup.width: 512 control.popup.width: 512
model: root.swapAdaptor.nonWatchAccounts model: d.accountsSelectorAdaptor.processedWalletAccounts
selectedAddress: root.swapInputParamsForm.selectedAccountAddress selectedAddress: root.swapInputParamsForm.selectedAccountAddress
onCurrentAccountAddressChanged: { onCurrentAccountAddressChanged: {
if (currentAccountAddress !== "" && currentAccountAddress !== root.swapInputParamsForm.selectedAccountAddress) { if (currentAccountAddress !== "" && currentAccountAddress !== root.swapInputParamsForm.selectedAccountAddress) {
@ -409,7 +438,7 @@ StatusDialog {
objectName: "signButton" objectName: "signButton"
readonly property string fromTokenSymbol: !!root.swapAdaptor.fromToken ? root.swapAdaptor.fromToken.symbol ?? "" : "" readonly property string fromTokenSymbol: !!root.swapAdaptor.fromToken ? root.swapAdaptor.fromToken.symbol ?? "" : ""
loadingWithText: root.swapAdaptor.approvalPending 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] : Constants.authenticationIconByType[root.loginType]
text: { text: {
if(root.swapAdaptor.validSwapProposalReceived) { if(root.swapAdaptor.validSwapProposalReceived) {
@ -461,7 +490,7 @@ StatusDialog {
formatBigNumber: (number, symbol, noSymbolOption) => root.swapAdaptor.currencyStore.formatBigNumber(number, symbol, noSymbolOption) 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 feesLoading: root.swapAdaptor.swapProposalLoading
fromTokenSymbol: root.swapAdaptor.fromToken.symbol fromTokenSymbol: root.swapAdaptor.fromToken.symbol
@ -470,11 +499,11 @@ StatusDialog {
"chainId", root.swapInputParamsForm.selectedNetworkChainId, "chainId", root.swapInputParamsForm.selectedNetworkChainId,
"address") "address")
accountName: root.swapAdaptor.selectedAccount.name accountName: d.selectedAccount.name
accountAddress: root.swapAdaptor.selectedAccount.address accountAddress: d.selectedAccount.address
accountEmoji: root.swapAdaptor.selectedAccount.emoji accountEmoji: d.selectedAccount.emoji
accountColor: Utils.getColorForId(root.swapAdaptor.selectedAccount.colorId) accountColor: Utils.getColorForId(d.selectedAccount.colorId)
accountBalanceFormatted: root.swapAdaptor.selectedAccount.accountBalance.formattedBalance accountBalanceFormatted: d.selectedAccount.accountBalance.formattedBalance
networkShortName: networkFilter.singleSelectionItemData.shortName networkShortName: networkFilter.singleSelectionItemData.shortName
networkName: networkFilter.singleSelectionItemData.chainName networkName: networkFilter.singleSelectionItemData.chainName
@ -513,7 +542,7 @@ StatusDialog {
formatBigNumber: (number, symbol, noSymbolOption) => root.swapAdaptor.currencyStore.formatBigNumber(number, symbol, noSymbolOption) 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 feesLoading: root.swapAdaptor.swapProposalLoading
fromTokenSymbol: root.swapAdaptor.fromToken.symbol fromTokenSymbol: root.swapAdaptor.fromToken.symbol
@ -528,10 +557,10 @@ StatusDialog {
"chainId", root.swapInputParamsForm.selectedNetworkChainId, "chainId", root.swapInputParamsForm.selectedNetworkChainId,
"address") "address")
accountName: root.swapAdaptor.selectedAccount.name accountName: d.selectedAccount.name
accountAddress: root.swapAdaptor.selectedAccount.address accountAddress: d.selectedAccount.address
accountEmoji: root.swapAdaptor.selectedAccount.emoji accountEmoji: d.selectedAccount.emoji
accountColor: Utils.getColorForId(root.swapAdaptor.selectedAccount.colorId) accountColor: Utils.getColorForId(d.selectedAccount.colorId)
networkShortName: networkFilter.singleSelectionItemData.shortName networkShortName: networkFilter.singleSelectionItemData.shortName
networkName: networkFilter.singleSelectionItemData.chainName networkName: networkFilter.singleSelectionItemData.chainName

View File

@ -33,51 +33,9 @@ QObject {
// To expose the selected from and to Token from the SwapModal // To expose the selected from and to Token from the SwapModal
readonly property var fromToken: fromTokenEntry.item readonly property var fromToken: fromTokenEntry.item
readonly property var toToken: toTokenEntry.item readonly property var toToken: toTokenEntry.item
readonly property var selectedAccount: selectedAccountEntry.item
readonly property string uuid: d.uuid 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 { readonly property SortFilterProxyModel filteredFlatNetworksModel: SortFilterProxyModel {
sourceModel: root.swapStore.flatNetworks sourceModel: root.swapStore.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled } filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
@ -94,55 +52,6 @@ QObject {
// storing txHash to verify against tx completed event // storing txHash to verify against tx completed event
property string txHash 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 // Properties to handle error states
readonly property bool isRouteEthBalanceInsufficient: root.validSwapProposalReceived && root.swapOutputData.errCode === Constants.routerErrorCodes.router.errNotEnoughNativeBalance readonly property bool isRouteEthBalanceInsufficient: root.validSwapProposalReceived && root.swapOutputData.errCode === Constants.routerErrorCodes.router.errNotEnoughNativeBalance
@ -209,13 +118,6 @@ QObject {
value: root.swapFormData.toTokenKey value: root.swapFormData.toTokenKey
} }
ModelEntry {
id: selectedAccountEntry
sourceModel: root.nonWatchAccounts
key: "address"
value: root.swapFormData.selectedAccountAddress
}
Connections { Connections {
target: root.swapStore target: root.swapStore
function onSuggestedRoutesReady(txRoutes, errCode, errDescription) { function onSuggestedRoutesReady(txRoutes, errCode, errDescription) {
@ -284,14 +186,6 @@ QObject {
d.txHash = "" 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) { function getDisabledChainIds(enabledChainId) {
let disabledChainIds = [] let disabledChainIds = []
let chainIds = ModelUtils.modelToFlatArray(root.filteredFlatNetworksModel, "chainId") let chainIds = ModelUtils.modelToFlatArray(root.filteredFlatNetworksModel, "chainId")

View File

@ -668,21 +668,22 @@ Item {
flatNetworksModel: WalletStores.RootStore.flatNetworks flatNetworksModel: WalletStores.RootStore.flatNetworks
areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled areTestNetworksEnabled: WalletStores.RootStore.areTestNetworksEnabled
groupedAccountAssetsModel: appMain.walletAssetsStore.groupedAccountAssetsModel groupedAccountAssetsModel: appMain.walletAssetsStore.groupedAccountAssetsModel
currentCurrency: appMain.currencyStore.currentCurrency plainTokensBySymbolModel: appMain.tokensStore.plainTokensBySymbolModel
showCommunityAssetsInSend: appMain.tokensStore.showCommunityAssetsInSend showCommunityAssetsInSend: appMain.tokensStore.showCommunityAssetsInSend
collectiblesBySymbolModel: WalletStores.RootStore.collectiblesStore.jointCollectiblesBySymbolModel collectiblesBySymbolModel: WalletStores.RootStore.collectiblesStore.jointCollectiblesBySymbolModel
tokenBySymbolModel: appMain.tokensStore.plainTokensBySymbolModel tokenBySymbolModel: appMain.tokensStore.plainTokensBySymbolModel
fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) { savedAddressesModel: WalletStores.RootStore.savedAddresses
return appMain.currencyStore.formatCurrencyAmount(amount, symbol) recentRecipientsModel: appMain.transactionStore.tempActivityController1Model
}
currentCurrency: appMain.currencyStore.currentCurrency
fnFormatCurrencyAmount: appMain.currencyStore.formatCurrencyAmount
fnFormatCurrencyAmountFromBigInt: appMain.currencyStore.formatCurrencyAmountFromBigInt
// TODO remove this call to mainModule under #16919 // TODO remove this call to mainModule under #16919
fnResolveENS: function(ensName, uuid) { fnResolveENS: function(ensName, uuid) {
mainModule.resolveENS(name, uuid) mainModule.resolveENS(name, uuid)
} }
savedAddressesModel: WalletStores.RootStore.savedAddresses
recentRecipientsModel: appMain.transactionStore.tempActivityController1Model
Component.onCompleted: { Component.onCompleted: {
// It's requested from many nested places, so as a workaround we use // It's requested from many nested places, so as a workaround we use
// Global to shorten the path via global signal. // Global to shorten the path via global signal.

View File

@ -41,8 +41,6 @@ QtObject {
/** For simple send modal flows, decoupling from transaction store **/ /** For simple send modal flows, decoupling from transaction store **/
/** curently selected fiat currency symbol **/
required property string currentCurrency
/** Expected model structure: /** Expected model structure:
- name: name of account - name: name of account
- address: wallet address - address: wallet address
@ -62,6 +60,13 @@ QtObject {
- balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ] - balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
**/ **/
required property var groupedAccountAssetsModel 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: /** Expected model structure:
- symbol [string] - unique identifier of a collectible - symbol [string] - unique identifier of a collectible
- collectionUid [string] - unique identifier of a collection - collectionUid [string] - unique identifier of a collection
@ -96,8 +101,6 @@ QtObject {
/** whether community tokens are shown in send modal /** whether community tokens are shown in send modal
based on a global setting **/ based on a global setting **/
required property bool showCommunityAssetsInSend required property bool showCommunityAssetsInSend
/** required function to format currency amount to locale string **/
required property var fnFormatCurrencyAmount
required property var savedAddressesModel required property var savedAddressesModel
required property var recentRecipientsModel required property var recentRecipientsModel
@ -107,6 +110,13 @@ QtObject {
/** required signal to receive resolved ens name address **/ /** required signal to receive resolved ens name address **/
signal ensNameResolved(string resolvedPubKey, string resolvedAddress, string uuid) 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 = {}) { function openSend(params = {}) {
// TODO remove once simple send is feature complete // TODO remove once simple send is feature complete
let sendModalCmp = root.simpleSendEnabled ? simpleSendModalComponent: sendModalComponent let sendModalCmp = root.simpleSendEnabled ? simpleSendModalComponent: sendModalComponent
@ -243,14 +253,13 @@ QtObject {
SimpleSendModal { SimpleSendModal {
id: simpleSendModal id: simpleSendModal
/** TODO: use the newly defined WalletAccountsSelectorAdaptor accountsModel: backendHandler.accountsSelectorAdaptor.processedWalletAccounts
in https://github.com/status-im/status-desktop/pull/16834 **/
accountsModel: root.walletAccountsModel
assetsModel: backendHandler.assetsSelectorViewAdaptor.outputAssetsModel assetsModel: backendHandler.assetsSelectorViewAdaptor.outputAssetsModel
collectiblesModel: backendHandler.collectiblesSelectionAdaptor.model collectiblesModel: backendHandler.collectiblesSelectionAdaptor.model
networksModel: backendHandler.filteredFlatNetworksModel networksModel: backendHandler.filteredFlatNetworksModel
savedAddressesModel: root.savedAddressesModel savedAddressesModel: root.savedAddressesModel
recentRecipientsModel: root.recentRecipientsModel recentRecipientsModel: root.recentRecipientsModel
currentCurrency: root.currentCurrency currentCurrency: root.currentCurrency
fnFormatCurrencyAmount: root.fnFormatCurrencyAmount fnFormatCurrencyAmount: root.fnFormatCurrencyAmount
fnResolveENS: root.fnResolveENS fnResolveENS: root.fnResolveENS
@ -315,6 +324,18 @@ QtObject {
close() 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 { readonly property var assetsSelectorViewAdaptor: TokenSelectorViewAdaptor {
// TODO: remove all store dependecies and add specific properties to the handler instead // TODO: remove all store dependecies and add specific properties to the handler instead
assetsModel: root.groupedAccountAssetsModel assetsModel: root.groupedAccountAssetsModel