feat(@desktop/wallet): Buy Mercuryo flow - Improvements

fixes #16041
This commit is contained in:
Khushboo Mehta 2024-08-13 14:03:35 +02:00 committed by Khushboo-dev-cpp
parent 2c2f87f654
commit b8f41e35c4
8 changed files with 499 additions and 308 deletions

View File

@ -5,10 +5,12 @@ import QtQuick.Layouts 1.15
import Storybook 1.0 import Storybook 1.0
import Models 1.0 import Models 1.0
import StatusQ 0.1
import StatusQ.Core.Backpressure 0.1 import StatusQ.Core.Backpressure 0.1
import AppLayouts.Wallet.popups.buy 1.0 import AppLayouts.Wallet.popups.buy 1.0
import AppLayouts.Wallet.stores 1.0 import AppLayouts.Wallet.stores 1.0
import AppLayouts.Wallet.adaptors 1.0
import shared.stores 1.0 import shared.stores 1.0
@ -47,6 +49,22 @@ SplitView {
d.debounceFetchProviderUrl() d.debounceFetchProviderUrl()
} }
} }
readonly property var currencyStore: CurrenciesStore {}
readonly property var assetsStore: WalletAssetsStore {
id: thisWalletAssetStore
walletTokensStore: TokensStore {
plainTokensBySymbolModel: TokensBySymbolModel {}
}
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
}
readonly property BuyCryptoParamsForm buyCryptoInputParamsForm: BuyCryptoParamsForm{
selectedWalletAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
selectedNetworkChainId: 11155111
selectedTokenKey: "ETH"
}
} }
PopupBackground { PopupBackground {
@ -61,7 +79,12 @@ SplitView {
text: "Reopen" text: "Reopen"
enabled: !buySellModal.visible enabled: !buySellModal.visible
onClicked: buySellModal.open() onClicked: {
buySellModal.buyCryptoInputParamsForm.selectedWalletAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
buySellModal.buyCryptoInputParamsForm.selectedNetworkChainId = 11155111
buySellModal.buyCryptoInputParamsForm.selectedTokenKey = "ETH"
buySellModal.open()
}
} }
BuyCryptoModal { BuyCryptoModal {
@ -70,29 +93,19 @@ SplitView {
visible: true visible: true
modal: false modal: false
closePolicy: Popup.CloseOnEscape closePolicy: Popup.CloseOnEscape
buyCryptoAdaptor: BuyCryptoModalAdaptor { buyProvidersModel: d.buyCryptoStore.providersModel
buyCryptoStore: d.buyCryptoStore isBuyProvidersModelLoading: d.buyCryptoStore.areProvidersLoading
readonly property var currencyStore: CurrenciesStore {}
readonly property var assetsStore: WalletAssetsStore {
id: thisWalletAssetStore
walletTokensStore: TokensStore {
plainTokensBySymbolModel: TokensBySymbolModel {}
}
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
}
buyCryptoFormData: buySellModal.buyCryptoInputParamsForm
walletAccountsModel: WalletAccountsModel{} walletAccountsModel: WalletAccountsModel{}
networksModel: NetworksModel.flatNetworks networksModel: NetworksModel.flatNetworks
areTestNetworksEnabled: true areTestNetworksEnabled: true
groupedAccountAssetsModel: assetsStore.groupedAccountAssetsModel currentCurrency: d.currencyStore.currentCurrency
plainTokensBySymbolModel: assetsStore.walletTokensStore.plainTokensBySymbolModel plainTokensBySymbolModel: d.assetsStore.walletTokensStore.plainTokensBySymbolModel
currentCurrency: currencyStore.currentCurrency groupedAccountAssetsModel: d.assetsStore.groupedAccountAssetsModel
} buyCryptoInputParamsForm: d.buyCryptoInputParamsForm
buyCryptoInputParamsForm: BuyCryptoParamsForm{ Component.onCompleted: {
selectedWalletAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" fetchProviders.connect(d.buyCryptoStore.fetchProviders)
selectedNetworkChainId: 11155111 fetchProviderUrl.connect(d.buyCryptoStore.fetchProviderUrl)
selectedTokenKey: "ETH" d.buyCryptoStore.providerUrlReady.connect(providerUrlReady)
} }
} }
} }

View File

@ -3,6 +3,8 @@ import QtTest 1.15
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Core.Backpressure 0.1 import StatusQ.Core.Backpressure 0.1
@ -22,22 +24,44 @@ Item {
QtObject { QtObject {
id: d id: d
property string uuid
property var debounceFetchProviderUrl: Backpressure.debounce(root, 500, function() { }
d.buyCryptoStore.providerUrlReady(d.uuid, "xxxx")
}) Component {
property var debounceFetchProvidersList: Backpressure.debounce(root, 500, function() { id: componentUnderTest
d.buyCryptoStore.areProvidersLoading = false BuyCryptoModal {
}) id: buySellModal
buyProvidersModel: buyCryptoStore.providersModel
isBuyProvidersModelLoading: buyCryptoStore.areProvidersLoading
currentCurrency: currencyStore.currentCurrency
walletAccountsModel: WalletAccountsModel{}
networksModel: NetworksModel.flatNetworks
areTestNetworksEnabled: true
plainTokensBySymbolModel: assetsStore.walletTokensStore.plainTokensBySymbolModel
groupedAccountAssetsModel: assetsStore.groupedAccountAssetsModel
buyCryptoInputParamsForm: BuyCryptoParamsForm {
selectedWalletAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
selectedNetworkChainId: 11155111
selectedTokenKey: "ETH"
}
Component.onCompleted: {
fetchProviders.connect(buyCryptoStore.fetchProviders)
fetchProviderUrl.connect(buyCryptoStore.fetchProviderUrl)
buyCryptoStore.providerUrlReady.connect(buySellModal.providerUrlReady)
}
// Temporary assignments to make tests run independently
readonly property var currencyStore: CurrenciesStore {}
readonly property var buyCryptoStore: BuyCryptoStore { readonly property var buyCryptoStore: BuyCryptoStore {
readonly property var providersModel: _onRampProvidersModel readonly property var providersModel: OnRampProvidersModel{}
property bool areProvidersLoading property bool areProvidersLoading
signal providerUrlReady(string uuid ,string url) signal providerUrlReady(string uuid ,string url)
function fetchProviders() { function fetchProviders() {
console.warn("fetchProviders called >>") console.warn("fetchProviders called >>")
areProvidersLoading = true areProvidersLoading = true
d.debounceFetchProvidersList() debounceFetchProvidersList()
} }
function fetchProviderUrl(uuid, providerID, function fetchProviderUrl(uuid, providerID,
@ -46,32 +70,27 @@ Item {
console.warn("fetchProviderUrl called >> uuid: ", uuid, "providerID: ",providerID console.warn("fetchProviderUrl called >> uuid: ", uuid, "providerID: ",providerID
, "isRecurrent: ", isRecurrent, "accountAddress: ", accountAddress, , "isRecurrent: ", isRecurrent, "accountAddress: ", accountAddress,
"chainID: ", chainID, "symbol: ", symbol) "chainID: ", chainID, "symbol: ", symbol)
d.uuid = uuid buySellModal.uuid = uuid
d.debounceFetchProviderUrl() debounceFetchProviderUrl()
} }
} }
readonly property ModelEntry selectedAccountEntry: ModelEntry {
sourceModel: walletAccountsModel
key: "address"
value: buyCryptoInputParamsForm.selectedWalletAddress
} }
readonly property ModelEntry selectedProviderEntry: ModelEntry {
OnRampProvidersModel{ sourceModel: buyCryptoStore.providersModel
id: _onRampProvidersModel key: "id"
value: buyCryptoInputParamsForm.selectedProviderId
} }
readonly property var recurrentOnRampProvidersModel: SortFilterProxyModel {
SortFilterProxyModel { sourceModel: buyProvidersModel
id: recurrentOnRampProvidersModel
sourceModel: _onRampProvidersModel
filters: ValueFilter { filters: ValueFilter {
roleName: "supportsRecurrentPurchase" roleName: "supportsRecurrentPurchase"
value: true value: true
} }
} }
Component {
id: componentUnderTest
BuyCryptoModal {
id: buySellModal
buyCryptoAdaptor: BuyCryptoModalAdaptor {
buyCryptoStore: d.buyCryptoStore
readonly property var currencyStore: CurrenciesStore {}
readonly property var assetsStore: WalletAssetsStore { readonly property var assetsStore: WalletAssetsStore {
id: thisWalletAssetStore id: thisWalletAssetStore
walletTokensStore: TokensStore { walletTokensStore: TokensStore {
@ -80,19 +99,13 @@ Item {
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {} readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
} }
buyCryptoFormData: buySellModal.buyCryptoInputParamsForm property string uuid
walletAccountsModel: WalletAccountsModel{} property var debounceFetchProviderUrl: Backpressure.debounce(root, 500, function() {
networksModel: NetworksModel.flatNetworks buySellModal.buyCryptoStore.providerUrlReady(uuid, "xxxx")
areTestNetworksEnabled: true })
groupedAccountAssetsModel: assetsStore.groupedAccountAssetsModel property var debounceFetchProvidersList: Backpressure.debounce(root, 500, function() {
plainTokensBySymbolModel: assetsStore.walletTokensStore.plainTokensBySymbolModel buySellModal.buyCryptoStore.areProvidersLoading = false
currentCurrency: currencyStore.currentCurrency })
}
buyCryptoInputParamsForm: BuyCryptoParamsForm{
selectedWalletAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
selectedNetworkChainId: 11155111
selectedTokenKey: "ETH"
}
} }
} }
@ -109,11 +122,15 @@ Item {
property BuyCryptoModal controlUnderTest: null property BuyCryptoModal controlUnderTest: null
function init() { function init() {
notificationSpy.clear()
controlUnderTest = createTemporaryObject(componentUnderTest, root) controlUnderTest = createTemporaryObject(componentUnderTest, root)
} }
function launchPopup() { function launchPopup() {
verify(!!controlUnderTest) verify(!!controlUnderTest)
controlUnderTest.buyCryptoInputParamsForm.selectedWalletAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
controlUnderTest.buyCryptoInputParamsForm.selectedNetworkChainId = 11155111
controlUnderTest.buyCryptoInputParamsForm.selectedTokenKey = "ETH"
controlUnderTest.open() controlUnderTest.open()
verify(!!controlUnderTest.opened) verify(!!controlUnderTest.opened)
} }
@ -126,26 +143,152 @@ Item {
compare(delegateUnderTest.title, modelToCompareAgainst.get(i).name) compare(delegateUnderTest.title, modelToCompareAgainst.get(i).name)
compare(delegateUnderTest.subTitle, modelToCompareAgainst.get(i).description) compare(delegateUnderTest.subTitle, modelToCompareAgainst.get(i).description)
compare(delegateUnderTest.asset.name, modelToCompareAgainst.get(i).logoUrl) compare(delegateUnderTest.asset.name, modelToCompareAgainst.get(i).logoUrl)
compare(delegateUnderTest.isUrlLoading, false)
const feesText = findChild(delegateUnderTest, "feesText") const feesText = findChild(delegateUnderTest, "feesText")
verify(!!feesText) verify(!!feesText)
compare(feesText.text, modelToCompareAgainst.get(i).fees) compare(feesText.text, modelToCompareAgainst.get(i).fees)
/* TODO: fix when writing more tests for this functionality const loadingIndicator = findChild(delegateUnderTest, "loadingIndicator")
const externalLinkIcon = findChild(delegateUnderTest, "externalLinkIcon") verify(!!loadingIndicator)
verify(!!externalLinkIcon) verify(!loadingIndicator.visible)
compare(externalLinkIcon.icon, "tiny/external")
compare(externalLinkIcon.color, Theme.palette.baseColor1) */ var extraIcon = null
if (modelToCompareAgainst.get(i).urlsNeedParameters) {
extraIcon = findChild(delegateUnderTest, "chevron-down-icon")
verify(!!extraIcon)
compare(extraIcon.icon, "chevron-down")
compare(extraIcon.rotation, 270)
compare(extraIcon.color, Theme.palette.baseColor1)
} else {
extraIcon = findChild(delegateUnderTest, "tiny/external-icon")
verify(!!extraIcon)
compare(extraIcon.icon, "tiny/external")
compare(extraIcon.rotation, 0)
compare(extraIcon.color, Theme.palette.baseColor1)
}
// Hover over the item and check hovered state // Hover over the item and check hovered state
mouseMove(delegateUnderTest, delegateUnderTest.width/2, delegateUnderTest.height/2) mouseMove(delegateUnderTest, delegateUnderTest.width/2, delegateUnderTest.height/2)
verify(delegateUnderTest.sensor.containsMouse) verify(delegateUnderTest.sensor.containsMouse)
/* TODO: fix when writing more tests for this functionality compare(extraIcon.color, Theme.palette.directColor1)
compare(externalLinkIcon.color, Theme.palette.directColor1) */
verify(delegateUnderTest.color, Theme.palette.baseColor2) verify(delegateUnderTest.color, Theme.palette.baseColor2)
} }
} }
function testDelegateMouseClicksForProvidersThatNeedParams(delegateUnderTest, modelData) {
const loadingIndicator = findChild(delegateUnderTest, "loadingIndicator")
verify(!!loadingIndicator)
verify(!loadingIndicator.visible)
verify(!controlUnderTest.replaceItem)
// test mouse click
tryCompare(notificationSpy, "count", 0)
mouseClick(delegateUnderTest)
waitForRendering(controlUnderTest.replaceLoader)
verify(controlUnderTest.replaceItem)
const selectParamsPanel = findChild(controlUnderTest, "selectParamsPanel")
verify(!!selectParamsPanel)
// title should not change
verify(controlUnderTest.stackTitle, qsTr("Buy assets for %1").arg(!!controlUnderTest.selectedAccountEntry.item ? controlUnderTest.selectedAccountEntry.item.name: ""))
compare(controlUnderTest.rightButtons.length, 2)
verify(controlUnderTest.rightButtons[0].visible)
verify(controlUnderTest.rightButtons[1].enabled)
verify(controlUnderTest.rightButtons[0].text, qsTr("Buy via %1").arg(!!controlUnderTest.selectedProviderEntry.item ? controlUnderTest.selectedProviderEntry.item.name: ""))
verify(!controlUnderTest.rightButtons[1].visible)
verify(controlUnderTest.backButton.visible)
const selectParamsForBuyCryptoPanelHeader = findChild(selectParamsPanel, "selectParamsForBuyCryptoPanelHeader")
verify(!!selectParamsForBuyCryptoPanelHeader)
compare(selectParamsForBuyCryptoPanelHeader.title, qsTr("Buy via %1").arg(!!controlUnderTest.selectedProviderEntry.item ? controlUnderTest.selectedProviderEntry.item.name: ""))
compare(selectParamsForBuyCryptoPanelHeader.subTitle, qsTr("Select which network and asset"))
compare(selectParamsForBuyCryptoPanelHeader.statusListItemTitle.color, Theme.palette.directColor1)
compare(selectParamsForBuyCryptoPanelHeader.asset.name, !!controlUnderTest.selectedProviderEntry.item ? controlUnderTest.selectedProviderEntry.item .logoUrl: "")
compare(selectParamsForBuyCryptoPanelHeader.color, Theme.palette.transparent)
compare(selectParamsForBuyCryptoPanelHeader.enabled, false)
const networkFilter = findChild(selectParamsPanel, "networkFilter")
verify(!!networkFilter)
compare(networkFilter.selection, [controlUnderTest.buyCryptoInputParamsForm.selectedNetworkChainId])
const tokenSelector = findChild(selectParamsPanel, "tokenSelector")
verify(!!tokenSelector)
compare(tokenSelector.currentTokensKey, controlUnderTest.buyCryptoInputParamsForm.selectedTokenKey)
const selectedTokenItem = findChild(selectParamsPanel, "selectedTokenItem")
verify(!!selectedTokenItem)
const modelDataToTest = ModelUtils.getByKey(tokenSelector.model, "tokensKey", tokenSelector.currentTokensKey)
const tokenSelectorIcon = findChild(selectedTokenItem, "tokenSelectorIcon")
verify(!!tokenSelectorIcon)
compare(tokenSelectorIcon.image.source, modelDataToTest.iconSource)
const tokenSelectorContentItemName = findChild(selectedTokenItem, "tokenSelectorContentItemName")
verify(!!tokenSelectorContentItemName)
compare(tokenSelectorContentItemName.text, modelDataToTest.name)
const tokenSelectorContentItemSymbol = findChild(selectedTokenItem, "tokenSelectorContentItemSymbol")
verify(!!tokenSelectorContentItemSymbol)
compare(tokenSelectorContentItemSymbol.text, modelDataToTest.symbol)
//switch to a network that has no tokens and ensure its reset
controlUnderTest.buyCryptoInputParamsForm.selectedNetworkChainId = 421613
waitForRendering(selectParamsPanel)
const nothingSelectedContentItem = findChild(selectParamsPanel, "tokenSelectorContentItemText")
verify(!!nothingSelectedContentItem)
verify(!selectedTokenItem.visible)
verify(!controlUnderTest.rightButtons[0].enabled)
// switch back a network and token thats valid and check if clicking buy button works properly
controlUnderTest.buyCryptoInputParamsForm.selectedNetworkChainId = 11155111
controlUnderTest.buyCryptoInputParamsForm.selectedTokenKey = "ETH"
waitForRendering(selectParamsPanel)
verify(controlUnderTest.rightButtons[0].enabled)
mouseClick(controlUnderTest.rightButtons[0])
verify(controlUnderTest.rightButtons[0].loading)
tryCompare(notificationSpy, "count", 1)
compare(notificationSpy.signalArguments[0][0], "xxxx")
compare(notificationSpy.signalArguments[0][1], modelData.hostname)
notificationSpy.clear()
// popup should be closed
verify(!controlUnderTest.opened)
}
function testDelegateMouseClicksForProvidersThatNeedNoParams(delegateUnderTest, modelData) {
// test provider that need no parameters and we directly redirect to the site
const loadingIndicator = findChild(delegateUnderTest, "loadingIndicator")
verify(!!loadingIndicator)
verify(!loadingIndicator.visible)
const extraIcon = findChild(delegateUnderTest, "tiny/external-icon")
verify(!!extraIcon)
verify(!extraIcon.visble)
// test mouse click
tryCompare(notificationSpy, "count", 0)
mouseClick(delegateUnderTest)
verify(loadingIndicator.visible)
tryCompare(notificationSpy, "count", 1)
compare(notificationSpy.signalArguments[0][0], "xxxx")
compare(notificationSpy.signalArguments[0][1], modelData.hostname)
notificationSpy.clear()
// popup should be closed
verify(!controlUnderTest.opened)
}
function test_launchAndCloseModal() { function test_launchAndCloseModal() {
launchPopup() launchPopup()
@ -165,6 +308,8 @@ Item {
compare(controlUnderTest.rightButtons[1].text, qsTr("Done")) compare(controlUnderTest.rightButtons[1].text, qsTr("Done"))
mouseClick(controlUnderTest.rightButtons[1]) mouseClick(controlUnderTest.rightButtons[1])
verify(!controlUnderTest.backButton.visible)
// popup should be closed // popup should be closed
verify(!controlUnderTest.opened) verify(!controlUnderTest.opened)
} }
@ -173,6 +318,8 @@ Item {
// Launch modal // Launch modal
launchPopup() launchPopup()
verify(controlUnderTest.stackTitle, qsTr("Buy assets for %1").arg(!!controlUnderTest.selectedAccountEntry.item ? controlUnderTest.selectedAccountEntry.item.name: ""))
// find tab bar // find tab bar
const tabBar = findChild(controlUnderTest, "tabBar") const tabBar = findChild(controlUnderTest, "tabBar")
verify(!!tabBar) verify(!!tabBar)
@ -210,10 +357,9 @@ Item {
// find providers list // find providers list
const providersList = findChild(controlUnderTest, "providersList") const providersList = findChild(controlUnderTest, "providersList")
waitForRendering(providersList)
verify(!!providersList) verify(!!providersList)
tryCompare(controlUnderTest.buyCryptoAdaptor.buyCryptoStore, "areProvidersLoading", false) tryCompare(controlUnderTest, "isBuyProvidersModelLoading", false)
mouseClick(tabBar.itemAt(0)) mouseClick(tabBar.itemAt(0))
compare(tabBar.currentIndex, 0) compare(tabBar.currentIndex, 0)
@ -222,21 +368,42 @@ Item {
compare(providersList.count, 4) compare(providersList.count, 4)
// check if delegate contents are as expected // check if delegate contents are as expected
testDelegateItems(providersList, _onRampProvidersModel) testDelegateItems(providersList, controlUnderTest.buyProvidersModel)
let delegateUnderTest = providersList.itemAtIndex(0) controlUnderTest.close()
verify(!!delegateUnderTest) }
// test mouse click function test_modalContent_OneTime_tab_mouseClicks() {
tryCompare(notificationSpy, "count", 0)
mouseClick(delegateUnderTest)
tryCompare(notificationSpy, "count", 1)
compare(notificationSpy.signalArguments[0][0], "xxxx")
compare(notificationSpy.signalArguments[0][1], _onRampProvidersModel.get(0).hostname)
notificationSpy.clear() notificationSpy.clear()
// Launch modal
launchPopup()
// popup should be closed // find providers list
verify(!controlUnderTest.opened) const providersList = findChild(controlUnderTest, "providersList")
verify(!!providersList)
for(let i =0; i< controlUnderTest.buyProvidersModel.count; i++) {
notificationSpy.clear()
launchPopup()
verify(controlUnderTest.opened)
tryCompare(controlUnderTest, "isBuyProvidersModelLoading", false)
let delegateUnderTest = providersList.itemAtIndex(i)
verify(!!delegateUnderTest)
waitForRendering(delegateUnderTest)
// test provider that need parameters like network and token to be selected
const modelData = controlUnderTest.buyProvidersModel.get(i)
verify(!!modelData)
if (modelData.urlsNeedParameters) {
testDelegateMouseClicksForProvidersThatNeedParams(delegateUnderTest, modelData)
} else {
testDelegateMouseClicksForProvidersThatNeedNoParams(delegateUnderTest, modelData)
}
}
controlUnderTest.close()
} }
function test_modalContent_recurrent_tab() { function test_modalContent_recurrent_tab() {
@ -252,7 +419,7 @@ Item {
const providersList = findChild(controlUnderTest, "providersList") const providersList = findChild(controlUnderTest, "providersList")
verify(!!providersList) verify(!!providersList)
tryCompare(controlUnderTest.buyCryptoAdaptor.buyCryptoStore, "areProvidersLoading", false) tryCompare(controlUnderTest, "isBuyProvidersModelLoading", false)
// check data in "Recurrent" tab -------------------------------------------------------- // check data in "Recurrent" tab --------------------------------------------------------
mouseClick(tabBar.itemAt(1)) mouseClick(tabBar.itemAt(1))
@ -264,18 +431,48 @@ Item {
compare(providersList.count, 1) compare(providersList.count, 1)
// check if delegate contents are as expected // check if delegate contents are as expected
testDelegateItems(providersList, recurrentOnRampProvidersModel) testDelegateItems(providersList, controlUnderTest.recurrentOnRampProvidersModel)
controlUnderTest.close()
}
let delegateUnderTest = providersList.itemAtIndex(0) function test_modalContent_Recurrent_tab_mouseClicks() {
verify(!!delegateUnderTest)
// test mouse click
tryCompare(notificationSpy, "count", 0)
verify(controlUnderTest.opened)
mouseClick(delegateUnderTest)
tryCompare(notificationSpy, "count", 0)
notificationSpy.clear() notificationSpy.clear()
//TODO: add more test logic here for second page of selecting params // Launch modal
launchPopup()
// find tab bar
const tabBar = findChild(controlUnderTest, "tabBar")
verify(!!tabBar)
// find providers list
const providersList = findChild(controlUnderTest, "providersList")
verify(!!providersList)
mouseClick(tabBar.itemAt(1))
compare(tabBar.currentIndex, 1)
waitForRendering(providersList)
verify(!!providersList)
for(let i =0; i< controlUnderTest.recurrentOnRampProvidersModel.count; i++) {
notificationSpy.clear()
launchPopup()
verify(controlUnderTest.opened)
tryCompare(controlUnderTest, "isBuyProvidersModelLoading", false)
let delegateUnderTest = providersList.itemAtIndex(i)
verify(!!delegateUnderTest)
waitForRendering(delegateUnderTest)
// test provider that need parameters like network and token to be selected
const modelData = controlUnderTest.recurrentOnRampProvidersModel.get(i)
verify(!!modelData)
if (modelData.urlsNeedParameters) {
testDelegateMouseClicksForProvidersThatNeedParams(delegateUnderTest, modelData)
} else {
testDelegateMouseClicksForProvidersThatNeedNoParams(delegateUnderTest, modelData)
}
}
} }
} }
} }

View File

@ -35,13 +35,13 @@ StatusListItem {
loading: root.loading loading: root.loading
}, },
StatusIcon { StatusIcon {
objectName: "externalLinkIcon"
icon: root.urlsNeedParameters ? "chevron-down": "tiny/external" icon: root.urlsNeedParameters ? "chevron-down": "tiny/external"
rotation: root.urlsNeedParameters ? 270: 0 rotation: root.urlsNeedParameters ? 270: 0
color: sensor.containsMouse ? Theme.palette.directColor1: Theme.palette.baseColor1 color: sensor.containsMouse ? Theme.palette.directColor1: Theme.palette.baseColor1
visible: !root.loading && !root.isUrlLoading visible: !root.loading && !root.isUrlLoading
}, },
StatusLoadingIndicator { StatusLoadingIndicator {
objectName: "loadingIndicator"
visible: root.isUrlLoading visible: root.isUrlLoading
} }
] ]

View File

@ -16,7 +16,7 @@ ColumnLayout {
id: root id: root
// required properties // required properties
required property var adaptor required property var assetsModel
required property var selectedProvider required property var selectedProvider
required property string selectedTokenKey required property string selectedTokenKey
required property int selectedNetworkChainId required property int selectedNetworkChainId
@ -27,9 +27,24 @@ ColumnLayout {
signal networkSelected(int chainId) signal networkSelected(int chainId)
signal tokenSelected(string tokensKey) signal tokenSelected(string tokensKey)
QtObject {
id: d
function updateTokenSelector() {
Qt.callLater(()=> {
if(!!holdingSelector.model && !!root.selectedTokenKey && root.selectedNetworkChainId !== -1) {
holdingSelector.selectToken(root.selectedTokenKey)
}
})
}
}
onSelectedTokenKeyChanged: d.updateTokenSelector()
onSelectedNetworkChainIdChanged: d.updateTokenSelector()
spacing: 20 spacing: 20
StatusListItem { StatusListItem {
objectName: "selectParamsForBuyCryptoPanelHeader"
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
leftPadding: 0 leftPadding: 0
@ -81,8 +96,9 @@ ColumnLayout {
} }
TokenSelector { TokenSelector {
id: holdingSelector id: holdingSelector
objectName: "tokenSelector"
Layout.fillWidth: true Layout.fillWidth: true
model: root.adaptor.outputAssetsModel model: root.assetsModel
popup.width: parent.width popup.width: parent.width
contentItem: Loader { contentItem: Loader {
height: 40 // by design height: 40 // by design
@ -93,7 +109,6 @@ ColumnLayout {
color: Theme.palette.transparent color: Theme.palette.transparent
} }
onTokenSelected: root.tokenSelected(tokensKey) onTokenSelected: root.tokenSelected(tokensKey)
Component.onCompleted: holdingSelector.selectToken(root.selectedTokenKey)
} }
} }
@ -111,6 +126,7 @@ ColumnLayout {
Component { Component {
id: selectedTokenCmp id: selectedTokenCmp
RowLayout { RowLayout {
objectName: "selectedTokenItem"
spacing: Style.current.halfPadding spacing: Style.current.halfPadding
StatusRoundedImage { StatusRoundedImage {
objectName: "tokenSelectorIcon" objectName: "tokenSelectorIcon"
@ -119,14 +135,14 @@ ColumnLayout {
image.source: ModelUtils.getByKey(holdingSelector.model, "tokensKey", holdingSelector.currentTokensKey, "iconSource") image.source: ModelUtils.getByKey(holdingSelector.model, "tokensKey", holdingSelector.currentTokensKey, "iconSource")
} }
StatusBaseText { StatusBaseText {
objectName: "tokenSelectorContentItemText" objectName: "tokenSelectorContentItemName"
font.pixelSize: 15 font.pixelSize: 15
color: Theme.palette.directColor1 color: Theme.palette.directColor1
text: ModelUtils.getByKey(holdingSelector.model, "tokensKey", holdingSelector.currentTokensKey, "name") text: ModelUtils.getByKey(holdingSelector.model, "tokensKey", holdingSelector.currentTokensKey, "name")
} }
StatusBaseText { StatusBaseText {
Layout.fillWidth: true Layout.fillWidth: true
objectName: "tokenSelectorContentItemText" objectName: "tokenSelectorContentItemSymbol"
font.pixelSize: 15 font.pixelSize: 15
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
text: ModelUtils.getByKey(holdingSelector.model, "tokensKey", holdingSelector.currentTokensKey, "symbol") text: ModelUtils.getByKey(holdingSelector.model, "tokensKey", holdingSelector.currentTokensKey, "symbol")

View File

@ -17,78 +17,161 @@ import utils 1.0
import AppLayouts.Wallet.controls 1.0 import AppLayouts.Wallet.controls 1.0
import AppLayouts.Wallet.adaptors 1.0 import AppLayouts.Wallet.adaptors 1.0
import AppLayouts.Wallet.panels 1.0 import AppLayouts.Wallet.panels 1.0
import AppLayouts.Wallet.stores 1.0
StatusStackModal { StatusStackModal {
id: root id: root
// required data
required property var buyProvidersModel
required property var isBuyProvidersModelLoading
required property BuyCryptoParamsForm buyCryptoInputParamsForm required property BuyCryptoParamsForm buyCryptoInputParamsForm
required property BuyCryptoModalAdaptor buyCryptoAdaptor required property var plainTokensBySymbolModel
required property var groupedAccountAssetsModel
required property var walletAccountsModel
required property var networksModel
required property bool areTestNetworksEnabled
required property string currentCurrency
signal fetchProviders()
signal fetchProviderUrl(string uuid,
string providerID,
bool isRecurrent,
string selectedWalletAddress,
int chainID,
string symbol)
// FIXME handling error in case the response is not successful
function providerUrlReady(uuid, url) {
if(uuid === d.uuid) {
d.urlIsBeingFetched = false
if (!!d.selectedProviderEntry.item && !!url)
Global.openLinkWithConfirmation(url, d.selectedProviderEntry.item.hostname)
root.close()
}
}
QtObject { QtObject {
id: d id: d
// States to track requests
property string uuid
property bool urlIsBeingFetched
readonly property var buyButton: StatusButton { readonly property var buyButton: StatusButton {
height: root.finishButton.height height: root.finishButton.height
visible: !!root.replaceItem visible: !!root.replaceItem
borderColor: "transparent" borderColor: "transparent"
text: qsTr("Buy via %1").arg(!!root.buyCryptoAdaptor.selectedProvider ? root.buyCryptoAdaptor.selectedProvider.name: "") text: qsTr("Buy via %1").arg(!!d.selectedProviderEntry.item ? d.selectedProviderEntry.item.name: "")
loading: root.buyCryptoAdaptor.urlIsBeingFetched loading: d.urlIsBeingFetched
onClicked: { onClicked: {
if(!!root.buyCryptoAdaptor.selectedProvider && !!root.buyCryptoAdaptor.selectedToken) { if(!!d.selectedProviderEntry.item && !!d.selectedTokenEntry.item) {
root.buyCryptoAdaptor.fetchProviderUrl( d.fetchProviderUrl(
root.buyCryptoInputParamsForm.selectedProviderId, root.buyCryptoInputParamsForm.selectedProviderId,
buyCryptoProvidersListPanel.currentTabIndex, buyCryptoProvidersListPanel.currentTabIndex,
root.buyCryptoInputParamsForm.selectedWalletAddress, root.buyCryptoInputParamsForm.selectedWalletAddress,
root.buyCryptoInputParamsForm.selectedNetworkChainId, root.buyCryptoInputParamsForm.selectedNetworkChainId,
root.buyCryptoAdaptor.selectedToken.symbol d.selectedTokenEntry.item.symbol
) )
} }
} }
enabled: root.buyCryptoInputParamsForm.filledCorrectly enabled: root.buyCryptoInputParamsForm.filledCorrectly
} }
readonly property ModelEntry selectedAccountEntry: ModelEntry {
sourceModel: root.walletAccountsModel
key: "address"
value: root.buyCryptoInputParamsForm.selectedWalletAddress
}
readonly property ModelEntry selectedTokenEntry: ModelEntry {
sourceModel: root.plainTokensBySymbolModel
key: "key"
value: root.buyCryptoInputParamsForm.selectedTokenKey
}
readonly property ModelEntry selectedProviderEntry: ModelEntry {
id: selectedProviderEntry
sourceModel: root.buyProvidersModel
key: "id"
value: root.buyCryptoInputParamsForm.selectedProviderId
}
function fetchProviderUrl(
providerID,
isRecurrent,
accountAddress = "",
chainID = 0,
symbol = "") {
// Identify new search with a different uuid
d.uuid = Utils.uuid()
d.urlIsBeingFetched = true
root.fetchProviderUrl(d.uuid, providerID, isRecurrent,
accountAddress, chainID, symbol)
}
// used to filter items based on search string in the token selector
property string searchString
readonly property var tokenSelectorViewAdaptor: TokenSelectorViewAdaptor {
assetsModel: root.groupedAccountAssetsModel
plainTokensBySymbolModel: root.plainTokensBySymbolModel
flatNetworksModel: root.networksModel
currentCurrency: root.currentCurrency
showAllTokens: true
enabledChainIds: root.buyCryptoInputParamsForm.selectedNetworkChainId !== -1 ? [root.buyCryptoInputParamsForm.selectedNetworkChainId] : []
accountAddress: root.buyCryptoInputParamsForm.selectedWalletAddress
searchString: d.searchString
}
readonly property var buyCryptoAdaptor: BuyCryptoModalAdaptor {
networksModel: root.networksModel
areTestNetworksEnabled: root.areTestNetworksEnabled
processedTokenSelectorAssetsModel: d.tokenSelectorViewAdaptor.outputAssetsModel
selectedProviderSupportedAssetsArray: {
if (!!d.selectedProviderEntry.item && !!d.selectedProviderEntry.item.supportedAssets)
return ModelUtils.modelToFlatArray(d.selectedProviderEntry.item.supportedAssets, "key")
return null
}
selectedChainId: root.buyCryptoInputParamsForm.selectedNetworkChainId
}
} }
width: 560 width: 560
height: 515 height: 515
padding: Style.current.xlPadding padding: Style.current.xlPadding
stackTitle: qsTr("Buy assets for %1").arg(!!buyCryptoAdaptor.selectedAccount ? buyCryptoAdaptor.selectedAccount.name: "") stackTitle: qsTr("Buy assets for %1").arg(!!d.selectedAccountEntry.item ? d.selectedAccountEntry.item.name: "")
rightButtons: [d.buyButton, finishButton] rightButtons: [d.buyButton, finishButton]
finishButton: StatusButton { finishButton: StatusButton {
text: qsTr("Done") text: qsTr("Done")
onClicked: root.close() onClicked: root.close()
} }
Connections { onOpened: root.fetchProviders()
target: root.buyCryptoAdaptor
function onProviderUrlReady(url) {
if (!!root.buyCryptoAdaptor.selectedProvider && !!url)
Global.openLinkWithConfirmation(url, root.buyCryptoAdaptor.selectedProvider.hostname)
root.close()
}
}
onOpened: root.buyCryptoAdaptor.fetchProviders()
onClosed: { onClosed: {
// reset the view // reset the view
d.uuid = ""
d.urlIsBeingFetched = false
root.replaceItem = undefined root.replaceItem = undefined
buyCryptoProvidersListPanel.currentTabIndex = 0 buyCryptoProvidersListPanel.currentTabIndex = 0
root.buyCryptoAdaptor.reset()
root.buyCryptoInputParamsForm.resetFormData() root.buyCryptoInputParamsForm.resetFormData()
} }
stackItems: [ stackItems: [
BuyCryptoProvidersListPanel { BuyCryptoProvidersListPanel {
id: buyCryptoProvidersListPanel id: buyCryptoProvidersListPanel
providersLoading: root.buyCryptoAdaptor.providersLoading providersLoading: root.isBuyProvidersModelLoading
providersModel: root.buyCryptoAdaptor.providersModel providersModel: root.buyProvidersModel
selectedProviderId: root.buyCryptoInputParamsForm.selectedProviderId selectedProviderId: root.buyCryptoInputParamsForm.selectedProviderId
isUrlBeingFetched: root.buyCryptoAdaptor.urlIsBeingFetched isUrlBeingFetched: d.urlIsBeingFetched
onProviderSelected: { onProviderSelected: {
root.buyCryptoInputParamsForm.selectedProviderId = id root.buyCryptoInputParamsForm.selectedProviderId = id
if(!!root.buyCryptoAdaptor.selectedProvider) { if(!!d.selectedProviderEntry.item) {
if(root.buyCryptoAdaptor.selectedProvider.urlsNeedParameters) { if(d.selectedProviderEntry.item.urlsNeedParameters) {
root.replace(selectParamsPanel) root.replace(selectParamsPanel)
} else { } else {
root.buyCryptoAdaptor.fetchProviderUrl(root.buyCryptoAdaptor.selectedProvider.id, currentTabIndex) d.fetchProviderUrl(d.selectedProviderEntry.item.id, currentTabIndex)
} }
} }
} }
@ -98,36 +181,12 @@ StatusStackModal {
Component { Component {
id: selectParamsPanel id: selectParamsPanel
SelectParamsForBuyCryptoPanel { SelectParamsForBuyCryptoPanel {
id: selectParamsPanelInst objectName: "selectParamsPanel"
adaptor: TokenSelectorViewAdaptor { assetsModel: d.buyCryptoAdaptor.filteredAssetsModel
/* TODO these should be hadbled and perhaps improved under selectedProvider: d.selectedProviderEntry.item
https://github.com/status-im/status-desktop/issues/16025 */
assetsModel: SortFilterProxyModel {
sourceModel: root.buyCryptoAdaptor.groupedAccountAssetsModelWithKey
filters: FastExpressionFilter {
expression: model.addressPerChain.rowCount() > 0
expectedRoles: ["addressPerChain"]
}
}
plainTokensBySymbolModel: SortFilterProxyModel {
sourceModel: root.buyCryptoAdaptor.plainTokensBySymbolModelWithKey
filters: FastExpressionFilter {
expression: model.addressPerChain.rowCount() > 0
expectedRoles: ["addressPerChain"]
}
}
flatNetworksModel: root.buyCryptoAdaptor.networksModel
currentCurrency: root.buyCryptoAdaptor.currentCurrency
showAllTokens: true
enabledChainIds: root.buyCryptoInputParamsForm.selectedNetworkChainId !== -1 ? [root.buyCryptoInputParamsForm.selectedNetworkChainId] : []
accountAddress: root.buyCryptoInputParamsForm.selectedWalletAddress
searchString: selectParamsPanelInst.searchString
}
selectedProvider: root.buyCryptoAdaptor.selectedProvider
selectedTokenKey: root.buyCryptoInputParamsForm.selectedTokenKey selectedTokenKey: root.buyCryptoInputParamsForm.selectedTokenKey
selectedNetworkChainId: root.buyCryptoInputParamsForm.selectedNetworkChainId selectedNetworkChainId: root.buyCryptoInputParamsForm.selectedNetworkChainId
filteredFlatNetworksModel: root.buyCryptoAdaptor.filteredFlatNetworksModel filteredFlatNetworksModel: d.buyCryptoAdaptor.filteredFlatNetworksModel
onNetworkSelected: { onNetworkSelected: {
if (root.buyCryptoInputParamsForm.selectedNetworkChainId !== chainId) { if (root.buyCryptoInputParamsForm.selectedNetworkChainId !== chainId) {
root.buyCryptoInputParamsForm.selectedNetworkChainId = chainId root.buyCryptoInputParamsForm.selectedNetworkChainId = chainId
@ -138,6 +197,11 @@ StatusStackModal {
root.buyCryptoInputParamsForm.selectedTokenKey = tokensKey root.buyCryptoInputParamsForm.selectedTokenKey = tokensKey
} }
} }
Binding {
target: d
property: "searchString"
value: searchString
}
} }
} }
} }

View File

@ -4,143 +4,37 @@ import SortFilterProxyModel 0.2
import StatusQ 0.1 import StatusQ 0.1
import StatusQ.Core.Utils 0.1 import StatusQ.Core.Utils 0.1
import utils 1.0
import shared.stores 1.0
import AppLayouts.Wallet 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStore
QObject { QObject {
id: root id: root
required property WalletStore.BuyCryptoStore buyCryptoStore
required property BuyCryptoParamsForm buyCryptoFormData
required property var walletAccountsModel
required property var networksModel required property var networksModel
required property bool areTestNetworksEnabled required property bool areTestNetworksEnabled
required property var groupedAccountAssetsModel required property var processedTokenSelectorAssetsModel
required property var plainTokensBySymbolModel required property var selectedProviderSupportedAssetsArray
required property string currentCurrency required property int selectedChainId
QtObject {
id: d
property string uuid
property bool urlIsBeingFetched
readonly property var selectedProviderSupportedArray: !!selectedProvider && !!selectedProvider.supportedAssets ? ModelUtils.modelToFlatArray(selectedProvider.supportedAssets, "key"): null
}
signal providerUrlReady(string url)
readonly property bool providersLoading: root.buyCryptoStore.areProvidersLoading
readonly property var providersModel: root.buyCryptoStore.providersModel
readonly property bool urlIsBeingFetched: d.urlIsBeingFetched
readonly property var selectedAccount: selectedAccountEntry.item
readonly property var selectedToken: selectedTokenEntry.item
readonly property var selectedProvider: selectedProviderEntry.item
readonly property SortFilterProxyModel filteredFlatNetworksModel: SortFilterProxyModel { readonly property SortFilterProxyModel filteredFlatNetworksModel: SortFilterProxyModel {
sourceModel: root.networksModel sourceModel: root.networksModel
filters: ValueFilter { roleName: "isTest"; value: root.areTestNetworksEnabled } filters: ValueFilter { roleName: "isTest"; value: root.areTestNetworksEnabled }
} }
/* TODO evaluate if this is still needed after // this proxy removes tokens not supported by selected on-ramp provider
https://github.com/status-im/status-desktop/issues/16025 */ readonly property SortFilterProxyModel filteredAssetsModel: SortFilterProxyModel {
readonly property ObjectProxyModel plainTokensBySymbolModelWithKey: ObjectProxyModel { sourceModel: root.processedTokenSelectorAssetsModel.count ? root.processedTokenSelectorAssetsModel: null
sourceModel: root.plainTokensBySymbolModel
delegate: SortFilterProxyModel {
id: delegateRoot
readonly property var addressPerChain: this
sourceModel: model.addressPerChain
proxyRoles: JoinRole {
name: "key"
roleNames: ["chainId", "address"]
separator: ""
}
filters: FastExpressionFilter { filters: FastExpressionFilter {
expression: !!d.selectedProviderSupportedArray ? d.selectedProviderSupportedArray.includes(model.key) : true function isSupportedByProvider(addressPerChain) {
expectedRoles: ["key"] if(!addressPerChain)
return true
return !!ModelUtils.getFirstModelEntryIf(
addressPerChain,
(addPerChain) => {
return root.selectedChainId === addPerChain.chainId &&
root.selectedProviderSupportedAssetsArray.includes(addPerChain.chainId+addPerChain.address)
})
} }
} expression: isSupportedByProvider(model.addressPerChain)
exposedRoles: ["addressPerChain"]
expectedRoles: ["addressPerChain"] expectedRoles: ["addressPerChain"]
} enabled: !!root.selectedProviderSupportedAssetsArray && root.selectedProviderSupportedAssetsArray.length > 0 && root.selectedChainId !== -1
/* TODO evaluate if this is still needed after
https://github.com/status-im/status-desktop/issues/16025 */
readonly property ObjectProxyModel groupedAccountAssetsModelWithKey: ObjectProxyModel {
sourceModel: root.groupedAccountAssetsModel
delegate: SortFilterProxyModel {
id: delegateRoot1
readonly property var addressPerChain: this
sourceModel: model.addressPerChain
proxyRoles: JoinRole {
name: "key"
roleNames: ["chainId", "address"]
separator: ""
}
filters: FastExpressionFilter {
expression: !!d.selectedProviderSupportedArray ? d.selectedProviderSupportedArray.includes(model.key) : true
expectedRoles: ["key"]
}
}
exposedRoles: ["addressPerChain"]
expectedRoles: ["addressPerChain"]
}
function reset() {
d.uuid = ""
d.urlIsBeingFetched = false
}
function fetchProviders() {
root.buyCryptoStore.fetchProviders()
}
function fetchProviderUrl(
providerID,
isRecurrent,
accountAddress = "",
chainID = 0,
symbol = "") {
// Identify new search with a different uuid
d.uuid = Utils.uuid()
d.urlIsBeingFetched = true
buyCryptoStore.fetchProviderUrl(d.uuid, providerID, isRecurrent,
accountAddress, chainID,symbol)
}
Connections {
target: root.buyCryptoStore
function onProviderUrlReady(uuid, url) {
if(uuid === d.uuid) {
d.urlIsBeingFetched = false
root.providerUrlReady(url)
} }
} }
} }
ModelEntry {
id: selectedAccountEntry
sourceModel: root.walletAccountsModel
key: "address"
value: root.buyCryptoFormData.selectedWalletAddress
}
ModelEntry {
id: selectedTokenEntry
sourceModel: root.plainTokensBySymbolModel
key: "key"
value: root.buyCryptoFormData.selectedTokenKey
}
ModelEntry {
id: selectedProviderEntry
sourceModel: root.providersModel
key: "id"
value: root.buyCryptoFormData.selectedProviderId
}
}

View File

@ -79,6 +79,8 @@ Item {
tokensStore: appMain.tokensStore tokensStore: appMain.tokensStore
currencyStore: appMain.currencyStore currencyStore: appMain.currencyStore
} }
readonly property WalletStores.BuyCryptoStore buyCryptoStore: WalletStores.BuyCryptoStore {}
readonly property FeatureFlagsStore featureFlagsStore: FeatureFlagsStore { readonly property FeatureFlagsStore featureFlagsStore: FeatureFlagsStore {
readonly property var featureFlags: typeof featureFlagsRootContextProperty !== undefined ? featureFlagsRootContextProperty : null readonly property var featureFlags: typeof featureFlagsRootContextProperty !== undefined ? featureFlagsRootContextProperty : null
@ -402,6 +404,7 @@ Item {
currencyStore: appMain.currencyStore currencyStore: appMain.currencyStore
walletAssetsStore: appMain.walletAssetsStore walletAssetsStore: appMain.walletAssetsStore
walletCollectiblesStore: appMain.walletCollectiblesStore walletCollectiblesStore: appMain.walletCollectiblesStore
buyCryptoStore: appMain.buyCryptoStore
networkConnectionStore: appMain.networkConnectionStore networkConnectionStore: appMain.networkConnectionStore
isDevBuild: !production isDevBuild: !production

View File

@ -45,6 +45,7 @@ QtObject {
property WalletStore.WalletAssetsStore walletAssetsStore property WalletStore.WalletAssetsStore walletAssetsStore
property WalletStore.CollectiblesStore walletCollectiblesStore property WalletStore.CollectiblesStore walletCollectiblesStore
property NetworkConnectionStore networkConnectionStore property NetworkConnectionStore networkConnectionStore
property WalletStore.BuyCryptoStore buyCryptoStore
property bool isDevBuild property bool isDevBuild
signal openExternalLink(string link) signal openExternalLink(string link)
@ -1249,15 +1250,18 @@ QtObject {
Component { Component {
id: buyCryptoModal id: buyCryptoModal
BuyCryptoModal { BuyCryptoModal {
buyCryptoAdaptor: BuyCryptoModalAdaptor { buyProvidersModel: root.buyCryptoStore.providersModel
buyCryptoStore: WalletStore.BuyCryptoStore {} isBuyProvidersModelLoading: root.buyCryptoStore.areProvidersLoading
buyCryptoFormData: buyCryptoInputParamsForm currentCurrency: root.currencyStore.currentCurrency
walletAccountsModel: root.rootStore.accounts walletAccountsModel: root.rootStore.accounts
plainTokensBySymbolModel: root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel
groupedAccountAssetsModel: root.walletAssetsStore.groupedAccountAssetsModel
networksModel: root.rootStore.profileSectionStore.walletStore.flatNetworks networksModel: root.rootStore.profileSectionStore.walletStore.flatNetworks
areTestNetworksEnabled: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled areTestNetworksEnabled: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled
groupedAccountAssetsModel: root.walletAssetsStore.groupedAccountAssetsModel Component.onCompleted: {
plainTokensBySymbolModel: root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel fetchProviders.connect(root.buyCryptoStore.fetchProviders)
currentCurrency: root.currencyStore.currentCurrency fetchProviderUrl.connect(root.buyCryptoStore.fetchProviderUrl)
root.buyCryptoStore.providerUrlReady.connect(providerUrlReady)
} }
onClosed: destroy() onClosed: destroy()
} }