feat(@desktop/wallet): implement allCollectibles module

Fixes #13235
This commit is contained in:
Dario Gabriel Lipicar 2024-01-17 17:19:58 -03:00 committed by dlipicar
parent b186a133ab
commit 29f1bee218
17 changed files with 320 additions and 127 deletions

View File

@ -37,7 +37,20 @@ proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
discard
self.events.on(SIGNAL_WALLET_ACCOUNT_SAVED) do(e:Args):
self.delegate.refreshWalletAccounts()
self.events.on(SIGNAL_WALLET_ACCOUNT_DELETED) do(e:Args):
self.delegate.refreshWalletAccounts()
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args):
self.delegate.refreshNetworks()
proc getWalletAddresses*(self: Controller): seq[string] =
return self.walletAccountService.getWalletAddresses()
proc getChainIds*(self: Controller): seq[int] =
return self.networkService.getNetworks().map(n => n.chainId)
proc updateCollectiblePreferences*(self: Controller, tokenPreferencesJson: string) =
self.collectibleService.updateCollectiblePreferences(tokenPreferencesJson)

View File

@ -13,6 +13,15 @@ method load*(self: AccessInterface) {.base.} =
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getAllCollectiblesModel*(self: AccessInterface): collectibles_model.Model {.base.} =
raise newException(ValueError, "No implementation available")
method refreshNetworks*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method refreshWalletAccounts*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method updateCollectiblePreferences*(self: AccessInterface, collectiblePreferencesJson: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -23,6 +23,7 @@ type
events: EventEmitter
view: View
controller: all_collectibles_controller.Controller
collectiblesController: collectibles_controller.Controller
moduleLoaded: bool
proc newModule*(
@ -38,12 +39,21 @@ proc newModule*(
result.events = events
result.controller = all_collectibles_controller.newController(result, events, collectibleService, networkService, walletAccountService, settingsService)
let collectiblesController = collectibles_controller.newController(
requestId = int32(backend_collectibles.CollectiblesRequestID.AllCollectibles),
loadType = collectibles_controller.LoadType.AutoLoadSingleUpdate,
networkService = networkService,
events = events
)
result.collectiblesController = collectiblesController
result.view = newView(result)
result.moduleLoaded = false
method delete*(self: Module) =
self.view.delete
self.controller.delete
self.collectiblesController.delete
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("walletSectionAllCollectibles", newQVariant(self.view))
@ -58,10 +68,25 @@ method load*(self: Module) =
method isLoaded*(self: Module): bool =
return self.moduleLoaded
proc refreshCollectiblesFilter(self: Module) =
let addresses = self.controller.getWalletAddresses()
let chainIds = self.controller.getChainIds()
self.collectiblesController.setFilterAddressesAndChains(addresses, chainIds)
method viewDidLoad*(self: Module) =
self.refreshCollectiblesFilter()
self.moduleLoaded = true
self.delegate.allCollectiblesModuleDidLoad()
method getAllCollectiblesModel*(self: Module): collectibles_model.Model =
return self.collectiblesController.getModel()
method refreshNetworks*(self: Module) =
self.refreshCollectiblesFilter()
method refreshWalletAccounts*(self: Module) =
self.refreshCollectiblesFilter()
method updateCollectiblePreferences*(self: Module, collectiblePreferencesJson: string) {.slot.} =
self.controller.updateCollectiblePreferences(collectiblePreferencesJson)

View File

@ -2,10 +2,14 @@ import NimQml, sequtils, strutils, chronicles
import ./io_interface
import app/modules/shared_models/collectibles_model as collectibles_model
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
allCollectiblesModel: collectibles_model.Model
proc delete*(self: View) =
self.QObject.delete
@ -13,10 +17,16 @@ QtObject:
new(result, delete)
result.QObject.setup
result.delegate = delegate
result.allCollectiblesModel = delegate.getAllCollectiblesModel()
proc load*(self: View) =
self.delegate.viewDidLoad()
proc getAllCollectiblesModel(self: View): QVariant {.slot.} =
return newQVariant(self.allCollectiblesModel)
QtProperty[QVariant] allCollectiblesModel:
read = getAllCollectiblesModel
proc collectiblePreferencesUpdated*(self: View, result: bool) {.signal.}
proc updateCollectiblePreferences*(self: View, collectiblePreferencesJson: string) {.slot.} =

View File

@ -17,7 +17,7 @@ import ./send/module as send_module
import ./activity/controller as activityc
import ./wallet_connect/controller as wcc
import app/modules/shared_modules/collectibles/controller as collectiblesc
import app/modules/shared_models/collectibles_model as collectiblesm
import app/modules/shared_modules/collectible_details/controller as collectible_detailsc
import app/global/global_singleton
@ -81,7 +81,6 @@ type
devicesService: devices_service.Service
activityController: activityc.Controller
collectiblesController: collectiblesc.Controller
collectibleDetailsController: collectible_detailsc.Controller
# instance to be used in temporary, short-lived, workflows (e.g. send popup)
tmpActivityController: activityc.Controller
@ -121,7 +120,8 @@ proc newModule*(
result.accountsModule = accounts_module.newModule(result, events, walletAccountService, networkService, currencyService)
result.allTokensModule = all_tokens_module.newModule(result, events, tokenService, walletAccountService, settingsService)
result.allCollectiblesModule = all_collectibles_module.newModule(result, events, collectibleService, networkService, walletAccountService, settingsService)
let allCollectiblesModule = all_collectibles_module.newModule(result, events, collectibleService, networkService, walletAccountService, settingsService)
result.allCollectiblesModule = allCollectiblesModule
result.assetsModule = assets_module.newModule(result, events, walletAccountService, networkService, tokenService,
currencyService)
result.sendModule = send_module.newModule(result, events, walletAccountService, networkService, currencyService,
@ -133,15 +133,8 @@ proc newModule*(
result.networksService = networkService
result.transactionService = transactionService
let collectiblesController = collectiblesc.newController(
requestId = int32(backend_collectibles.CollectiblesRequestID.WalletAccount),
loadType = collectiblesc.LoadType.OnDemand,
networkService = networkService,
events = events
)
result.collectiblesController = collectiblesController
let collectiblesToTokenConverter = proc(id: string): backend_activity.Token =
return collectiblesController.getActivityToken(id)
return allCollectiblesModule.getAllCollectiblesModel().getActivityToken(id)
result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService, events, collectiblesToTokenConverter)
result.tmpActivityController = activityc.newController(int32(ActivityID.Temporary), currencyService, tokenService, events, collectiblesToTokenConverter)
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
@ -149,7 +142,7 @@ proc newModule*(
result.wcController = wcc.newController(events, walletAccountService)
result.view = newView(result, result.activityController, result.tmpActivityController, result.collectiblesController, result.collectibleDetailsController, result.wcController)
result.view = newView(result, result.activityController, result.tmpActivityController, result.collectibleDetailsController, result.wcController)
method delete*(self: Module) =
self.accountsModule.delete
@ -163,7 +156,6 @@ method delete*(self: Module) =
self.view.delete
self.activityController.delete
self.tmpActivityController.delete
self.collectiblesController.delete
self.collectibleDetailsController.delete
self.wcController.delete
@ -189,7 +181,6 @@ proc notifyFilterChanged(self: Module) =
self.accountsModule.filterChanged(self.filter.addresses, self.filter.chainIds)
self.sendModule.filterChanged(self.filter.addresses, self.filter.chainIds)
self.activityController.globalFilterChanged(self.filter.addresses, self.filter.allAddresses, self.filter.chainIds, self.filter.allChainsEnabled)
self.collectiblesController.setFilterAddressesAndChains(self.filter.addresses, self.filter.chainIds)
self.allTokensModule.filterChanged(self.filter.addresses)
self.view.setAddressFilters(self.filter.addresses.join(":"))
if self.filter.addresses.len > 0:

View File

@ -1,7 +1,6 @@
import NimQml, json
import ./activity/controller as activityc
import app/modules/shared_modules/collectibles/controller as collectiblesc
import app/modules/shared_modules/collectible_details/controller as collectible_detailsc
import ./io_interface
import ../../shared_models/currency_amount
@ -18,7 +17,6 @@ QtObject:
tmpSymbol: string # shouldn't be used anywhere except in prepare*/getPrepared* procs
activityController: activityc.Controller
tmpActivityController: activityc.Controller
collectiblesController: collectiblesc.Controller
collectibleDetailsController: collectible_detailsc.Controller
isNonArchivalNode: bool
keypairOperabilityForObservedAccount: string
@ -33,12 +31,11 @@ QtObject:
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface, activityController: activityc.Controller, tmpActivityController: activityc.Controller, collectiblesController: collectiblesc.Controller, collectibleDetailsController: collectible_detailsc.Controller, wcController: wcc.Controller): View =
proc newView*(delegate: io_interface.AccessInterface, activityController: activityc.Controller, tmpActivityController: activityc.Controller, collectibleDetailsController: collectible_detailsc.Controller, wcController: wcc.Controller): View =
new(result, delete)
result.delegate = delegate
result.activityController = activityController
result.tmpActivityController = tmpActivityController
result.collectiblesController = collectiblesController
result.collectibleDetailsController = collectibleDetailsController
result.wcController = wcController
@ -149,11 +146,6 @@ QtObject:
QtProperty[QVariant] activityController:
read = getActivityController
proc getCollectiblesController(self: View): QVariant {.slot.} =
return newQVariant(self.collectiblesController)
QtProperty[QVariant] collectiblesController:
read = getCollectiblesController
proc getCollectibleDetailsController(self: View): QVariant {.slot.} =
return newQVariant(self.collectibleDetailsController)
QtProperty[QVariant] collectibleDetailsController:

View File

@ -0,0 +1,72 @@
import NimQml, Tables, strutils, strformat
import backend/collectibles_types as backend
type
ModelRole {.pure.} = enum
AccountAddress = UserRole + 1,
Balance
TxTimestamp
QtObject:
type
OwnershipModel* = ref object of QAbstractListModel
items: seq[backend.AccountBalance]
proc delete(self: OwnershipModel) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: OwnershipModel) =
self.QAbstractListModel.setup
proc newOwnershipModel*(): OwnershipModel =
new(result, delete)
result.setup
proc `$`*(self: OwnershipModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""[{i}]:({$self.items[i]})"""
proc countChanged(self: OwnershipModel) {.signal.}
proc getCount(self: OwnershipModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: OwnershipModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: OwnershipModel): Table[int, string] =
{
ModelRole.AccountAddress.int:"accountAddress",
ModelRole.Balance.int:"balance",
ModelRole.TxTimestamp.int:"txTimestamp",
}.toTable
method data(self: OwnershipModel, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.AccountAddress:
result = newQVariant(item.address)
of ModelRole.Balance:
result = newQVariant($item.balance)
of ModelRole.TxTimestamp:
result = newQVariant(item.txTimestamp)
proc setItems*(self: OwnershipModel, items: seq[backend.AccountBalance]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()

View File

@ -1,8 +1,9 @@
import NimQml, json, strformat, sequtils, strutils, stint, strutils
import NimQml, json, strformat, sequtils, sugar, strutils, stint, strutils
import options
import backend/collectibles as backend
import collectible_trait_model
import collectible_ownership_model
import ../../../app_service/service/community_tokens/dto/community_token
const invalidTimestamp* = high(int)
@ -24,6 +25,7 @@ QtObject:
data: backend.Collectible
extradata: ExtraData
traits: TraitModel
ownership: OwnershipModel
proc setup(self: CollectiblesEntry) =
self.QObject.setup
@ -34,9 +36,13 @@ QtObject:
proc setData(self: CollectiblesEntry, data: backend.Collectible) =
self.data = data
self.traits = newTraitModel()
self.ownership = newOwnershipModel()
if isSome(data.collectibleData) and isSome(data.collectibleData.get().traits):
let traits = data.collectibleData.get().traits.get()
self.traits.setItems(traits)
if isSome(data.ownership):
let ownership = data.ownership.get()
self.ownership.setItems(ownership)
self.setup()
proc newCollectibleDetailsFullEntry*(data: backend.Collectible, extradata: ExtraData): CollectiblesEntry =
@ -51,6 +57,7 @@ QtObject:
result.id = id
result.extradata = extradata
result.traits = newTraitModel()
result.ownership = newOwnershipModel()
result.setup()
proc newCollectibleDetailsEmptyEntry*(): CollectiblesEntry =
@ -69,7 +76,8 @@ QtObject:
id:{self.id},
data:{self.data},
extradata:{self.extradata},
traits:{self.traits}
traits:{self.traits},
ownership:{self.ownership},
)"""
proc getCollectibleUniqueID*(self: CollectiblesEntry): backend.CollectibleUniqueID =
@ -241,33 +249,23 @@ QtObject:
read = getTraits
notify = traitsChanged
proc balanceChanged*(self: CollectiblesEntry) {.signal.}
proc getBalance*(self: CollectiblesEntry): UInt256 =
var balance: UInt256 = stint.u256(0)
if self.hasOwnership():
for item in self.getOwnership():
balance += item.balance
return balance
proc getBalanceAsString*(self: CollectiblesEntry): string {.slot.} =
return $self.getBalance()
QtProperty[string] balance:
read = getBalanceAsString
notify = balanceChanged
proc lastTxTimestampChanged*(self: CollectiblesEntry) {.signal.}
proc getLastTxTimestamp*(self: CollectiblesEntry): int =
var lastTxTimestamp = -1
if self.hasOwnership():
for item in self.getOwnership():
lastTxTimestamp = max(lastTxTimestamp, item.txTimestamp)
if lastTxTimestamp < 0:
lastTxTimestamp = invalidTimestamp
return lastTxTimestamp
QtProperty[int] lastTxTimestamp:
read = getLastTxTimestamp
notify = lastTxTimestampChanged
proc ownershipChanged*(self: CollectiblesEntry) {.signal.}
proc getOwnershipModel*(self: CollectiblesEntry): QVariant {.slot.} =
return newQVariant(self.ownership)
QtProperty[QVariant] ownership:
read = getOwnershipModel
notify = ownershipChanged
proc ownershipAddressesChanged*(self: CollectiblesEntry) {.signal.}
proc getOwnershipAddresses*(self: CollectiblesEntry): string {.slot.} =
if not self.hasOwnership():
return ""
return self.getOwnership().map(o => o.address).join(":")
QtProperty[string] ownershipAddresses:
read = getOwnershipAddresses
notify = ownershipAddressesChanged
proc communityIdChanged*(self: CollectiblesEntry) {.signal.}
proc getCommunityID*(self: CollectiblesEntry): string {.slot.} =
@ -355,8 +353,7 @@ QtObject:
self.collectionNameChanged()
self.collectionImageUrlChanged()
self.traitsChanged()
self.balanceChanged()
self.lastTxTimestampChanged()
# Ownership doesn't change with updated data
self.communityIdChanged()
self.communityNameChanged()
self.communityColorChanged()

View File

@ -23,8 +23,8 @@ type
CollectionName
CollectionSlug
IsLoading
Balance
LastTxTimestamp
Ownership
OwnershipAddresses
# Community-related roles
CommunityId
CommunityName
@ -162,8 +162,8 @@ QtObject:
CollectibleRole.CollectionName.int:"collectionName",
CollectibleRole.CollectionSlug.int:"collectionSlug",
CollectibleRole.IsLoading.int:"isLoading",
CollectibleRole.Balance.int:"balance",
CollectibleRole.LastTxTimestamp.int:"lastTxTimestamp",
CollectibleRole.Ownership.int:"ownership",
CollectibleRole.OwnershipAddresses.int:"ownershipAddresses",
CollectibleRole.CommunityId.int:"communityId",
CollectibleRole.CommunityName.int:"communityName",
CollectibleRole.CommunityColor.int:"communityColor",
@ -208,10 +208,10 @@ QtObject:
result = newQVariant(item.getCollectionSlug())
of CollectibleRole.IsLoading:
result = newQVariant(false)
of CollectibleRole.Balance:
result = newQVariant(item.getBalanceAsString())
of CollectibleRole.LastTxTimestamp:
result = newQVariant(item.getLastTxTimestamp())
of CollectibleRole.Ownership:
result = newQVariant(item.getOwnershipModel())
of CollectibleRole.OwnershipAddresses:
result = newQVariant(item.getOwnershipAddresses())
of CollectibleRole.CommunityId:
result = newQVariant(item.getCommunityId())
of CollectibleRole.CommunityName:
@ -247,8 +247,7 @@ QtObject:
of "collectionName": result = item.getCollectionName()
of "collectionSlug": result = item.getCollectionSlug()
of "isLoading": result = $false
of "balance": result = item.getBalanceAsString()
of "lastTxTimestamp": result = $item.getLastTxTimestamp()
of "ownershipAddresses": result = item.getOwnershipAddresses()
of "communityId": result = item.getCommunityID()
of "communityName": result = item.getCommunityName()
of "communityColor": result = item.getCommunityColor()

View File

@ -120,7 +120,7 @@ QtObject:
self.checkModelState()
proc loadMoreItems(self: Controller) {.slot.} =
proc loadMoreItems(self: Controller) =
if self.model.getIsFetching():
return
@ -142,6 +142,11 @@ QtObject:
self.fetchFromStart = true
error "error fetching collectibles entries: ", response.error
proc onModelLoadMoreItems(self: Controller) {.slot.} =
if self.loadType.isAutoLoad():
return
self.loadMoreItems()
proc getExtraData(self: Controller, chainID: int): ExtraData =
let network = self.networkService.getNetwork(chainID)
return getExtraData(network)
@ -273,7 +278,7 @@ QtObject:
result.setupEventHandlers()
signalConnect(result.model, "loadMoreItems()", result, "loadMoreItems()")
signalConnect(result.model, "loadMoreItems()", result, "onModelLoadMoreItems()")
proc setFilterAddressesAndChains*(self: Controller, addresses: seq[string], chainIds: seq[int]) =
if chainIds == self.chainIds and addresses == self.addresses:
@ -296,6 +301,3 @@ QtObject:
self.filter = filter
self.resetModel()
proc getActivityToken*(self: Controller, id: string): backend_activity.Token =
return self.model.getActivityToken(id)

View File

@ -13,6 +13,7 @@ type
WalletAccount
ProfileShowcase
WalletSend
AllCollectibles
# Declared in services/wallet/collectibles/service.go
const eventCollectiblesOwnershipUpdateStarted*: string = "wallet-collectibles-ownership-update-started"

View File

@ -2,7 +2,9 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import mainui 1.0
import utils 1.0
@ -33,11 +35,34 @@ SplitView {
communityTokensStore: QtObject {}
}
QtObject {
id: d
readonly property string networksChainsCurrentlySelected: {
let supportNwChains = ":"
for (let i =0; i< networksRepeater.count; i++) {
if (networksRepeater.itemAt(i).checked && networksRepeater.itemAt(i).visible)
supportNwChains += networksRepeater.itemAt(i).chainID + ":"
}
return supportNwChains
}
readonly property string addressesSelected: {
let supportedAddresses = ""
for (let i =0; i< accountsRepeater.count; i++) {
if (accountsRepeater.itemAt(i).checked && accountsRepeater.itemAt(i).visible)
supportedAddresses += accountsRepeater.itemAt(i).address + ":"
}
return supportedAddresses
}
}
CollectiblesView {
id: assetsView
SplitView.preferredWidth: 600
SplitView.fillHeight: true
collectiblesModel: collectiblesModel
networkFilters: d.networksChainsCurrentlySelected
addressFilters: d.addressesSelected
filterVisible: ctrlFilterVisible.checked
onCollectibleClicked: logs.logEvent("onCollectibleClicked", ["chainId", "contractAddress", "tokenId", "uid"], arguments)
onSendRequested: logs.logEvent("onSendRequested", ["symbol"], arguments)
@ -46,15 +71,14 @@ SplitView {
onManageTokensRequested: logs.logEvent("onManageTokensRequested")
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumWidth: 150
SplitView.preferredWidth: 250
logsView.logText: logs.logText
Pane {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
ColumnLayout {
spacing: 12
anchors.fill: parent
Switch {
id: ctrlFilterVisible
text: "Filter visible"
@ -70,8 +94,62 @@ SplitView {
text: "Community collectibles"
checked: true
}
CheckBox {
id: loadingCheckbox
checked: false
text: "loading"
}
ColumnLayout {
Layout.fillWidth: true
Text {
text: "select supported network(s)"
}
Repeater {
id: networksRepeater
model: NetworksModel.allNetworks
delegate: CheckBox {
property int chainID: chainId
width: parent.width
text: chainName
visible: isTest
checked: true
onToggled: {
isEnabled = checked
}
}
}
}
ColumnLayout {
Layout.fillWidth: true
Text {
text: "select account(s)"
}
Repeater {
id: accountsRepeater
model: WalletAccountsModel {}
delegate: CheckBox {
property string address: model.address
checked: true
visible: index<2
width: parent.width
text: name
}
}
}
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumWidth: 150
SplitView.preferredWidth: 250
logsView.logText: logs.logText
}
}
// category: Views

View File

@ -20,6 +20,7 @@ ListModel {
readonly property var data: [
{
uid: "123",
chainId: 5,
name: "Punx not dead!",
collectionUid: "",
collectionName: "",
@ -28,10 +29,12 @@ ListModel {
communityImage: "",
imageUrl: ModelsData.collectibles.cryptoPunks,
isLoading: false,
backgroundColor: ""
backgroundColor: "",
ownershipAddresses: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240:0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881"
},
{
uid: "pp23",
chainId: 5,
name: "pepepunk#23",
collectionUid: "pepepunks",
collectionName: "Pepepunks",
@ -40,10 +43,12 @@ ListModel {
communityImage: "",
imageUrl: "https://i.seadn.io/s/raw/files/ba2811bb5cd0bed67529d69fa92ef5aa.jpg?auto=format&dpr=1&w=1000",
isLoading: false,
backgroundColor: ""
backgroundColor: "",
ownershipAddresses: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
},
{
uid: "34545656768",
chainId: 420,
name: "Kitty 1",
collectionUid: "KT",
collectionName: "Kitties",
@ -52,10 +57,12 @@ ListModel {
communityImage: "",
imageUrl: ModelsData.collectibles.kitty1Big,
isLoading: true,
backgroundColor: ""
backgroundColor: "",
ownershipAddresses: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881"
},
{
uid: "123456",
chainId: 420,
name: "Kitty 2",
collectionUid: "KT",
collectionName: "Kitties",
@ -64,10 +71,12 @@ ListModel {
communityImage: "",
imageUrl: ModelsData.collectibles.kitty2Big,
isLoading: false,
backgroundColor: ""
backgroundColor: "",
ownershipAddresses: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
},
{
uid: "12345645459537432",
chainId: 421613,
name: "Big Kitty",
collectionUid: "KT",
collectionName: "Kitties",
@ -76,10 +85,12 @@ ListModel {
communityImage: "",
imageUrl: ModelsData.collectibles.kitty3Big,
isLoading: false,
backgroundColor: ""
backgroundColor: "",
ownershipAddresses: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240:0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881"
},
{
uid: "pp21",
chainId: 421613,
name: "pepepunk#21",
collectionUid: "pepepunks",
collectionName: "Pepepunks",
@ -88,10 +99,12 @@ ListModel {
communityImage: "",
imageUrl: "https://i.seadn.io/s/raw/files/cfa559bb63e4378f17649c1e3b8f18fe.jpg?auto=format&dpr=1&w=1000",
isLoading: false,
backgroundColor: ""
backgroundColor: "",
ownershipAddresses: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881"
},
{
uid: "lp#666a",
chainId: 421613,
name: "Lonely Panda #666",
collectionUid: "lpan_collection",
collectionName: "Lonely Panda Collection",
@ -100,7 +113,8 @@ ListModel {
communityImage: "",
imageUrl: "",
isLoading: false,
backgroundColor: "pink"
backgroundColor: "pink",
ownershipAddresses: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
},
]

View File

@ -277,9 +277,7 @@ SettingsContentBase {
tokensListModel: tokensStore.extendedFlatTokensModel
baseWalletAssetsModel: RootStore.assets
baseWalletCollectiblesModel: {
RootStore.setFillterAllAddresses() // FIXME no other way to get _all_ collectibles?
// TODO concat proxy model to include community collectibles (#12519)
return RootStore.collectiblesStore.ownedCollectibles
return RootStore.collectiblesStore.allCollectiblesModel
}
Binding on currentIndex {

View File

@ -4,19 +4,19 @@ import utils 1.0
QtObject {
id: root
readonly property var ownedCollectibles: Global.appIsReady ? walletSection.collectiblesController.model : null
/* PRIVATE: Modules used to get data from backend */
readonly property var _allCollectiblesModule: !!walletSectionAllCollectibles ? walletSectionAllCollectibles : null
/* This list contains the complete list of collectibles with separate
entry per collectible which has a unique [network + contractAddress + tokenID] */
readonly property var allCollectiblesModel: !!root._allCollectiblesModule ? root._allCollectiblesModule.allCollectiblesModel : null
/* The following are used to display the detailed view of a collectible */
readonly property var detailedCollectible: Global.appIsReady ? walletSection.collectibleDetailsController.detailedEntry : null
readonly property var detailedCollectibleStatus: Global.appIsReady ? walletSection.collectibleDetailsController.status : null
readonly property bool isDetailedCollectibleLoading: Global.appIsReady ? walletSection.collectibleDetailsController.isDetailedEntryLoading : true
function fetchMoreCollectibles() {
if (!root.ownedCollectibles.hasMore
|| root.ownedCollectibes.isFetching)
return
walletSection.collectiblesController.loadMoreItems()
}
function getDetailedCollectible(chainId, contractAddress, tokenId) {
walletSection.collectibleDetailsController.getDetailedCollectible(chainId, contractAddress, tokenId)
}

View File

@ -28,6 +28,8 @@ ColumnLayout {
id: root
required property var collectiblesModel
required property string addressFilters
required property string networkFilters
property bool sendEnabled: true
property bool filterVisible
@ -67,10 +69,22 @@ ColumnLayout {
sourceModel: d.renamedModel
}
readonly property var nwFilters: root.networkFilters.split(":")
readonly property var addrFilters: root.addressFilters.split(":").map((addr) => addr.toLowerCase())
function hideAllCommunityTokens(communityId) {
const tokenSymbols = ModelUtils.getAll(communityCollectiblesView.model, "symbol", "communityId", communityId)
d.controller.settingsHideCommunityTokens(communityId, tokenSymbols)
}
function containsAny(list, filterList) {
for (let i = 0; i < list.length; i++) {
if (filterList.includes(list[i].toLowerCase())) {
return true
}
}
return false
}
}
component CustomSFPM: SortFilterProxyModel {
@ -83,6 +97,13 @@ ColumnLayout {
roleNames: ["collectionName", "communityName"]
}
filters: [
FastExpressionFilter {
expression: {
d.addrFilters
return d.nwFilters.includes(model.chainId+"") && d.containsAny(model.ownershipAddresses.split(":"), d.addrFilters)
}
expectedRoles: ["chainId", "ownershipAddresses"]
},
FastExpressionFilter {
expression: {
d.controller.settingsDirty
@ -269,37 +290,6 @@ ColumnLayout {
cellWidth: d.cellWidth
delegate: collectibleDelegate
// For some reason fetchMore is not working properly.
// Adding some logic here as a workaround.
visibleArea.onYPositionChanged: checkLoadMore()
visibleArea.onHeightRatioChanged: checkLoadMore()
Connections {
target: gridView
function onVisibleChanged() {
gridView.checkLoadMore()
}
}
Connections {
target: root.collectiblesModel
function onHasMoreChanged() {
gridView.checkLoadMore()
}
function onIsFetchingChanged() {
gridView.checkLoadMore()
}
}
function checkLoadMore() {
// If there is no more items to load or we're already fetching, return
if (!gridView.visible || !root.collectiblesModel.hasMore || root.collectiblesModel.isFetching)
return
// Only trigger if close to the bottom of the list
if (visibleArea.yPosition + visibleArea.heightRatio > 0.9)
root.collectiblesModel.loadMore()
}
}
Component {

View File

@ -156,7 +156,9 @@ RightTabBaseView {
}
CollectiblesView {
collectiblesModel: RootStore.collectiblesStore.ownedCollectibles
collectiblesModel: RootStore.collectiblesStore.allCollectiblesModel
networkFilters: RootStore.networkFilters
addressFilters: RootStore.addressFilters
sendEnabled: root.networkConnectionStore.sendBuyBridgeEnabled && !RootStore.overview.isWatchOnlyAccount && RootStore.overview.canSend
filterVisible: filterButton.checked
onCollectibleClicked: {