Old version of TokenSelector removed
This commit is contained in:
parent
c8b8d1ee9d
commit
9f40251588
|
@ -1,208 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
orientation: Qt.Vertical
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
ListModel {
|
||||
id: plainTokensModel
|
||||
ListElement {
|
||||
key: "aave"
|
||||
name: "Aave"
|
||||
symbol: "AAVE"
|
||||
image: "https://cryptologos.cc/logos/aave-aave-logo.png"
|
||||
communityId: ""
|
||||
}
|
||||
ListElement {
|
||||
key: "usdc"
|
||||
name: "USDC"
|
||||
symbol: "USDC"
|
||||
image: ""
|
||||
communityId: ""
|
||||
}
|
||||
ListElement {
|
||||
key: "hst"
|
||||
name: "Decision Token"
|
||||
symbol: "HST"
|
||||
image: "https://etherscan.io/token/images/horizonstate2_28.png"
|
||||
communityId: ""
|
||||
}
|
||||
// DAI should be filtered out
|
||||
ListElement {
|
||||
key: "DAI"
|
||||
name: "Dai Stablecoin"
|
||||
symbol: "DAI"
|
||||
image: ""
|
||||
communityId: ""
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||
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 var walletAccountsModel: WalletAccountsModel {}
|
||||
|
||||
readonly property var adaptor: TokenSelectorViewAdaptor {
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
plainTokensBySymbolModel: plainTokensModel
|
||||
flatNetworksModel: d.flatNetworks
|
||||
currentCurrency: d.currencyStore.currentCurrency
|
||||
|
||||
showAllTokens: ctrlShowAllTokens.checked
|
||||
enabledChainIds: ctrlNetwork.currentValue ? [ctrlNetwork.currentValue] : []
|
||||
accountAddress: ctrlAccount.currentValue ?? ""
|
||||
showCommunityAssets: ctrlShowCommunityAssets.checked
|
||||
searchString: tokenSelector.searchString
|
||||
}
|
||||
}
|
||||
|
||||
Pane {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.palette.baseColor3
|
||||
}
|
||||
|
||||
TokenSelector {
|
||||
id: tokenSelector
|
||||
anchors.centerIn: parent
|
||||
|
||||
nonInteractiveDelegateKey: ctrlNonInteractiveDelegateKey.text
|
||||
|
||||
model: d.adaptor.outputAssetsModel
|
||||
onTokenSelected: (tokensKey) => {
|
||||
console.warn("!!! TOKEN SELECTED:", tokensKey)
|
||||
logs.logEvent("TokenSelector::onTokenSelected", ["tokensKey"], arguments)
|
||||
}
|
||||
onActivated: ctrlSelectedAsset.currentIndex = ctrlSelectedAsset.indexOfValue(currentTokensKey)
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
SplitView.minimumHeight: 340
|
||||
SplitView.preferredHeight: 340
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Selected asset:" }
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlSelectedAsset
|
||||
model: d.assetsStore.groupedAccountAssetsModel
|
||||
textRole: "name"
|
||||
valueRole: "tokensKey"
|
||||
displayText: currentText || "N/A"
|
||||
onActivated: tokenSelector.selectToken(currentValue)
|
||||
}
|
||||
TextField {
|
||||
id: ctrlNonInteractiveDelegateKey
|
||||
placeholderText: "Non interactive delegate token key"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Reset"
|
||||
onClicked: {
|
||||
tokenSelector.reset()
|
||||
ctrlSelectedAsset.currentIndex = -1
|
||||
ctrlNonInteractiveDelegateKey.clear()
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: ctrlShowAllTokens
|
||||
text: "Show all tokens"
|
||||
onToggled: {
|
||||
// NB: ComboBox doesn't like changing models at runtime
|
||||
tokenSelector.model = null
|
||||
tokenSelector.model = d.adaptor.outputAssetsModel
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
id: ctrlShowCommunityAssets
|
||||
text: "Show community assets"
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Network:" }
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlNetwork
|
||||
textRole: "chainName"
|
||||
valueRole: "chainId"
|
||||
displayText: currentText || "All networks"
|
||||
model: d.flatNetworks
|
||||
currentIndex: -1
|
||||
}
|
||||
}
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "Selected: %1".arg(ctrlNetwork.currentValue ? ctrlNetwork.currentValue.toString() : "All")
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Account:" }
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlAccount
|
||||
textRole: "name"
|
||||
valueRole: "address"
|
||||
displayText: currentText || "All accounts"
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: d.walletAccountsModel
|
||||
sorters: RoleSorter { roleName: "position" }
|
||||
}
|
||||
currentIndex: -1
|
||||
}
|
||||
}
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "Selected: %1".arg(ctrlAccount.currentValue ?? "all")
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Controls
|
||||
|
||||
// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3406-231273&t=Ncl9lN1umbGEMxOn-0
|
|
@ -1,244 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Wallet.views 1.0
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
orientation: Qt.Vertical
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
ListModel {
|
||||
id: plainTokensModel
|
||||
ListElement {
|
||||
key: "aave"
|
||||
name: "Aave"
|
||||
symbol: "AAVE"
|
||||
image: "https://cryptologos.cc/logos/aave-aave-logo.png"
|
||||
communityId: ""
|
||||
}
|
||||
ListElement {
|
||||
key: "usdc"
|
||||
name: "USDC"
|
||||
symbol: "USDC"
|
||||
image: ""
|
||||
communityId: ""
|
||||
}
|
||||
ListElement {
|
||||
key: "hst"
|
||||
name: "Decision Token"
|
||||
symbol: "HST"
|
||||
image: "https://etherscan.io/token/images/horizonstate2_28.png"
|
||||
communityId: ""
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
property var enabledChainIds: []
|
||||
function addFilter(chainId) {
|
||||
if (d.enabledChainIds.includes(chainId))
|
||||
return
|
||||
const newFilters = d.enabledChainIds.concat(chainId)
|
||||
d.enabledChainIds = newFilters
|
||||
}
|
||||
function removeFilter(chainId) {
|
||||
const newFilters = d.enabledChainIds.filter((filter) => filter !== chainId)
|
||||
d.enabledChainIds = newFilters
|
||||
}
|
||||
function rebuildFilter() {
|
||||
let newFilters = []
|
||||
for (let i = 0; i < chainIdsRepeater.count; i++) {
|
||||
const item = chainIdsRepeater.itemAt(i)
|
||||
if (!!item && item.checked) {
|
||||
newFilters.push(item.chainId)
|
||||
}
|
||||
}
|
||||
d.enabledChainIds = newFilters
|
||||
}
|
||||
|
||||
readonly property string enabledChainIdsString: enabledChainIds.join(":")
|
||||
|
||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||
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 var walletAccountsModel: WalletAccountsModel {}
|
||||
|
||||
readonly property var adaptor: TokenSelectorViewAdaptor {
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
plainTokensBySymbolModel: plainTokensModel
|
||||
flatNetworksModel: d.flatNetworks
|
||||
enabledChainIds: d.enabledChainIds
|
||||
currentCurrency: d.currencyStore.currentCurrency
|
||||
|
||||
showAllTokens: ctrlShowAllTokens.checked
|
||||
accountAddress: ctrlAccount.currentValue ?? ""
|
||||
showCommunityAssets: ctrlShowCommunityAssets.checked
|
||||
searchString: ctrlSearch.text
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: d.rebuildFilter()
|
||||
|
||||
Pane {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.palette.baseColor3
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 380
|
||||
height: 200
|
||||
color: Theme.palette.statusListItem.backgroundColor
|
||||
border.color: Theme.palette.primaryColor1
|
||||
border.width: 1
|
||||
anchors.centerIn: parent
|
||||
|
||||
// tokensKey, name, symbol, decimals, currentCurrencyBalance (computed), marketDetails, balances -> [ chainId, address, balance, iconUrl ]
|
||||
TokenSelectorView {
|
||||
id: tokenSelector
|
||||
anchors.fill: parent
|
||||
|
||||
model: d.adaptor.outputAssetsModel
|
||||
|
||||
onTokenSelected: (tokensKey) => {
|
||||
console.warn("!!! TOKEN SELECTED:", tokensKey)
|
||||
logs.logEvent("TokenSelectorView::onTokenSelected", ["tokensKey"], arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
SplitView.minimumHeight: 400
|
||||
SplitView.preferredHeight: 400
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
CheckBox {
|
||||
id: ctrlTestNetworks
|
||||
text: "Test networks enabled"
|
||||
tristate: true
|
||||
checkState: Qt.PartiallyChecked
|
||||
onClicked: d.rebuildFilter()
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: chainIdsRepeater
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: d.flatNetworks
|
||||
filters: ValueFilter {
|
||||
roleName: "isTest"
|
||||
value: ctrlTestNetworks.checked
|
||||
enabled: ctrlTestNetworks.checkState !== Qt.PartiallyChecked
|
||||
}
|
||||
}
|
||||
delegate: CheckBox {
|
||||
required property int chainId
|
||||
required property string chainName
|
||||
required property string shortName
|
||||
required property bool isEnabled
|
||||
checked: isEnabled
|
||||
opacity: enabled ? 1 : 0.3
|
||||
text: "%1 (%2) - %3".arg(chainName).arg(shortName).arg(chainId)
|
||||
onToggled: {
|
||||
if (checked)
|
||||
d.addFilter(chainId)
|
||||
else
|
||||
d.removeFilter(chainId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Enabled chain ids: %1".arg(d.enabledChainIdsString)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Search:" }
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlSearch
|
||||
placeholderText: "Token name or symbol"
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
id: ctrlShowAllTokens
|
||||
text: "Show all tokens"
|
||||
checked: true
|
||||
onToggled: {
|
||||
// NB: ListView doesn't like changing models at runtime
|
||||
tokenSelector.model = null
|
||||
tokenSelector.model = d.adaptor.outputAssetsModel
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
id: ctrlShowCommunityAssets
|
||||
text: "Show community assets"
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Account:" }
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlAccount
|
||||
textRole: "name"
|
||||
valueRole: "address"
|
||||
displayText: currentIndex === -1 ? "All accounts" : currentText
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: d.walletAccountsModel
|
||||
sorters: RoleSorter { roleName: "position" }
|
||||
}
|
||||
currentIndex: -1
|
||||
}
|
||||
}
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "Selected: %1".arg(ctrlAccount.currentValue ?? "all")
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Views
|
|
@ -1,260 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtTest 1.15
|
||||
import QtQml 2.15
|
||||
|
||||
import Models 1.0
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
ListModel {
|
||||
id: plainTokensModel
|
||||
ListElement {
|
||||
key: "aave"
|
||||
name: "Aave"
|
||||
symbol: "AAVE"
|
||||
image: "https://cryptologos.cc/logos/aave-aave-logo.png"
|
||||
communityId: ""
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||
readonly property var assetsStore: WalletAssetsStore {
|
||||
id: thisWalletAssetStore
|
||||
walletTokensStore: TokensStore {
|
||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||
}
|
||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||
}
|
||||
|
||||
readonly property var adaptor: TokenSelectorViewAdaptor {
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
plainTokensBySymbolModel: plainTokensModel
|
||||
flatNetworksModel: d.flatNetworks
|
||||
currentCurrency: "USD"
|
||||
enabledChainIds: [420]
|
||||
|
||||
Binding on searchString {
|
||||
value: controlUnderTest ? controlUnderTest.searchString : ""
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: componentUnderTest
|
||||
TokenSelector {
|
||||
anchors.centerIn: parent
|
||||
model: d.adaptor.outputAssetsModel
|
||||
}
|
||||
}
|
||||
|
||||
SignalSpy {
|
||||
id: signalSpy
|
||||
target: controlUnderTest
|
||||
signalName: "tokenSelected"
|
||||
}
|
||||
|
||||
property TokenSelector controlUnderTest: null
|
||||
|
||||
TestCase {
|
||||
name: "TokenSelector"
|
||||
when: windowShown
|
||||
|
||||
function init() {
|
||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||
signalSpy.clear()
|
||||
}
|
||||
|
||||
function test_basicGeometry() {
|
||||
verify(!!controlUnderTest)
|
||||
verify(controlUnderTest.width > 0)
|
||||
verify(controlUnderTest.height > 0)
|
||||
}
|
||||
|
||||
function test_clickEthToken() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
mouseClick(controlUnderTest)
|
||||
waitForItemPolished(controlUnderTest)
|
||||
|
||||
const listview = findChild(controlUnderTest.popup.contentItem, "tokenSelectorListview")
|
||||
verify(!!listview)
|
||||
waitForItemPolished(listview)
|
||||
|
||||
const tokensKey = "ETH"
|
||||
const delegate = findChild(listview, "tokenSelectorAssetDelegate_%1".arg(tokensKey))
|
||||
verify(!!delegate)
|
||||
tryCompare(delegate, "tokensKey", tokensKey)
|
||||
|
||||
// click the delegate, verify the signal has been fired and has the correct "tokensKey" as argument
|
||||
mouseClick(delegate)
|
||||
tryCompare(signalSpy, "count", 1)
|
||||
compare(signalSpy.signalArguments[0][0], tokensKey)
|
||||
compare(controlUnderTest.currentTokensKey, tokensKey)
|
||||
|
||||
// close the popup, reopen and verify our token is highlighted
|
||||
controlUnderTest.popup.close()
|
||||
mouseClick(controlUnderTest)
|
||||
tryCompare(controlUnderTest.popup, "opened", true)
|
||||
tryCompare(delegate, "highlighted", true)
|
||||
}
|
||||
|
||||
function test_clickNonInteractiveToken() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const tokensKey = "STT"
|
||||
controlUnderTest.nonInteractiveDelegateKey = tokensKey
|
||||
|
||||
mouseClick(controlUnderTest)
|
||||
waitForItemPolished(controlUnderTest)
|
||||
|
||||
const listview = findChild(controlUnderTest.popup.contentItem, "tokenSelectorListview")
|
||||
verify(!!listview)
|
||||
waitForItemPolished(listview)
|
||||
|
||||
const delegate = findChild(listview, "tokenSelectorAssetDelegate_%1".arg(tokensKey))
|
||||
verify(!!delegate)
|
||||
tryCompare(delegate, "tokensKey", tokensKey)
|
||||
tryCompare(delegate, "interactive", false)
|
||||
|
||||
mouseClick(delegate)
|
||||
tryCompare(signalSpy, "count", 0)
|
||||
tryCompare(controlUnderTest, "currentTokensKey", "")
|
||||
}
|
||||
|
||||
function test_selectToken() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const tokensKey = "STT"
|
||||
controlUnderTest.selectToken(tokensKey)
|
||||
tryCompare(signalSpy, "count", 1)
|
||||
compare(signalSpy.signalArguments[0][0], tokensKey)
|
||||
tryCompare(controlUnderTest, "currentTokensKey", tokensKey)
|
||||
|
||||
const listview = findChild(controlUnderTest.popup.contentItem, "tokenSelectorListview")
|
||||
verify(!!listview)
|
||||
mouseClick(controlUnderTest)
|
||||
const delegate = findChild(listview, "tokenSelectorAssetDelegate_%1".arg(tokensKey))
|
||||
verify(!!delegate)
|
||||
tryCompare(delegate, "tokensKey", tokensKey)
|
||||
tryCompare(delegate, "highlighted", true)
|
||||
}
|
||||
|
||||
function test_selectNonexistingToken() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const tokensKey = "0x6b175474e89094c44da98b954eedeac495271d0f" // MET
|
||||
|
||||
// not available by default
|
||||
controlUnderTest.selectToken(tokensKey)
|
||||
tryCompare(signalSpy, "count", 1)
|
||||
compare(signalSpy.signalArguments[0][0], "")
|
||||
tryCompare(controlUnderTest, "currentTokensKey", "")
|
||||
|
||||
// enable community assets, now should be available, try to select it
|
||||
d.adaptor.showCommunityAssets = true
|
||||
controlUnderTest.selectToken(tokensKey)
|
||||
tryCompare(signalSpy, "count", 2)
|
||||
compare(signalSpy.signalArguments[1][0], tokensKey)
|
||||
tryCompare(controlUnderTest, "currentTokensKey", tokensKey)
|
||||
|
||||
// disable community assets to simulate token gone
|
||||
d.adaptor.showCommunityAssets = false
|
||||
|
||||
// control should reset itself back
|
||||
tryCompare(signalSpy, "count", 3)
|
||||
compare(signalSpy.signalArguments[2][0], "")
|
||||
tryCompare(controlUnderTest, "currentTokensKey", "")
|
||||
}
|
||||
|
||||
function test_search() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
mouseClick(controlUnderTest)
|
||||
waitForItemPolished(controlUnderTest)
|
||||
|
||||
const originalCount = controlUnderTest.count
|
||||
verify(originalCount > 0)
|
||||
|
||||
// verify the search box has focus
|
||||
const searchBox = findChild(controlUnderTest.popup.contentItem, "searchBox")
|
||||
verify(!!searchBox)
|
||||
tryCompare(searchBox.input.edit, "focus", true)
|
||||
|
||||
// type "dAi"
|
||||
keyClick(Qt.Key_D)
|
||||
keyClick(Qt.Key_A, Qt.ShiftModifier)
|
||||
keyClick(Qt.Key_I)
|
||||
|
||||
// search yields 1 result
|
||||
waitForItemPolished(controlUnderTest)
|
||||
tryCompare(controlUnderTest, "count", 1)
|
||||
|
||||
// closing the popup should clear the search and put the view back to original count
|
||||
controlUnderTest.popup.close()
|
||||
mouseClick(controlUnderTest)
|
||||
tryCompare(searchBox.input.edit, "text", "")
|
||||
tryCompare(controlUnderTest, "count", originalCount)
|
||||
}
|
||||
|
||||
function test_sections() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
d.adaptor.enabledChainIds = [10] // filter Optimism chain only
|
||||
|
||||
mouseClick(controlUnderTest)
|
||||
waitForItemPolished(controlUnderTest)
|
||||
|
||||
const listview = findChild(controlUnderTest.popup.contentItem, "tokenSelectorListview")
|
||||
verify(!!listview)
|
||||
waitForItemPolished(listview)
|
||||
|
||||
const sttDelegate = findChild(listview, "tokenSelectorAssetDelegate_STT")
|
||||
verify(!!sttDelegate)
|
||||
tryCompare(sttDelegate, "tokensKey", "STT")
|
||||
compare(sttDelegate.ListView.section, "Your assets on Optimism")
|
||||
|
||||
const ethDelegate = findChild(listview, "tokenSelectorAssetDelegate_ETH")
|
||||
verify(!!ethDelegate)
|
||||
tryCompare(ethDelegate, "tokensKey", "ETH")
|
||||
compare(ethDelegate.ListView.section, "Popular assets")
|
||||
}
|
||||
|
||||
function test_plainTokenDelegate() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
d.adaptor.showAllTokens = true
|
||||
const tokensKey = "aave"
|
||||
|
||||
mouseClick(controlUnderTest)
|
||||
waitForItemPolished(controlUnderTest)
|
||||
|
||||
const listview = findChild(controlUnderTest.popup.contentItem, "tokenSelectorListview")
|
||||
verify(!!listview)
|
||||
waitForItemPolished(listview)
|
||||
|
||||
const delegate = findChild(listview, "tokenSelectorAssetDelegate_%1".arg(tokensKey))
|
||||
verify(!!delegate)
|
||||
tryCompare(delegate, "tokensKey", tokensKey)
|
||||
tryCompare(delegate, "currencyBalanceAsString", "")
|
||||
|
||||
// click the delegate, verify the signal has been fired and has the correct "tokensKey" as argument
|
||||
mouseClick(delegate)
|
||||
tryCompare(signalSpy, "count", 1)
|
||||
compare(signalSpy.signalArguments[0][0], tokensKey)
|
||||
compare(controlUnderTest.currentTokensKey, tokensKey)
|
||||
d.adaptor.showAllTokens = false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtTest 1.15
|
||||
|
||||
import Models 1.0
|
||||
|
||||
import AppLayouts.Wallet.views 1.0
|
||||
import AppLayouts.Wallet.stores 1.0
|
||||
import AppLayouts.Wallet.adaptors 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property var flatNetworks: NetworksModel.flatNetworks
|
||||
readonly property var assetsStore: WalletAssetsStore {
|
||||
id: thisWalletAssetStore
|
||||
walletTokensStore: TokensStore {
|
||||
plainTokensBySymbolModel: TokensBySymbolModel {}
|
||||
}
|
||||
readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {}
|
||||
assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel
|
||||
}
|
||||
|
||||
readonly property var adaptor: TokenSelectorViewAdaptor {
|
||||
assetsModel: d.assetsStore.groupedAccountAssetsModel
|
||||
flatNetworksModel: d.flatNetworks
|
||||
currentCurrency: "USD"
|
||||
enabledChainIds: ModelUtils.modelToFlatArray(d.flatNetworks, "chainId")
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: componentUnderTest
|
||||
TokenSelectorView {
|
||||
anchors.fill: parent
|
||||
model: d.adaptor.outputAssetsModel
|
||||
}
|
||||
}
|
||||
|
||||
SignalSpy {
|
||||
id: signalSpy
|
||||
target: controlUnderTest
|
||||
signalName: "tokenSelected"
|
||||
}
|
||||
|
||||
property TokenSelectorView controlUnderTest: null
|
||||
|
||||
TestCase {
|
||||
name: "TokenSelectorView"
|
||||
when: windowShown
|
||||
|
||||
function init() {
|
||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||
signalSpy.clear()
|
||||
}
|
||||
|
||||
function test_basicGeometry() {
|
||||
verify(!!controlUnderTest)
|
||||
verify(controlUnderTest.width > 0)
|
||||
verify(controlUnderTest.height > 0)
|
||||
}
|
||||
|
||||
function test_clickEthToken() {
|
||||
verify(!!controlUnderTest)
|
||||
|
||||
const tokensKey = "ETH"
|
||||
|
||||
const delegate = findChild(controlUnderTest, "tokenSelectorAssetDelegate_%1".arg(tokensKey))
|
||||
verify(!!delegate)
|
||||
|
||||
// click the delegate, verify the signal has been fired and has the correct "tokensKey" as argument
|
||||
mouseClick(delegate)
|
||||
tryCompare(signalSpy, "count", 1)
|
||||
compare(signalSpy.signalArguments[0][0], tokensKey)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Components.private 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
|
||||
import AppLayouts.Wallet.views 1.0
|
||||
|
||||
import utils 1.0
|
||||
import shared.controls 1.0
|
||||
|
||||
ComboBox {
|
||||
id: root
|
||||
|
||||
// expected model structure:
|
||||
// tokensKey, name, symbol, decimals, currencyBalanceAsString (computed), marketDetails, balances -> [ chainId, address, balance, iconUrl ]
|
||||
|
||||
// input API
|
||||
property string nonInteractiveDelegateKey
|
||||
|
||||
// output API
|
||||
readonly property string currentTokensKey: d.currentTokensKey
|
||||
readonly property alias searchString: searchBox.text
|
||||
|
||||
/**
|
||||
Emitted when a token gets selected
|
||||
*/
|
||||
signal tokenSelected(string tokensKey)
|
||||
|
||||
// manipulation
|
||||
function selectToken(tokensKey) {
|
||||
const idx = ModelUtils.indexOf(model, "tokensKey", tokensKey)
|
||||
if (idx === -1) {
|
||||
console.warn("TokenSelector::selectToken: unknown tokensKey:", tokensKey)
|
||||
tokensKey = ""
|
||||
}
|
||||
|
||||
currentIndex = idx
|
||||
d.currentTokensKey = tokensKey
|
||||
root.tokenSelected(tokensKey)
|
||||
}
|
||||
|
||||
function reset() {
|
||||
selectToken("")
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
// NB: internal tracking; the ComboBox currentValue is not persistent,
|
||||
// i.e. relying on currentValue is not safe
|
||||
property string currentTokensKey
|
||||
|
||||
readonly property bool isTokenSelected: !!currentTokensKey
|
||||
|
||||
// NB: handle cases when our currently selected token disappears from the model -> reset
|
||||
readonly property Connections _conn: Connections {
|
||||
target: model ?? null
|
||||
function onModelReset() {
|
||||
if (d.isTokenSelected && !root.popup.opened)
|
||||
root.selectToken(d.currentTokensKey)
|
||||
}
|
||||
function onRowsRemoved() {
|
||||
if (d.isTokenSelected && !root.popup.opened)
|
||||
root.selectToken(d.currentTokensKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font.family: Theme.palette.baseFont.name
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
spacing: Style.current.halfPadding
|
||||
verticalPadding: 10
|
||||
leftPadding: 12
|
||||
rightPadding: leftPadding + indicator.width + spacing
|
||||
opacity: enabled ? 1 : 0.3
|
||||
|
||||
popup.width: 380
|
||||
popup.height: 380
|
||||
popup.x: root.width - popup.width
|
||||
popup.margins: Style.current.xlPadding*2
|
||||
popup.background: Rectangle {
|
||||
color: Theme.palette.statusSelect.menuItemBackgroundColor
|
||||
radius: Style.current.radius
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 4
|
||||
radius: 12
|
||||
samples: 25
|
||||
spread: 0.2
|
||||
color: Theme.palette.dropShadow
|
||||
}
|
||||
}
|
||||
popup.contentItem: ColumnLayout {
|
||||
Connections {
|
||||
target: root.popup
|
||||
function onOpened() {
|
||||
listview.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
SearchBox {
|
||||
Layout.fillWidth: true
|
||||
id: searchBox
|
||||
objectName: "searchBox"
|
||||
|
||||
input.leftPadding: root.leftPadding
|
||||
input.rightPadding: root.leftPadding
|
||||
minimumHeight: 56
|
||||
maximumHeight: 56
|
||||
placeholderText: qsTr("Search asset name or symbol")
|
||||
input.showBackground: false
|
||||
focus: visible
|
||||
onVisibleChanged: if (!visible) input.edit.clear()
|
||||
}
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
StatusListView {
|
||||
id: listview
|
||||
objectName: "tokenSelectorListview"
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: root.popup.visible ? root.delegateModel : null
|
||||
currentIndex: root.highlightedIndex
|
||||
|
||||
section.property: "sectionName"
|
||||
section.delegate: StatusBaseText {
|
||||
required property string section
|
||||
visible: searchBox.text === ""
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: visible ? section : ""
|
||||
color: Theme.palette.baseColor1
|
||||
padding: Style.current.padding
|
||||
}
|
||||
}
|
||||
StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
visible: listview.count === 0
|
||||
color: Theme.palette.baseColor1
|
||||
text: qsTr("No assets found")
|
||||
}
|
||||
}
|
||||
|
||||
background: StatusComboboxBackground {
|
||||
border.width: 0
|
||||
color: {
|
||||
if (d.isTokenSelected)
|
||||
return "transparent"
|
||||
return root.hovered ? Theme.palette.primaryColor2 : Theme.palette.primaryColor3
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Loader {
|
||||
height: 40 // by design
|
||||
sourceComponent: d.isTokenSelected ? iconTextContentItem : textContentItem
|
||||
}
|
||||
|
||||
indicator: StatusComboboxIndicator {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: root.leftPadding
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Theme.palette.primaryColor1
|
||||
}
|
||||
|
||||
delegate: TokenSelectorAssetDelegate {
|
||||
objectName: "tokenSelectorAssetDelegate_" + model.tokensKey
|
||||
|
||||
required property var model
|
||||
required property int index
|
||||
|
||||
width: ListView.view.width
|
||||
|
||||
highlighted: model.tokensKey === d.currentTokensKey
|
||||
enabled: model.tokensKey !== root.nonInteractiveDelegateKey
|
||||
balancesListInteractive: !ListView.view.moving
|
||||
|
||||
name: model.name
|
||||
symbol: model.symbol
|
||||
currencyBalanceAsString: model.currencyBalanceAsString ?? ""
|
||||
iconSource: model.iconSource
|
||||
balancesModel: model.balances
|
||||
|
||||
onClicked: root.selectToken(model.tokensKey)
|
||||
}
|
||||
|
||||
Component {
|
||||
id: textContentItem
|
||||
StatusBaseText {
|
||||
objectName: "tokenSelectorContentItemText"
|
||||
font.pixelSize: root.font.pixelSize
|
||||
font.weight: Font.Medium
|
||||
color: Theme.palette.primaryColor1
|
||||
text: qsTr("Select asset")
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: iconTextContentItem
|
||||
RowLayout {
|
||||
spacing: root.spacing
|
||||
StatusRoundedImage {
|
||||
objectName: "tokenSelectorIcon"
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
image.source: ModelUtils.getByKey(model, "tokensKey", d.currentTokensKey, "iconSource")
|
||||
}
|
||||
StatusBaseText {
|
||||
objectName: "tokenSelectorContentItemText"
|
||||
font.pixelSize: 28
|
||||
color: root.hovered ? Theme.palette.blue : Theme.palette.darkBlue
|
||||
text: ModelUtils.getByKey(model, "tokensKey", d.currentTokensKey, "symbol")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ StatusNetworkListItemTag 1.0 StatusNetworkListItemTag.qml
|
|||
StatusTxProgressBar 1.0 StatusTxProgressBar.qml
|
||||
SwapExchangeButton 1.0 SwapExchangeButton.qml
|
||||
SwapProvidersTermsAndConditionsText 1.0 SwapProvidersTermsAndConditionsText.qml
|
||||
TokenSelector 1.0 TokenSelector.qml
|
||||
TokenSelectorButton 1.0 TokenSelectorButton.qml
|
||||
TokenSelectorCompactButton 1.0 TokenSelectorCompactButton.qml
|
||||
TokenSelectorNew 1.0 TokenSelectorNew.qml
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
|
||||
StatusListView {
|
||||
id: root
|
||||
|
||||
// expected model structure:
|
||||
// tokensKey, name, symbol, decimals, currencyBalanceAsString (computed), iconSource, marketDetails, balances -> [ chainId, address, balance, iconUrl ]
|
||||
|
||||
// output API
|
||||
signal tokenSelected(string tokensKey)
|
||||
|
||||
currentIndex: -1
|
||||
|
||||
delegate: TokenSelectorAssetDelegate {
|
||||
objectName: "tokenSelectorAssetDelegate_" + model.tokensKey
|
||||
|
||||
required property var model
|
||||
required property int index
|
||||
|
||||
width: ListView.view.width
|
||||
balancesListInteractive: !ListView.view.moving
|
||||
|
||||
name: model.name
|
||||
symbol: model.symbol
|
||||
currencyBalanceAsString: model.currencyBalanceAsString ?? ""
|
||||
iconSource: model.iconSource
|
||||
balancesModel: model.balances
|
||||
|
||||
onClicked: root.tokenSelected(model.tokensKey)
|
||||
}
|
||||
}
|
|
@ -6,5 +6,4 @@ SavedAddresses 1.0 SavedAddresses.qml
|
|||
TokenSelectorAssetDelegate 1.0 TokenSelectorAssetDelegate.qml
|
||||
TokenSelectorCollectibleDelegate 1.0 TokenSelectorCollectibleDelegate.qml
|
||||
TokenSelectorSectionDelegate 1.0 TokenSelectorSectionDelegate.qml
|
||||
TokenSelectorView 1.0 TokenSelectorView.qml
|
||||
AccountContextMenu 1.0 AccountContextMenu.qml
|
||||
|
|
Loading…
Reference in New Issue