feat(@desktop/wallet): Add support for Account selection in Swap Modal using already existing AccountsModalHeader.qml
fixes #14749
This commit is contained in:
parent
81d7ca32b0
commit
9d8542c95d
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
SwapModal 1.0 SwapModal.qml
|
||||
SwapFormData 1.0 SwapFormData.qml
|
||||
SwapInputParamsForm 1.0 SwapInputParamsForm.qml
|
||||
SwapModalAdaptor 1.0 SwapModalAdaptor.qml
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
Item {
|
||||
implicitWidth: 1
|
||||
implicitHeight: 16
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" : ""
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue