feat(@desktop/wallet): Add support for Account selection in Swap Modal using already existing AccountsModalHeader.qml

fixes #14749
This commit is contained in:
Khushboo Mehta 2024-05-15 23:22:13 +02:00 committed by Khushboo-dev-cpp
parent 81d7ca32b0
commit 9d8542c95d
19 changed files with 586 additions and 54 deletions

View File

@ -1,7 +1,9 @@
import QtQuick 2.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.Controls 0.1
@ -10,6 +12,7 @@ import utils 1.0
import Storybook 1.0
import Models 1.0
import shared.stores 1.0
import AppLayouts.Wallet.stores 1.0
import AppLayouts.Wallet.popups.swap 1.0
@ -22,7 +25,13 @@ SplitView {
QtObject {
id: d
readonly property var accountsModel: WalletAccountsModel {}
readonly property var tokenBySymbolModel: TokensBySymbolModel {}
readonly property var flatNetworksModel: NetworksModel.flatNetworks
readonly property var filteredNetworksModel: SortFilterProxyModel {
sourceModel: d.flatNetworksModel
filters: ValueFilter { roleName: "isTest"; value: areTestNetworksEnabledCheckbox.checked }
}
}
PopupBackground {
@ -45,28 +54,45 @@ SplitView {
SwapModal {
id: swapModal
visible: true
formData: SwapFormData {
swapInputParamsForm: SwapInputParamsForm {
selectedAccountIndex: accountComboBox.currentIndex
selectedNetworkChainId: {
if (NetworksModel.flatNetworks.count > 0) {
return ModelUtils.get(NetworksModel.flatNetworks, networksComboBox.currentIndex).chainId
if (networksComboBox.model.count > 0 && networksComboBox.currentIndex >= 0) {
return ModelUtils.get(networksComboBox.model, networksComboBox.currentIndex, "chainId")
}
return -1
}
fromTokensKey: {
if (d.tokenBySymbolModel.count > 0) {
return ModelUtils.get(d.tokenBySymbolModel, fromTokenComboBox.currentIndex).key
return ModelUtils.get(d.tokenBySymbolModel, fromTokenComboBox.currentIndex, "key")
}
return ""
}
fromTokenAmount: swapInput.text
toTokenKey: {
if (d.tokenBySymbolModel.count > 0) {
return ModelUtils.get(d.tokenBySymbolModel, toTokenComboBox.currentIndex).key
return ModelUtils.get(d.tokenBySymbolModel, toTokenComboBox.currentIndex, "key")
}
return ""
}
}
swapAdaptor: SwapModalAdaptor {
swapStore: SwapStore {
readonly property var accounts: d.accountsModel
readonly property var flatNetworks: d.flatNetworksModel
readonly property bool areTestNetworksEnabled: areTestNetworksEnabledCheckbox.checked
}
walletAssetsStore: WalletAssetsStore {
id: thisWalletAssetStore
walletTokensStore: TokensStore {
readonly property var plainTokensBySymbolModel: TokensBySymbolModel {}
}
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
}
currencyStore: CurrenciesStore {}
swapFormData: swapModal.swapInputParamsForm
}
}
}
@ -79,14 +105,32 @@ SplitView {
ColumnLayout {
spacing: 10
CheckBox {
id: areTestNetworksEnabledCheckbox
text: "areTestNetworksEnabled"
checked: true
onCheckedChanged: networksComboBox.currentIndex = 0
}
StatusBaseText {
text:"Selected Account"
}
ComboBox {
id: accountComboBox
textRole: "name"
model: WalletSendAccountsModel {}
model: SortFilterProxyModel {
sourceModel: d.accountsModel
filters: ValueFilter {
roleName: "walletType"
value: Constants.watchWalletType
inverted: true
}
sorters: RoleSorter { roleName: "position"; sortOrder: Qt.AscendingOrder }
}
currentIndex: 0
onCurrentIndexChanged: {
swapModal.swapInputParamsForm.selectedAccountIndex = currentIndex
}
}
StatusBaseText {
@ -95,8 +139,9 @@ SplitView {
ComboBox {
id: networksComboBox
textRole: "chainName"
model: NetworksModel.flatNetworks
model: d.filteredNetworksModel
currentIndex: 0
onCountChanged: currentIndex = 0
}
StatusBaseText {

View File

@ -0,0 +1,283 @@
import QtQuick 2.15
import QtTest 1.15
import StatusQ 0.1 // See #10218
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Core.Theme 0.1
import QtQuick.Controls 2.15
import Models 1.0
import Storybook 1.0
import utils 1.0
import shared.stores 1.0
import AppLayouts.Wallet.popups.swap 1.0
import AppLayouts.Wallet.stores 1.0
import AppLayouts.Wallet 1.0
Item {
id: root
width: 600
height: 400
readonly property var swapStore: SwapStore {
readonly property var accounts: WalletAccountsModel {}
readonly property var flatNetworks: NetworksModel.flatNetworks
readonly property bool areTestNetworksEnabled: true
}
readonly property var swapAdaptor: SwapModalAdaptor {
currencyStore: CurrenciesStore {}
walletAssetsStore: WalletAssetsStore {
id: thisWalletAssetStore
walletTokensStore: TokensStore {
readonly property var plainTokensBySymbolModel: TokensBySymbolModel {}
}
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
}
swapStore: root.swapStore
swapFormData: root.swapFormData
}
readonly property var swapFormData: SwapInputParamsForm {}
Component {
id: componentUnderTest
SwapModal {
swapInputParamsForm: root.swapFormData
swapAdaptor: root.swapAdaptor
}
}
TestCase {
name: "SwapModal"
when: windowShown
property SwapModal controlUnderTest: null
// helper functions -------------------------------------------------------------
function launchAndVerfyModal() {
verify(!!controlUnderTest)
controlUnderTest.open()
verify(!!controlUnderTest.opened)
}
function closeAndVerfyModal() {
verify(!!controlUnderTest)
controlUnderTest.close()
verify(!controlUnderTest.opened)
}
function getAndVerifyAccountsModalHeader() {
const accountsModalHeader = findChild(controlUnderTest, "accountsModalHeader")
verify(!!accountsModalHeader)
return accountsModalHeader
}
function launchAccountSelectionPopup(accountsModalHeader) {
// Launch account selection popup
verify(!accountsModalHeader.control.popup.opened)
mouseClick(accountsModalHeader, Qt.LeftButton)
waitForRendering(accountsModalHeader)
verify(!!accountsModalHeader.control.popup.opened)
return accountsModalHeader
}
// end helper functions -------------------------------------------------------------
function init() {
controlUnderTest = createTemporaryObject(componentUnderTest, root)
}
function test_floating_header_default_account() {
verify(!!controlUnderTest)
/* 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++) {
root.swapFormData.selectedAccountIndex = i
// Launch popup
launchAndVerfyModal()
const floatingHeaderBackground = findChild(controlUnderTest, "headerBackground")
verify(!!floatingHeaderBackground)
compare(floatingHeaderBackground.color.toString().toUpperCase(), Utils.getColorForId(swapAdaptor.nonWatchAccounts.get(i).colorId).toString().toUpperCase())
const headerContentItemText = findChild(controlUnderTest, "headerContentItemText")
verify(!!headerContentItemText)
compare(headerContentItemText.text, swapAdaptor.nonWatchAccounts.get(i).name)
const headerContentItemEmoji = findChild(controlUnderTest, "headerContentItemEmoji")
verify(!!headerContentItemEmoji)
compare(headerContentItemEmoji.emojiId, SQUtils.Emoji.iconId(swapAdaptor.nonWatchAccounts.get(i).emoji))
}
closeAndVerfyModal()
}
function test_floating_header_doesnt_contain_watch_accounts() {
// main input list from store should contian watch accounts
let hasWatchAccount = false
for(let i =0; i< swapStore.accounts.count; i++) {
if(swapStore.accounts.get(i).walletType === Constants.watchWalletType) {
hasWatchAccount = true
break
}
}
verify(!!hasWatchAccount)
// launch modal and get the account selection header
launchAndVerfyModal()
const accountsModalHeader = getAndVerifyAccountsModalHeader()
// header model should not contain watch accounts
let floatingHeaderHasWatchAccount = false
for(let i =0; i< accountsModalHeader.model.count; i++) {
if(accountsModalHeader.model.get(i).walletType === Constants.watchWalletType) {
floatingHeaderHasWatchAccount = true
break
}
}
verify(!floatingHeaderHasWatchAccount)
closeAndVerfyModal()
}
function test_floating_header_list_items() {
// Launch popup and account selection modal
launchAndVerfyModal()
const accountsModalHeader = getAndVerifyAccountsModalHeader()
launchAccountSelectionPopup(accountsModalHeader)
const comboBoxList = findChild(controlUnderTest, "accountSelectorList")
verify(!!comboBoxList)
for(let i =0; i< comboBoxList.model.count; i++) {
let delegateUnderTest = comboBoxList.itemAtIndex(i)
// check if the items are organized as per the position role
if(!!delegateUnderTest && !!comboBoxList.itemAtIndex(i+1)) {
verify(comboBoxList.itemAtIndex(i+1).modelData.position > delegateUnderTest.modelData.position)
}
compare(delegateUnderTest.title, swapAdaptor.nonWatchAccounts.get(i).name)
compare(delegateUnderTest.subTitle, SQUtils.Utils.elideText(swapAdaptor.nonWatchAccounts.get(i).address, 6, 4))
compare(delegateUnderTest.asset.color.toString().toUpperCase(), swapAdaptor.nonWatchAccounts.get(i).color.toString().toUpperCase())
compare(delegateUnderTest.asset.emoji, swapAdaptor.nonWatchAccounts.get(i).emoji)
const walletAccountCurrencyBalance = findChild(delegateUnderTest, "walletAccountCurrencyBalance")
verify(!!walletAccountCurrencyBalance)
verify(walletAccountCurrencyBalance.text, LocaleUtils.currencyAmountToLocaleString(swapAdaptor.nonWatchAccounts.get(i).currencyBalance))
// check if selected item in combo box is highlighted with the right color
if(comboBoxList.currentIndex === i) {
verify(delegateUnderTest.color, Theme.palette.statusListItem.highlightColor)
}
else {
verify(delegateUnderTest.color, Theme.palette.transparent)
}
// TODO: always null not sure why
// const walletAccountTypeIcon = findChild(delegateUnderTest, "walletAccountTypeIcon")
// verify(!!walletAccountTypeIcon)
// compare(walletAccountTypeIcon.icon, swapAdaptor.nonWatchAccounts.get(i).walletType === Constants.watchWalletType ? "show" : delegateUnderTest.modelData.migratedToKeycard ? "keycard": "")
// Hover over the item and check hovered state
mouseMove(delegateUnderTest, delegateUnderTest.width/2, delegateUnderTest.height/2)
verify(delegateUnderTest.sensor.containsMouse)
compare(delegateUnderTest.subTitle, WalletUtils.colorizedChainPrefix(root.swapAdaptor.getNetworkShortNames(swapAdaptor.nonWatchAccounts.get(i).preferredSharingChainIds)))
verify(delegateUnderTest.color, Theme.palette.baseColor2)
}
controlUnderTest.close()
}
function test_floating_header_after_setting_fromAsset() {
// Launch popup
launchAndVerfyModal()
// launch account selection dropdown
const accountsModalHeader = getAndVerifyAccountsModalHeader()
launchAccountSelectionPopup(accountsModalHeader)
const comboBoxList = findChild(accountsModalHeader, "accountSelectorList")
verify(!!comboBoxList)
// before setting network chainId and fromTokensKey the header should not have balances
for(let i =0; i< comboBoxList.model.count; i++) {
let delegateUnderTest = comboBoxList.itemAtIndex(i)
verify(!delegateUnderTest.modelData.fromToken)
verify(!delegateUnderTest.modelData.accountBalance)
}
// close account selection dropdown
accountsModalHeader.control.popup.close()
// set network chainId and fromTokensKey and verify balances in account selection dropdown
root.swapFormData.selectedNetworkChainId = root.swapAdaptor.__filteredFlatNetworksModel.get(0).chainId
root.swapFormData.fromTokensKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(0).key
compare(controlUnderTest.swapInputParamsForm.selectedNetworkChainId, root.swapFormData.selectedNetworkChainId)
compare(controlUnderTest.swapInputParamsForm.fromTokensKey, root.swapFormData.fromTokensKey)
// launch account selection dropdown
launchAccountSelectionPopup(accountsModalHeader)
verify(!!comboBoxList)
for(let i =0; i< comboBoxList.model.count; i++) {
let delegateUnderTest = comboBoxList.itemAtIndex(i)
verify(!!delegateUnderTest.modelData.fromToken)
verify(!!delegateUnderTest.modelData.accountBalance)
compare(delegateUnderTest.inlineTagModel, 1)
const inlineTagDelegate_0 = findChild(delegateUnderTest, "inlineTagDelegate_0")
verify(!!inlineTagDelegate_0)
compare(inlineTagDelegate_0.asset.name, Style.svg("tiny/%1".arg(delegateUnderTest.modelData.accountBalance.iconUrl)))
compare(inlineTagDelegate_0.asset.color.toString().toUpperCase(), delegateUnderTest.modelData.accountBalance.chainColor.toString().toUpperCase())
compare(inlineTagDelegate_0.titleText.color, delegateUnderTest.modelData.accountBalance.balance === "0" ? Theme.palette.baseColor1 : Theme.palette.directColor1)
let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(delegateUnderTest.modelData.accountBalance.balance, delegateUnderTest.modelData.fromToken.decimals)
compare(inlineTagDelegate_0.title, root.swapAdaptor.formatCurrencyAmount(bigIntBalance, delegateUnderTest.modelData.fromToken.symbol))
}
closeAndVerfyModal()
}
function test_floating_header_selection() {
// Launch popup
launchAndVerfyModal()
for(let i =0; i< swapAdaptor.nonWatchAccounts.count; i++) {
// launch account selection dropdown
const accountsModalHeader = getAndVerifyAccountsModalHeader()
launchAccountSelectionPopup(accountsModalHeader)
const comboBoxList = findChild(accountsModalHeader, "accountSelectorList")
verify(!!comboBoxList)
let delegateUnderTest = comboBoxList.itemAtIndex(i)
mouseClick(delegateUnderTest, Qt.LeftButton)
waitForRendering(delegateUnderTest)
verify(accountsModalHeader.control.popup.closed)
// The input params form's slected Index should be updated as per this selection
compare(root.swapFormData.selectedAccountIndex, i)
// 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())
const headerContentItemText = findChild(accountsModalHeader, "headerContentItemText")
verify(!!headerContentItemText)
compare(headerContentItemText.text, swapAdaptor.nonWatchAccounts.get(i).name)
const headerContentItemEmoji = findChild(accountsModalHeader, "headerContentItemEmoji")
verify(!!headerContentItemEmoji)
compare(headerContentItemEmoji.emojiId, SQUtils.Emoji.iconId(swapAdaptor.nonWatchAccounts.get(i).emoji))
}
closeAndVerfyModal()
}
}
}

View File

@ -40,7 +40,13 @@ ListModel {
symbol: "ZRX"
}
}
]
],
preferredSharingChainIds: "5:420:421613",
currencyBalance: ({amount: 1.25,
symbol: "USD",
displayDecimals: 4,
stripTrailingZeroes: false}),
migratedToKeycard: true
},
{
name: "Hot wallet (generated)",
@ -60,7 +66,13 @@ ListModel {
symbol: "DBF"
}
}
]
],
preferredSharingChainIds: "5:420:421613",
currencyBalance: ({amount: 10,
symbol: "USD",
displayDecimals: 4,
stripTrailingZeroes: false}),
migratedToKeycard: false
},
{
name: "Family (seed)",
@ -89,7 +101,13 @@ ListModel {
symbol: "DAI"
}
}
]
],
preferredSharingChainIds: "5:420:421613",
currencyBalance: ({amount: 110.05,
symbol: "USD",
displayDecimals: 4,
stripTrailingZeroes: false}),
migratedToKeycard: false
},
{
name: "Tag Heuer (watch)",
@ -100,7 +118,13 @@ ListModel {
walletType: Constants.watchWalletType,
position: 2,
assets: [
]
],
preferredSharingChainIds: "5:420:421613",
currencyBalance: ({amount: 3,
symbol: "USD",
displayDecimals: 4,
stripTrailingZeroes: false}),
migratedToKeycard: false
},
{
name: "Fab (key)",
@ -120,7 +144,13 @@ ListModel {
symbol: "SOX"
}
}
]
],
preferredSharingChainIds: "5:420:421613",
currencyBalance: ({amount: 999,
symbol: "USD",
displayDecimals: 4,
stripTrailingZeroes: false}),
migratedToKeycard: false
}
]

View File

@ -0,0 +1,5 @@
import QtQuick 2.15
QtObject {
id: root
}

View File

@ -2,3 +2,4 @@ CollectiblesStore 1.0 CollectiblesStore.qml
WalletAssetsStore 1.0 WalletAssetsStore.qml
TokensStore 1.0 TokensStore.qml
ActivityFiltersStore 1.0 ActivityFiltersStore.qml
SwapStore 1.0 SwapStore.qml

View File

@ -135,12 +135,12 @@ Item {
RootStore.backButtonName = ""
}
property SwapFormData swapFormData: SwapFormData {
selectedAccountIndex: RootStore.showAllAccounts ? 0 : leftTab.currentAccountIndex
property SwapInputParamsForm swapFormData: SwapInputParamsForm {
selectedAccountIndex: d.selectedAccountIndex
selectedNetworkChainId: {
// Without this when we switch testnet mode, the correct network is not evaluated
RootStore.areTestNetworksEnabled
return StatusQUtils.ModelUtils.get(RootStore.filteredFlatModel, 0).chainId
return StatusQUtils.ModelUtils.get(RootStore.filteredFlatModel, 0, "chainId")
}
}
@ -167,6 +167,8 @@ Item {
rightPanelStackView.currentItem.resetView()
}
}
readonly property int selectedAccountIndex: RootStore.showAllAccounts ? 0 : leftTab.currentAccountIndex
}
SignPhraseModal {
@ -214,6 +216,7 @@ Item {
hasFloatingButtons: true
})
onLaunchSwapModal: {
d.swapFormData.selectedAccountIndex = d.selectedAccountIndex
d.swapFormData.fromTokensKey = tokensKey
Global.openSwapModalRequested(d.swapFormData)
}
@ -330,6 +333,7 @@ Item {
}
onLaunchSwapModal: {
d.swapFormData.fromTokensKey = ""
d.swapFormData.selectedAccountIndex = d.selectedAccountIndex
if(!!walletStore.currentViewedHoldingTokensKey && walletStore.currentViewedHoldingType === Constants.TokenType.ERC20) {
d.swapFormData.fromTokensKey = walletStore.currentViewedHoldingTokensKey
}

View File

@ -5,14 +5,21 @@ import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Popups.Dialog 0.1
import shared.popups.send.controls 1.0
StatusDialog {
id: root
title: qsTr("Swap")
// This should be the only property which should be used when being launched from elsewhere
property SwapFormData formData: SwapFormData {}
/* This should be the only property which should be used to input
parameters to the modal when being launched from elsewhere */
required property SwapInputParamsForm swapInputParamsForm
required property SwapModalAdaptor swapAdaptor
objectName: "swapModal"
title: qsTr("Swap")
bottomPadding: 16
padding: 0
@ -23,32 +30,44 @@ StatusDialog {
color: Theme.palette.baseColor3
}
header: AccountsModalHeader {
anchors.top: parent.top
anchors.topMargin: -height - 18
control.popup.width: 512
model: root.swapAdaptor.nonWatchAccounts
getNetworkShortNames: root.swapAdaptor.getNetworkShortNames
formatCurrencyAmount: root.swapAdaptor.formatCurrencyAmount
/* TODO: once the Account Header is reworked we simply should be
able to use an index and not this logic of selectedAccount being set */
selectedAccount: root.swapAdaptor.getSelectedAccount(root.swapInputParamsForm.selectedAccountIndex)
onSelectedIndexChanged: {
root.swapInputParamsForm.selectedAccountIndex = selectedIndex
}
}
// This is a temporary placeholder while each of the components are being added.
contentItem: Column {
spacing: 5
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "This area is a temporary placeholder"
text: qsTr("This area is a temporary placeholder")
font.bold: true
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "Selected account index: %1".arg(formData.selectedAccountIndex)
text: qsTr("Selected network: %1").arg(swapInputParamsForm.selectedNetworkChainId)
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "Selected network: %1".arg(formData.selectedNetworkChainId)
text: qsTr("Selected from token: %1").arg(swapInputParamsForm.fromTokensKey)
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "Selected from token: %1".arg(formData.fromTokensKey)
text: qsTr("from token amount: %1").arg(swapInputParamsForm.fromTokenAmount)
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "from token amount: %1".arg(formData.fromTokenAmount)
}
StatusBaseText {
Layout.alignment: Qt.AlignHCenter
text: "Selected to token: %1".arg(formData.toTokenKey)
text: qsTr("Selected to token: %1").arg(swapInputParamsForm.toTokenKey)
}
}
}

View File

@ -0,0 +1,98 @@
import QtQml 2.15
import SortFilterProxyModel 0.2
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import utils 1.0
import shared.stores 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStore
QObject {
id: root
required property CurrenciesStore currencyStore
required property WalletStore.WalletAssetsStore walletAssetsStore
required property WalletStore.SwapStore swapStore
required property SwapInputParamsForm swapFormData
readonly property var nonWatchAccounts: SortFilterProxyModel {
sourceModel: root.swapStore.accounts
filters: ValueFilter {
roleName: "walletType"
value: Constants.watchWalletType
inverted: true
}
sorters: RoleSorter { roleName: "position"; sortOrder: Qt.AscendingOrder }
proxyRoles: [
FastExpressionRole {
name: "accountBalance"
expression: __processAccountBalance(model.address)
expectedRoles: ["address"]
},
FastExpressionRole {
name: "fromToken"
expression: root.__selectedFromToken
}
]
}
function getNetworkShortNames(chainIds) {
var networkString = ""
let chainIdsArray = chainIds.split(":")
for (let i = 0; i< chainIdsArray.length; i++) {
let nwShortName = ModelUtils.getByKey(root.__filteredFlatNetworksModel, "chainId", Number(chainIdsArray[i]), "shortName")
if(!!nwShortName) {
networkString = networkString + nwShortName + ':'
}
}
return networkString
}
function formatCurrencyAmount(balance, symbol) {
return root.currencyStore.formatCurrencyAmount(balance, symbol)
}
// TODO: remove once the AccountsModalHeader is reworked!!
function getSelectedAccount(index) {
if (root.nonWatchAccounts.count > 0 && index >= 0) {
return ModelUtils.get(nonWatchAccounts, index)
}
return null
}
// Internal properties and functions -----------------------------------------------------------------------------------------------------------------------------
readonly property SortFilterProxyModel __filteredFlatNetworksModel: SortFilterProxyModel {
sourceModel: root.swapStore.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
}
/* TODO: the below logic is only needed until https://github.com/status-im/status-desktop/issues/14550
is implemented then we should use that helper to connect the balances model with a wallet account */
readonly property var __selectedFromToken: ModelUtils.getByKey(root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.fromTokensKey)
readonly property var __balancesModelForSelectedFromToken: ModelUtils.getByKey(root.walletAssetsStore.baseGroupedAccountAssetModel, "tokensKey", root.swapFormData.fromTokensKey, "balances")
readonly property LeftJoinModel __networkJointBalancesModelForSelectedFromToken: LeftJoinModel {
leftModel: root.__balancesModelForSelectedFromToken
rightModel: root.__filteredFlatNetworksModel
joinRole: "chainId"
}
readonly property SortFilterProxyModel __filteredBalancesModelForSelectedFromToken: SortFilterProxyModel {
sourceModel: __networkJointBalancesModelForSelectedFromToken
filters: ValueFilter { roleName: "chainId"; value: root.swapFormData.selectedNetworkChainId}
}
function __processAccountBalance(address) {
let network = ModelUtils.getByKey(root.__filteredFlatNetworksModel, "chainId", root.swapFormData.selectedNetworkChainId)
if(!!network) {
let accountBalances = ModelUtils.getByKey(root.__filteredBalancesModelForSelectedFromToken, "account", address)
if(accountBalances === null) {
return {
balance: "0",
iconUrl: network.iconUrl,
chainColor: network.chainColor}
}
return accountBalances
}
return null
}
}

View File

@ -1,2 +1,3 @@
SwapModal 1.0 SwapModal.qml
SwapFormData 1.0 SwapFormData.qml
SwapInputParamsForm 1.0 SwapInputParamsForm.qml
SwapModalAdaptor 1.0 SwapModalAdaptor.qml

View File

@ -0,0 +1,11 @@
import QtQuick 2.15
QtObject {
id: root
/* TODO: all of these should come from their respective stores once the stores are reworked and
streamlined. This store should contain only swap specific properties/methods if any */
readonly property var accounts: walletSectionAccounts.accounts
readonly property var flatNetworks: networksModule.flatNetworks
readonly property bool areTestNetworksEnabled: networksModule.areTestNetworksEnabled
}

View File

@ -15,6 +15,9 @@ QtObject {
property TokensStore walletTokensStore
/* this property represents the grouped_account_assets_model from backend*/
readonly property var baseGroupedAccountAssetModel: walletSectionAssets.groupedAccountAssetsModel
readonly property var assetsController: ManageTokensController {
sourceModel: groupedAccountAssetsModel
settingsKey: "WalletAssets"
@ -92,7 +95,7 @@ QtObject {
/* This model joins the "Tokens by symbol model combined with Community details"
and "Grouped Account Assets Model" by tokenskey */
property LeftJoinModel groupedAccountAssetsModel: LeftJoinModel {
leftModel: walletSectionAssets.groupedAccountAssetsModel
leftModel: root.baseGroupedAccountAssetModel
rightModel: _jointTokensBySymbolModel
joinRole: "tokensKey"
}

View File

@ -3,3 +3,4 @@ ActivityFiltersStore 1.0 ActivityFiltersStore.qml
CollectiblesStore 1.0 CollectiblesStore.qml
TokensStore 1.0 TokensStore.qml
WalletAssetsStore 1.0 WalletAssetsStore.qml
SwapStore 1.0 SwapStore.qml

View File

@ -387,7 +387,7 @@ QtObject {
}
function openSwapModal(parameters) {
openPopup(swapModal, {formData: parameters})
openPopup(swapModal, {swapInputParamsForm: parameters})
}
readonly property list<Component> _components: [
@ -1240,6 +1240,12 @@ QtObject {
Component {
id: swapModal
SwapModal {
swapAdaptor: SwapModalAdaptor {
swapStore: WalletStore.SwapStore {}
walletAssetsStore: root.walletAssetsStore
currencyStore: root.currencyStore
swapFormData: swapInputParamsForm
}
onClosed: destroy()
}
}

View File

@ -0,0 +1,6 @@
import QtQuick 2.15
Item {
implicitWidth: 1
implicitHeight: 16
}

View File

@ -52,3 +52,4 @@ MockedKeycardReaderStateSelector 1.0 MockedKeycardReaderStateSelector.qml
MockedKeycardStateSelector 1.0 MockedKeycardStateSelector.qml
AssetsSectionDelegate 1.0 AssetsSectionDelegate.qml
ExpandableTag 1.0 ExpandableTag.qml
Padding 1.0 Padding.qml

View File

@ -8,15 +8,19 @@ import StatusQ.Core.Utils 0.1 as StatusQUtils
import utils 1.0
import "../controls"
import shared.controls 1.0
StatusComboBox {
id: root
property var selectedAccount
property var getNetworkShortNames: function(chainIds){}
property var formatCurrencyAmount: function(balance, symbol){}
property int selectedIndex: -1
objectName: "accountsModalHeader"
popupContentItemObjectName: "accountSelectorList"
control.padding: 0
control.spacing: 0
control.leftPadding: 8
@ -27,6 +31,8 @@ StatusComboBox {
control.indicator: null
control.background: Rectangle {
objectName: "headerBackground"
width: contentItem.childrenRect.width + control.leftPadding + control.rightPadding
height: 32
radius: 8
@ -43,21 +49,19 @@ StatusComboBox {
anchors.verticalCenter: parent.verticalCenter
width: childrenRect.width
spacing: 8
component Padding: Item {
width: 12
height: 16
}
Padding {}
StatusEmoji {
objectName: "headerContentItemEmoji"
anchors.verticalCenter: parent.verticalCenter
width: 16
height: 16
emojiId: StatusQUtils.Emoji.iconId(selectedAccount.emoji ?? "", StatusQUtils.Emoji.size.verySmall) || ""
emojiId: StatusQUtils.Emoji.iconId(!!selectedAccount && !!selectedAccount.emoji ? selectedAccount.emoji : "", StatusQUtils.Emoji.size.verySmall) || ""
visible: !!emojiId
}
StatusBaseText {
objectName: "headerContentItemText"
anchors.verticalCenter: parent.verticalCenter
text: selectedAccount.name ?? ""
text: !!selectedAccount && !!selectedAccount.name ? selectedAccount.name : ""
font.pixelSize: 15
color: Theme.palette.indirectColor1
}
@ -76,15 +80,16 @@ StatusComboBox {
width: ListView.view.width
modelData: model
getNetworkShortNames: root.getNetworkShortNames
formatCurrencyAmount: root.formatCurrencyAmount
color: sensor.containsMouse || highlighted ?
Theme.palette.baseColor2 :
selectedAccount.name === model.name ? Theme.palette.statusListItem.highlightColor : "transparent"
!!selectedAccount && selectedAccount.name === model.name ? Theme.palette.statusListItem.highlightColor : "transparent"
onClicked: {
selectedIndex = index
control.popup.close()
}
Component.onCompleted:{
if(selectedAccount.address === model.address)
if(!!selectedAccount && selectedAccount.address === model.address)
selectedIndex = index
}
}

View File

@ -1,5 +1,6 @@
import QtQuick 2.15
import StatusQ 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
@ -16,6 +17,7 @@ StatusListItem {
property var modelData
property var getNetworkShortNames: function(chainIds){}
property bool clearVisible: false
property var formatCurrencyAmount: function(balances, symbols){}
signal cleared()
objectName: !!modelData ? modelData.name: ""
@ -45,25 +47,19 @@ StatusListItem {
Column {
anchors.verticalCenter: parent.verticalCenter
StatusTextWithLoadingState {
objectName: "walletAccountCurrencyBalance"
anchors.right: parent.right
font.pixelSize: 15
text: LocaleUtils.currencyAmountToLocaleString(!!modelData ? modelData.currencyBalance: "")
}
Row {
StatusIcon {
objectName: "walletAccountTypeIcon"
anchors.right: parent.right
spacing: 6
StatusIcon {
width: !!icon ? 15: 0
height: !!icon ? 15 : 0
color: Theme.palette.directColor1
icon: !!modelData && modelData.walletType === Constants.watchWalletType ? "show" : ""
}
StatusIcon {
width: !!icon ? 15: 0
height: !!icon ? 15 : 0
color: Theme.palette.directColor1
icon: !!modelData && modelData.migratedToKeycard ? "keycard" : ""
}
width: !!icon ? 15: 0
height: !!icon ? 15 : 0
color: Theme.palette.directColor1
icon: !!modelData ? modelData.walletType === Constants.watchWalletType ? "show" :
modelData.migratedToKeycard ? "keycard" : "" : ""
}
},
ClearButton {
@ -74,4 +70,21 @@ StatusListItem {
onClicked: root.cleared()
}
]
inlineTagModel: !!root.modelData.fromToken && !!root.modelData.accountBalance ? 1 : 0
inlineTagDelegate: StatusListItemTag {
objectName: "inlineTagDelegate_" + index
readonly property double balance: StatusQUtils.AmountsArithmetic.toNumber(root.modelData.accountBalance.balance, root.modelData.fromToken.decimals)
background: null
height: 16
asset.height: 16
asset.width: 16
title: root.formatCurrencyAmount(balance, root.modelData.fromToken.symbol)
titleText.font.pixelSize: 12
titleText.color: balance === 0 ? Theme.palette.baseColor1 : Theme.palette.directColor1
asset.isImage: true
asset.name: Style.svg("tiny/%1".arg(root.modelData.accountBalance.iconUrl))
asset.color: root.modelData.accountBalance.chainColor
closeButtonVisible: false
}
}

View File

@ -10,7 +10,7 @@ import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import "../controls"
import shared.popups.send.controls 1.0
Item {
id: root