Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions storybook/pages/SimpleSendModalPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ SplitView {
readonly property WalletAssetsStoreMock walletAssetStore: WalletAssetsStoreMock {
walletTokensStore: TokensStoreMock {
tokenGroupsModel: TokenGroupsModel{}
tokenGroupsForChainModel: TokenGroupsModel {
skipInitialLoad: true
}
searchResultModel: TokenGroupsModel {
skipInitialLoad: true
fetchMode: true
fetchBatchSize: 8
fetchInitialCount: 8
tokenGroupsForChainModel: d.walletAssetStore.walletTokensStore.tokenGroupsForChainModel
}
_displayAssetsBelowBalanceThresholdDisplayAmountFunc: () => 0
}
}
Expand Down Expand Up @@ -167,6 +177,13 @@ SplitView {

onReviewSendClicked: console.log("Review send clicked")
onLaunchBuyFlow: console.log("launch buy flow clicked")
onSearchInAssets: (keyword) => {
if (assetsSelectorViewAdaptor.searchString === "" && keyword !== "") {
d.walletAssetStore.walletTokensStore.buildGroupsForChain(simpleSend.selectedChainId)
}
assetsSelectorViewAdaptor.search(keyword)
}
onFetchMoreAssets: assetsSelectorViewAdaptor.loadMoreItems()

Binding on selectedAccountAddress {
value: accountsCombobox.currentValue ?? ""
Expand Down Expand Up @@ -219,6 +236,7 @@ SplitView {

accountAddress: simpleSend.selectedAccountAddress
enabledChainIds: [simpleSend.selectedChainId]
searchResultModel: d.walletAssetStore.walletTokensStore.searchResultModel
}

CollectiblesSelectionAdaptor {
Expand Down
97 changes: 86 additions & 11 deletions storybook/src/Models/TokenGroupsModel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -394,22 +394,76 @@ ListModel {
]

property bool skipInitialLoad: false
property bool fetchMode: false
property int fetchBatchSize: 15
property int fetchInitialCount: fetchBatchSize

property bool hasMoreItems: false
property bool isLoadingMore: false
property string searchKeyword: ""

property var tokenGroupsForChainModel // used for search only

property var _filteredItems: []

Component.onCompleted: {
if (!skipInitialLoad) {
append(data)
_filteredItems = data.slice()
_updateVisibleItems(Math.max(fetchInitialCount, 0))
}
}

property bool hasMoreItems: false
property bool isLoadingMore: false
function _relevanceScore(item, keywordLower) {
if (!keywordLower) {
return 0
}

property var tokenGroupsForChainModel // used for search only
const symbol = (item.symbol || "").toLowerCase()
const name = (item.name || "").toLowerCase()
const key = (item.key || "").toLowerCase()

if (symbol === keywordLower)
return 100
if (name === keywordLower)
return 95
if (symbol.startsWith(keywordLower))
return 90
if (name.startsWith(keywordLower))
return 85

const symbolIndex = symbol.indexOf(keywordLower)
if (symbolIndex > 0)
return 70 - Math.min(symbolIndex, 20)

const nameIndex = name.indexOf(keywordLower)
if (nameIndex > 0)
return 60 - Math.min(nameIndex, 20)

const keyIndex = key.indexOf(keywordLower)
if (keyIndex === 0)
return 50
if (keyIndex > 0)
return 40 - Math.min(keyIndex, 20)

return -1
}

function _updateVisibleItems(maxItemCount) {
clear()
const targetCount = fetchMode ? Math.min(maxItemCount, _filteredItems.length) : _filteredItems.length
for (let i = 0; i < targetCount; i++) {
append(_filteredItems[i])
}
hasMoreItems = count < _filteredItems.length
}

function search(keyword) {
clear() // clear the existing model
searchKeyword = (keyword || "").trim()
_filteredItems = []
clear()
hasMoreItems = false

if (!keyword || keyword.trim() === "") {
if (searchKeyword === "") {
return
}

Expand All @@ -418,17 +472,38 @@ ListModel {
return
}

const lowerKeyword = keyword.toLowerCase()
const keywordLower = searchKeyword.toLowerCase()
const scoredResults = []
for (let i = 0; i < tokenGroupsForChainModel.ModelCount.count; i++) {
const item = ModelUtils.get(tokenGroupsForChainModel, i)
const symbolMatch = item.symbol && item.symbol.toLowerCase().includes(lowerKeyword)
const nameMatch = item.name && item.name.toLowerCase().includes(lowerKeyword)
if (symbolMatch || nameMatch) {
append(item)
const score = _relevanceScore(item, keywordLower)
if (score >= 0) {
scoredResults.push({
score: score,
index: i,
item: item
})
}
}

scoredResults.sort((a, b) => {
if (a.score !== b.score)
return b.score - a.score
return a.index - b.index
})

_filteredItems = scoredResults.map(entry => entry.item)
_updateVisibleItems(Math.max(fetchInitialCount, 0))
}

function fetchMore() {
if (!fetchMode || isLoadingMore || !hasMoreItems) {
return
}

isLoadingMore = true
const nextVisibleCount = count + Math.max(fetchBatchSize, 1)
_updateVisibleItems(nextVisibleCount)
isLoadingMore = false
}
}