feat(@desktop/wallet): implement nested collectibles model
Part of #12072
This commit is contained in:
parent
61f3d903ce
commit
bad497cc90
|
@ -42,7 +42,11 @@ proc newModule*(
|
||||||
result.view = newView(result)
|
result.view = newView(result)
|
||||||
result.viewVariant = newQVariant(result.view)
|
result.viewVariant = newQVariant(result.view)
|
||||||
result.controller = accountsc.newController(result, walletAccountService)
|
result.controller = accountsc.newController(result, walletAccountService)
|
||||||
result.collectiblesController = collectiblesc.newController(int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase), events)
|
result.collectiblesController = collectiblesc.newController(
|
||||||
|
requestId = int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase),
|
||||||
|
autofetch = false,
|
||||||
|
events = events
|
||||||
|
)
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
## Forward declarations
|
## Forward declarations
|
||||||
|
@ -58,7 +62,7 @@ method getModuleAsVariant*(self: Module): QVariant =
|
||||||
return self.viewVariant
|
return self.viewVariant
|
||||||
|
|
||||||
method getCollectiblesModel*(self: Module): QVariant =
|
method getCollectiblesModel*(self: Module): QVariant =
|
||||||
return self.collectiblesController.getModel()
|
return self.collectiblesController.getModelAsVariant()
|
||||||
|
|
||||||
method convertWalletAccountDtoToKeyPairAccountItem(self: Module, account: WalletAccountDto): KeyPairAccountItem =
|
method convertWalletAccountDtoToKeyPairAccountItem(self: Module, account: WalletAccountDto): KeyPairAccountItem =
|
||||||
result = newKeyPairAccountItem(
|
result = newKeyPairAccountItem(
|
||||||
|
|
|
@ -122,7 +122,11 @@ proc newModule*(
|
||||||
result.transactionService = transactionService
|
result.transactionService = transactionService
|
||||||
result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService, events)
|
result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService, events)
|
||||||
result.tmpActivityController = activityc.newController(int32(ActivityID.Temporary), currencyService, tokenService, events)
|
result.tmpActivityController = activityc.newController(int32(ActivityID.Temporary), currencyService, tokenService, events)
|
||||||
result.collectiblesController = collectiblesc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), events)
|
result.collectiblesController = collectiblesc.newController(
|
||||||
|
requestId = int32(backend_collectibles.CollectiblesRequestID.WalletAccount),
|
||||||
|
autofetch = false,
|
||||||
|
events = events
|
||||||
|
)
|
||||||
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
|
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
|
||||||
result.filter = initFilter(result.controller)
|
result.filter = initFilter(result.controller)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import stint
|
import stint
|
||||||
import ../../../shared_models/currency_amount
|
import ../../../shared_models/currency_amount
|
||||||
import app_service/service/transaction/dto
|
import app_service/service/transaction/dto
|
||||||
|
import app/modules/shared_models/collectibles_model as collectibles
|
||||||
|
import app/modules/shared_models/collectibles_nested_model as nested_collectibles
|
||||||
|
|
||||||
type
|
type
|
||||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||||
|
@ -57,3 +59,9 @@ method setSelectedReceiveAccountIndex*(self: AccessInterface, index: int) =
|
||||||
|
|
||||||
method filterChanged*(self: AccessInterface, addresses: seq[string], chainIds: seq[int]) =
|
method filterChanged*(self: AccessInterface, addresses: seq[string], chainIds: seq[int]) =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getCollectiblesModel*(self: AccessInterface): collectibles.Model =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method getNestedCollectiblesModel*(self: AccessInterface): nested_collectibles.Model =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
|
@ -13,6 +13,11 @@ import app/modules/shared/wallet_utils
|
||||||
import app_service/service/transaction/dto
|
import app_service/service/transaction/dto
|
||||||
import app/modules/shared_models/currency_amount
|
import app/modules/shared_models/currency_amount
|
||||||
|
|
||||||
|
import app/modules/shared_modules/collectibles/controller as collectiblesc
|
||||||
|
import app/modules/shared_models/collectibles_model as collectibles
|
||||||
|
import app/modules/shared_models/collectibles_nested_model as nested_collectibles
|
||||||
|
import backend/collectibles as backend_collectibles
|
||||||
|
|
||||||
export io_interface
|
export io_interface
|
||||||
|
|
||||||
const cancelledRequest* = "cancelled"
|
const cancelledRequest* = "cancelled"
|
||||||
|
@ -31,7 +36,10 @@ type
|
||||||
delegate: delegate_interface.AccessInterface
|
delegate: delegate_interface.AccessInterface
|
||||||
events: EventEmitter
|
events: EventEmitter
|
||||||
view: View
|
view: View
|
||||||
controller: Controller
|
controller: controller.Controller
|
||||||
|
# Get the list of owned collectibles by the currently selected account
|
||||||
|
collectiblesController: collectiblesc.Controller
|
||||||
|
nestedCollectiblesModel: nested_collectibles.Model
|
||||||
moduleLoaded: bool
|
moduleLoaded: bool
|
||||||
tmpSendTransactionDetails: TmpSendTransactionDetails
|
tmpSendTransactionDetails: TmpSendTransactionDetails
|
||||||
senderCurrentAccountIndex: int
|
senderCurrentAccountIndex: int
|
||||||
|
@ -52,8 +60,15 @@ proc newModule*(
|
||||||
result = Module()
|
result = Module()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.events = events
|
result.events = events
|
||||||
result.view = newView(result)
|
|
||||||
result.controller = controller.newController(result, events, walletAccountService, networkService, currencyService, transactionService)
|
result.controller = controller.newController(result, events, walletAccountService, networkService, currencyService, transactionService)
|
||||||
|
result.collectiblesController = collectiblesc.newController(
|
||||||
|
requestId = int32(backend_collectibles.CollectiblesRequestID.WalletSend),
|
||||||
|
autofetch = true,
|
||||||
|
events = events
|
||||||
|
)
|
||||||
|
result.nestedCollectiblesModel = nested_collectibles.newModel(result.collectiblesController.getModel())
|
||||||
|
result.view = newView(result)
|
||||||
|
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
result.senderCurrentAccountIndex = 0
|
result.senderCurrentAccountIndex = 0
|
||||||
result.receiveCurrentAccountIndex = 0
|
result.receiveCurrentAccountIndex = 0
|
||||||
|
@ -61,6 +76,8 @@ proc newModule*(
|
||||||
method delete*(self: Module) =
|
method delete*(self: Module) =
|
||||||
self.view.delete
|
self.view.delete
|
||||||
self.controller.delete
|
self.controller.delete
|
||||||
|
self.nestedCollectiblesModel.delete
|
||||||
|
self.collectiblesController.delete
|
||||||
|
|
||||||
method convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): NetworkItem =
|
method convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): NetworkItem =
|
||||||
result = initNetworkItem(
|
result = initNetworkItem(
|
||||||
|
@ -297,8 +314,21 @@ method filterChanged*(self: Module, addresses: seq[string], chainIds: seq[int])
|
||||||
self.view.switchSenderAccountByAddress(addresses[0])
|
self.view.switchSenderAccountByAddress(addresses[0])
|
||||||
self.view.switchReceiveAccountByAddress(addresses[0])
|
self.view.switchReceiveAccountByAddress(addresses[0])
|
||||||
|
|
||||||
|
proc updateCollectiblesFilter*(self: Module) =
|
||||||
|
let addresses = @[self.view.getSenderAddressByIndex(self.senderCurrentAccountIndex)]
|
||||||
|
let chainIds = self.controller.getChainIds()
|
||||||
|
self.collectiblesController.globalFilterChanged(addresses, chainIds)
|
||||||
|
|
||||||
method setSelectedSenderAccountIndex*(self: Module, index: int) =
|
method setSelectedSenderAccountIndex*(self: Module, index: int) =
|
||||||
self.senderCurrentAccountIndex = index
|
self.senderCurrentAccountIndex = index
|
||||||
|
self.updateCollectiblesFilter()
|
||||||
|
|
||||||
method setSelectedReceiveAccountIndex*(self: Module, index: int) =
|
method setSelectedReceiveAccountIndex*(self: Module, index: int) =
|
||||||
self.receiveCurrentAccountIndex = index
|
self.receiveCurrentAccountIndex = index
|
||||||
|
|
||||||
|
method getCollectiblesModel*(self: Module): collectibles.Model =
|
||||||
|
return self.collectiblesController.getModel()
|
||||||
|
|
||||||
|
method getNestedCollectiblesModel*(self: Module): nested_collectibles.Model =
|
||||||
|
return self.nestedCollectiblesModel
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ import NimQml, sequtils, strutils, stint, sugar
|
||||||
|
|
||||||
import ./io_interface, ./accounts_model, ./account_item, ./network_model, ./network_item, ./suggested_route_item, ./transaction_routes
|
import ./io_interface, ./accounts_model, ./account_item, ./network_model, ./network_item, ./suggested_route_item, ./transaction_routes
|
||||||
import app/modules/shared_models/token_model
|
import app/modules/shared_models/token_model
|
||||||
|
import app/modules/shared_models/collectibles_model as collectibles
|
||||||
|
import app/modules/shared_models/collectibles_nested_model as nested_collectibles
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -10,6 +12,9 @@ QtObject:
|
||||||
accounts: AccountsModel
|
accounts: AccountsModel
|
||||||
# this one doesn't include watch accounts and its what the user switches when using the sendModal
|
# this one doesn't include watch accounts and its what the user switches when using the sendModal
|
||||||
senderAccounts: AccountsModel
|
senderAccounts: AccountsModel
|
||||||
|
# list of collectibles owned by the selected sender account
|
||||||
|
collectiblesModel: collectibles.Model
|
||||||
|
nestedCollectiblesModel: nested_collectibles.Model
|
||||||
# for send modal
|
# for send modal
|
||||||
selectedSenderAccount: AccountItem
|
selectedSenderAccount: AccountItem
|
||||||
fromNetworksModel: NetworkModel
|
fromNetworksModel: NetworkModel
|
||||||
|
@ -43,6 +48,8 @@ QtObject:
|
||||||
result.fromNetworksModel = newNetworkModel()
|
result.fromNetworksModel = newNetworkModel()
|
||||||
result.toNetworksModel = newNetworkModel()
|
result.toNetworksModel = newNetworkModel()
|
||||||
result.transactionRoutes = newTransactionRoutes()
|
result.transactionRoutes = newTransactionRoutes()
|
||||||
|
result.collectiblesModel = delegate.getCollectiblesModel()
|
||||||
|
result.nestedCollectiblesModel = delegate.getNestedCollectiblesModel()
|
||||||
|
|
||||||
proc load*(self: View) =
|
proc load*(self: View) =
|
||||||
self.delegate.viewDidLoad()
|
self.delegate.viewDidLoad()
|
||||||
|
@ -61,6 +68,20 @@ QtObject:
|
||||||
read = getSenderAccounts
|
read = getSenderAccounts
|
||||||
notify = senderAccountsChanged
|
notify = senderAccountsChanged
|
||||||
|
|
||||||
|
proc collectiblesModelChanged*(self: View) {.signal.}
|
||||||
|
proc getCollectiblesModel(self: View): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.collectiblesModel)
|
||||||
|
QtProperty[QVariant] collectiblesModel:
|
||||||
|
read = getCollectiblesModel
|
||||||
|
notify = collectiblesModelChanged
|
||||||
|
|
||||||
|
proc nestedCollectiblesModelChanged*(self: View) {.signal.}
|
||||||
|
proc getNestedCollectiblesModel(self: View): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.nestedCollectiblesModel)
|
||||||
|
QtProperty[QVariant] nestedCollectiblesModel:
|
||||||
|
read = getNestedCollectiblesModel
|
||||||
|
notify = nestedCollectiblesModelChanged
|
||||||
|
|
||||||
proc selectedSenderAccountChanged*(self: View) {.signal.}
|
proc selectedSenderAccountChanged*(self: View) {.signal.}
|
||||||
proc getSelectedSenderAccount(self: View): QVariant {.slot.} =
|
proc getSelectedSenderAccount(self: View): QVariant {.slot.} =
|
||||||
return newQVariant(self.selectedSenderAccount)
|
return newQVariant(self.selectedSenderAccount)
|
||||||
|
@ -72,6 +93,9 @@ QtObject:
|
||||||
read = getSelectedSenderAccount
|
read = getSelectedSenderAccount
|
||||||
notify = selectedSenderAccountChanged
|
notify = selectedSenderAccountChanged
|
||||||
|
|
||||||
|
proc getSenderAddressByIndex*(self: View, index: int): string {.slot.} =
|
||||||
|
return self.senderAccounts.getItemByIndex(index).address()
|
||||||
|
|
||||||
proc selectedReceiveAccountChanged*(self: View) {.signal.}
|
proc selectedReceiveAccountChanged*(self: View) {.signal.}
|
||||||
proc getSelectedReceiveAccount(self: View): QVariant {.slot.} =
|
proc getSelectedReceiveAccount(self: View): QVariant {.slot.} =
|
||||||
return newQVariant(self.selectedReceiveAccount)
|
return newQVariant(self.selectedReceiveAccount)
|
||||||
|
|
|
@ -11,6 +11,8 @@ type
|
||||||
imageUrl: string
|
imageUrl: string
|
||||||
backgroundColor: string
|
backgroundColor: string
|
||||||
collectionName: string
|
collectionName: string
|
||||||
|
collectionSlug: string
|
||||||
|
collectionImageUrl: string
|
||||||
isLoading: bool
|
isLoading: bool
|
||||||
isPinned: bool
|
isPinned: bool
|
||||||
|
|
||||||
|
@ -24,6 +26,8 @@ proc initItem*(
|
||||||
imageUrl: string,
|
imageUrl: string,
|
||||||
backgroundColor: string,
|
backgroundColor: string,
|
||||||
collectionName: string,
|
collectionName: string,
|
||||||
|
collectionSlug: string,
|
||||||
|
collectionImageUrl: string,
|
||||||
isPinned: bool
|
isPinned: bool
|
||||||
): Item =
|
): Item =
|
||||||
result.chainId = chainId
|
result.chainId = chainId
|
||||||
|
@ -35,11 +39,13 @@ proc initItem*(
|
||||||
result.imageUrl = imageUrl
|
result.imageUrl = imageUrl
|
||||||
result.backgroundColor = if (backgroundColor == ""): "transparent" else: ("#" & backgroundColor)
|
result.backgroundColor = if (backgroundColor == ""): "transparent" else: ("#" & backgroundColor)
|
||||||
result.collectionName = collectionName
|
result.collectionName = collectionName
|
||||||
|
result.collectionSlug = collectionSlug
|
||||||
|
result.collectionImageUrl = collectionImageUrl
|
||||||
result.isLoading = false
|
result.isLoading = false
|
||||||
result.isPinned = isPinned
|
result.isPinned = isPinned
|
||||||
|
|
||||||
proc initItem*: Item =
|
proc initItem*: Item =
|
||||||
result = initItem(0, "", u256(0), "", "", "", "", "transparent", "Collectibles", false)
|
result = initItem(0, "", u256(0), "", "", "", "", "transparent", "Collectibles", "", "", false)
|
||||||
|
|
||||||
proc initLoadingItem*: Item =
|
proc initLoadingItem*: Item =
|
||||||
result = initItem()
|
result = initItem()
|
||||||
|
@ -56,6 +62,8 @@ proc `$`*(self: Item): string =
|
||||||
imageUrl: {self.imageUrl},
|
imageUrl: {self.imageUrl},
|
||||||
backgroundColor: {self.backgroundColor},
|
backgroundColor: {self.backgroundColor},
|
||||||
collectionName: {self.collectionName},
|
collectionName: {self.collectionName},
|
||||||
|
collectionSlug: {self.collectionSlug},
|
||||||
|
collectionImageUrl: {self.collectionImageUrl},
|
||||||
isLoading: {self.isLoading},
|
isLoading: {self.isLoading},
|
||||||
isPinned: {self.isPinned},
|
isPinned: {self.isPinned},
|
||||||
]"""
|
]"""
|
||||||
|
@ -88,9 +96,19 @@ proc getImageUrl*(self: Item): string =
|
||||||
proc getBackgroundColor*(self: Item): string =
|
proc getBackgroundColor*(self: Item): string =
|
||||||
return self.backgroundColor
|
return self.backgroundColor
|
||||||
|
|
||||||
|
# Unique ID to identify collection, generated by us
|
||||||
|
proc getCollectionId*(self: Item): string =
|
||||||
|
return fmt"{self.getChainId}+{self.getContractAddress}"
|
||||||
|
|
||||||
proc getCollectionName*(self: Item): string =
|
proc getCollectionName*(self: Item): string =
|
||||||
return self.collectionName
|
return self.collectionName
|
||||||
|
|
||||||
|
proc getCollectionSlug*(self: Item): string =
|
||||||
|
return self.collectionSlug
|
||||||
|
|
||||||
|
proc getCollectionImageUrl*(self: Item): string =
|
||||||
|
return self.collectionImageUrl
|
||||||
|
|
||||||
proc getIsLoading*(self: Item): bool =
|
proc getIsLoading*(self: Item): bool =
|
||||||
return self.isLoading
|
return self.isLoading
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@ type
|
||||||
MediaUrl
|
MediaUrl
|
||||||
MediaType
|
MediaType
|
||||||
BackgroundColor
|
BackgroundColor
|
||||||
|
CollectionUid
|
||||||
CollectionName
|
CollectionName
|
||||||
|
CollectionSlug
|
||||||
IsLoading
|
IsLoading
|
||||||
IsPinned
|
IsPinned
|
||||||
|
|
||||||
|
@ -145,7 +147,9 @@ QtObject:
|
||||||
CollectibleRole.MediaType.int:"mediaType",
|
CollectibleRole.MediaType.int:"mediaType",
|
||||||
CollectibleRole.ImageUrl.int:"imageUrl",
|
CollectibleRole.ImageUrl.int:"imageUrl",
|
||||||
CollectibleRole.BackgroundColor.int:"backgroundColor",
|
CollectibleRole.BackgroundColor.int:"backgroundColor",
|
||||||
|
CollectibleRole.CollectionUid.int:"collectionUid",
|
||||||
CollectibleRole.CollectionName.int:"collectionName",
|
CollectibleRole.CollectionName.int:"collectionName",
|
||||||
|
CollectibleRole.CollectionSlug.int:"collectionSlug",
|
||||||
CollectibleRole.IsLoading.int:"isLoading",
|
CollectibleRole.IsLoading.int:"isLoading",
|
||||||
CollectibleRole.IsPinned.int:"isPinned",
|
CollectibleRole.IsPinned.int:"isPinned",
|
||||||
}.toTable
|
}.toTable
|
||||||
|
@ -180,8 +184,12 @@ QtObject:
|
||||||
result = newQVariant(item.getImageUrl())
|
result = newQVariant(item.getImageUrl())
|
||||||
of CollectibleRole.BackgroundColor:
|
of CollectibleRole.BackgroundColor:
|
||||||
result = newQVariant(item.getBackgroundColor())
|
result = newQVariant(item.getBackgroundColor())
|
||||||
|
of CollectibleRole.CollectionUid:
|
||||||
|
result = newQVariant(item.getCollectionId())
|
||||||
of CollectibleRole.CollectionName:
|
of CollectibleRole.CollectionName:
|
||||||
result = newQVariant(item.getCollectionName())
|
result = newQVariant(item.getCollectionName())
|
||||||
|
of CollectibleRole.CollectionSlug:
|
||||||
|
result = newQVariant(item.getCollectionSlug())
|
||||||
of CollectibleRole.IsLoading:
|
of CollectibleRole.IsLoading:
|
||||||
result = newQVariant(false)
|
result = newQVariant(false)
|
||||||
of CollectibleRole.IsPinned:
|
of CollectibleRole.IsPinned:
|
||||||
|
@ -195,6 +203,26 @@ QtObject:
|
||||||
error "Invalid role for loading item"
|
error "Invalid role for loading item"
|
||||||
result = newQVariant()
|
result = newQVariant()
|
||||||
|
|
||||||
|
proc rowData(self: Model, index: int, column: string): string {.slot.} =
|
||||||
|
if (index >= self.items.len):
|
||||||
|
return
|
||||||
|
let item = self.items[index]
|
||||||
|
case column:
|
||||||
|
of "uid": result = item.getId()
|
||||||
|
of "chainId": result = $item.getChainId()
|
||||||
|
of "contractAddress": result = item.getContractAddress()
|
||||||
|
of "tokenId": result = item.getTokenId().toString()
|
||||||
|
of "name": result = item.getName()
|
||||||
|
of "mediaUrl": result = item.getMediaUrl()
|
||||||
|
of "mediaType": result = item.getMediaType()
|
||||||
|
of "imageUrl": result = item.getImageUrl()
|
||||||
|
of "backgroundColor": result = item.getBackgroundColor()
|
||||||
|
of "collectionUid": result = item.getCollectionId()
|
||||||
|
of "collectionName": result = item.getCollectionName()
|
||||||
|
of "collectionSlug": result = item.getCollectionSlug()
|
||||||
|
of "isLoading": result = $false
|
||||||
|
of "isPinned": result = $item.getIsPinned()
|
||||||
|
|
||||||
proc appendCollectibleItems(self: Model, newItems: seq[Item]) =
|
proc appendCollectibleItems(self: Model, newItems: seq[Item]) =
|
||||||
if len(newItems) == 0:
|
if len(newItems) == 0:
|
||||||
return
|
return
|
||||||
|
@ -271,6 +299,9 @@ QtObject:
|
||||||
else:
|
else:
|
||||||
self.removeLoadingItems()
|
self.removeLoadingItems()
|
||||||
|
|
||||||
|
proc getItems*(self: Model): seq[Item] =
|
||||||
|
return self.items
|
||||||
|
|
||||||
proc setItems*(self: Model, newItems: seq[Item], offset: int, hasMore: bool) =
|
proc setItems*(self: Model, newItems: seq[Item], offset: int, hasMore: bool) =
|
||||||
if offset == 0:
|
if offset == 0:
|
||||||
self.removeCollectibleItems()
|
self.removeCollectibleItems()
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import strformat, stint
|
||||||
|
|
||||||
|
type
|
||||||
|
Item* = object
|
||||||
|
id: string # Collectible ID if isCollection=false, Collection Slug otherwise
|
||||||
|
chainId: int
|
||||||
|
name: string
|
||||||
|
iconUrl: string
|
||||||
|
collectionId: string
|
||||||
|
collectionName: string
|
||||||
|
isCollection: bool
|
||||||
|
|
||||||
|
proc initItem*(
|
||||||
|
id: string,
|
||||||
|
chainId: int,
|
||||||
|
name: string,
|
||||||
|
iconUrl: string,
|
||||||
|
collectionId: string,
|
||||||
|
collectionName: string,
|
||||||
|
isCollection: bool
|
||||||
|
): Item =
|
||||||
|
result.id = id
|
||||||
|
result.chainId = chainId
|
||||||
|
result.name = name
|
||||||
|
result.iconUrl = iconUrl
|
||||||
|
result.collectionId = collectionId
|
||||||
|
result.collectionName = collectionName
|
||||||
|
result.isCollection = isCollection
|
||||||
|
|
||||||
|
proc `$`*(self: Item): string =
|
||||||
|
result = fmt"""CollectiblesNestedEntry(
|
||||||
|
id: {self.id},
|
||||||
|
chainId: {self.chainId},
|
||||||
|
name: {self.name},
|
||||||
|
iconUrl: {self.iconUrl},
|
||||||
|
collectionId: {self.collectionId},
|
||||||
|
collectionName: {self.collectionName},
|
||||||
|
isCollection: {self.isCollection},
|
||||||
|
]"""
|
||||||
|
|
||||||
|
proc getId*(self: Item): string =
|
||||||
|
return self.id
|
||||||
|
|
||||||
|
proc getChainId*(self: Item): int =
|
||||||
|
return self.chainId
|
||||||
|
|
||||||
|
proc getName*(self: Item): string =
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
proc getIconUrl*(self: Item): string =
|
||||||
|
return self.iconUrl
|
||||||
|
|
||||||
|
proc getCollectionId*(self: Item): string =
|
||||||
|
return self.collectionId
|
||||||
|
|
||||||
|
proc getCollectionName*(self: Item): string =
|
||||||
|
return self.collectionName
|
||||||
|
|
||||||
|
proc getIsCollection*(self: Item): bool =
|
||||||
|
return self.isCollection
|
|
@ -0,0 +1,166 @@
|
||||||
|
import NimQml, Tables, strutils, strformat, sequtils, logging
|
||||||
|
|
||||||
|
import ./collectibles_model as flat_model
|
||||||
|
import ./collectibles_item as flat_item
|
||||||
|
import ./collectibles_nested_item as nested_item
|
||||||
|
|
||||||
|
import ./collectibles_nested_utils
|
||||||
|
|
||||||
|
type
|
||||||
|
CollectiblesNestedRole {.pure.} = enum
|
||||||
|
Uid = UserRole + 1,
|
||||||
|
ChainId
|
||||||
|
Name
|
||||||
|
IconUrl
|
||||||
|
CollectionUid
|
||||||
|
CollectionName
|
||||||
|
IsCollection
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type
|
||||||
|
Model* = ref object of QAbstractListModel
|
||||||
|
flatModel: flat_model.Model
|
||||||
|
items: seq[nested_item.Item]
|
||||||
|
currentCollectionUid: string
|
||||||
|
|
||||||
|
proc delete(self: Model) =
|
||||||
|
self.items = @[]
|
||||||
|
self.QAbstractListModel.delete
|
||||||
|
|
||||||
|
proc setup(self: Model) =
|
||||||
|
self.QAbstractListModel.setup
|
||||||
|
|
||||||
|
proc newModel*(flatModel: flat_model.Model): Model =
|
||||||
|
new(result, delete)
|
||||||
|
result.flatModel = flatModel
|
||||||
|
result.items = @[]
|
||||||
|
result.currentCollectionUid = ""
|
||||||
|
result.setup
|
||||||
|
|
||||||
|
signalConnect(result.flatModel, "countChanged()", result, "refreshItems()")
|
||||||
|
|
||||||
|
# Forward declaration
|
||||||
|
proc refreshItems*(self: Model)
|
||||||
|
|
||||||
|
proc `$`*(self: Model): string =
|
||||||
|
result = fmt"""CollectiblesNestedModel(
|
||||||
|
flatModel: {self.flatModel},
|
||||||
|
currentCollectionUid: {self.currentCollectionUid},
|
||||||
|
]"""
|
||||||
|
|
||||||
|
proc countChanged(self: Model) {.signal.}
|
||||||
|
proc getCount*(self: Model): int {.slot.} =
|
||||||
|
self.items.len
|
||||||
|
QtProperty[int] count:
|
||||||
|
read = getCount
|
||||||
|
notify = countChanged
|
||||||
|
|
||||||
|
proc getCurrentCollectionUid*(self: Model): string {.slot.} =
|
||||||
|
result = self.currentCollectionUid
|
||||||
|
proc currentCollectionUidChanged(self: Model) {.signal.}
|
||||||
|
proc setCurrentCollectionUid(self: Model, currentCollectionUid: string) {.slot.} =
|
||||||
|
self.currentCollectionUid = currentCollectionUid
|
||||||
|
self.currentCollectionUidChanged()
|
||||||
|
self.refreshItems()
|
||||||
|
QtProperty[string] currentCollectionUid:
|
||||||
|
read = getCurrentCollectionUid
|
||||||
|
write = setCurrentCollectionUid
|
||||||
|
notify = currentCollectionUidChanged
|
||||||
|
|
||||||
|
method rowCount(self: Model, index: QModelIndex = nil): int =
|
||||||
|
return self.items.len
|
||||||
|
|
||||||
|
method roleNames(self: Model): Table[int, string] =
|
||||||
|
{
|
||||||
|
CollectiblesNestedRole.Uid.int:"uid",
|
||||||
|
CollectiblesNestedRole.ChainId.int:"chainId",
|
||||||
|
CollectiblesNestedRole.Name.int:"name",
|
||||||
|
CollectiblesNestedRole.IconUrl.int:"iconUrl",
|
||||||
|
CollectiblesNestedRole.CollectionUid.int:"collectionUid",
|
||||||
|
CollectiblesNestedRole.CollectionName.int:"collectionName",
|
||||||
|
CollectiblesNestedRole.IsCollection.int:"isCollection",
|
||||||
|
}.toTable
|
||||||
|
|
||||||
|
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
||||||
|
if (not index.isValid):
|
||||||
|
return
|
||||||
|
|
||||||
|
if (index.row < 0 or index.row >= self.getCount()):
|
||||||
|
return
|
||||||
|
|
||||||
|
let item = self.items[index.row]
|
||||||
|
let enumRole = role.CollectiblesNestedRole
|
||||||
|
|
||||||
|
case enumRole:
|
||||||
|
of CollectiblesNestedRole.Uid:
|
||||||
|
result = newQVariant(item.getId())
|
||||||
|
of CollectiblesNestedRole.ChainId:
|
||||||
|
result = newQVariant(item.getChainId())
|
||||||
|
of CollectiblesNestedRole.Name:
|
||||||
|
result = newQVariant(item.getName())
|
||||||
|
of CollectiblesNestedRole.IconUrl:
|
||||||
|
result = newQVariant(item.getIconUrl())
|
||||||
|
of CollectiblesNestedRole.CollectionUid:
|
||||||
|
result = newQVariant(item.getCollectionId())
|
||||||
|
of CollectiblesNestedRole.CollectionName:
|
||||||
|
result = newQVariant(item.getCollectionName())
|
||||||
|
of CollectiblesNestedRole.IsCollection:
|
||||||
|
result = newQVariant(item.getIsCollection())
|
||||||
|
|
||||||
|
proc rowData(self: Model, index: int, column: string): string {.slot.} =
|
||||||
|
if (index >= self.items.len):
|
||||||
|
return
|
||||||
|
let item = self.items[index]
|
||||||
|
case column:
|
||||||
|
of "uid": result = item.getId()
|
||||||
|
of "chainId": result = $item.getChainId()
|
||||||
|
of "name": result = item.getName()
|
||||||
|
of "iconUrl": result = item.getIconUrl()
|
||||||
|
of "collectionUid": result = item.getCollectionId()
|
||||||
|
of "collectionName": result = item.getCollectionName()
|
||||||
|
of "isCollection": result = $item.getIsCollection()
|
||||||
|
|
||||||
|
proc getCollectiblesPerCollectionId(items: seq[flat_item.Item]): Table[string, seq[flat_item.Item]] =
|
||||||
|
var collectiblesPerCollection = initTable[string, seq[flat_item.Item]]()
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
let collectionId = item.getCollectionId()
|
||||||
|
if not collectiblesPerCollection.hasKey(collectionId):
|
||||||
|
collectiblesPerCollection[collectionId] = @[]
|
||||||
|
collectiblesPerCollection[collectionId].add(item)
|
||||||
|
|
||||||
|
return collectiblesPerCollection
|
||||||
|
|
||||||
|
proc refreshItems*(self: Model) {.slot.} =
|
||||||
|
self.beginResetModel()
|
||||||
|
self.items = @[]
|
||||||
|
|
||||||
|
var collectiblesPerCollection = getCollectiblesPerCollectionId(self.flatModel.getItems())
|
||||||
|
for collectionId, collectionCollectibles in collectiblesPerCollection.pairs:
|
||||||
|
if self.currentCollectionUid == "":
|
||||||
|
# No collection selected
|
||||||
|
# If the collection contains more than 1 collectible, we add a single collection item
|
||||||
|
# Otherwise, we add the collectible
|
||||||
|
if collectionCollectibles.len > 1:
|
||||||
|
let collectionItem = collectibleToCollectionNestedItem(collectionCollectibles[0])
|
||||||
|
self.items.add(collectionItem)
|
||||||
|
else:
|
||||||
|
for collectible in collectionCollectibles:
|
||||||
|
let collectibleItem = collectibleToCollectibleNestedItem(collectible)
|
||||||
|
self.items.add(collectibleItem)
|
||||||
|
else:
|
||||||
|
if self.currentCollectionUid == collectionId:
|
||||||
|
for collectible in collectionCollectibles:
|
||||||
|
let collectibleItem = collectibleToCollectibleNestedItem(collectible)
|
||||||
|
self.items.add(collectibleItem)
|
||||||
|
# No need to keep looking
|
||||||
|
break
|
||||||
|
|
||||||
|
self.endResetModel()
|
||||||
|
self.countChanged()
|
||||||
|
|
||||||
|
proc resetModel*(self: Model) =
|
||||||
|
self.beginResetModel()
|
||||||
|
self.items = @[]
|
||||||
|
self.endResetModel()
|
||||||
|
self.countChanged()
|
|
@ -0,0 +1,25 @@
|
||||||
|
import sequtils, sugar, times
|
||||||
|
import collectibles_item as flat_item
|
||||||
|
import collectibles_nested_item as nested_item
|
||||||
|
|
||||||
|
proc collectibleToCollectibleNestedItem*(flatItem: flat_item.Item): nested_item.Item =
|
||||||
|
return nested_item.initItem(
|
||||||
|
flatItem.getId(),
|
||||||
|
flatItem.getChainId(),
|
||||||
|
flatItem.getName(),
|
||||||
|
flatItem.getImageUrl(),
|
||||||
|
flatItem.getCollectionId(),
|
||||||
|
flatItem.getCollectionName(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
proc collectibleToCollectionNestedItem*(flatItem: flat_item.Item): nested_item.Item =
|
||||||
|
return nested_item.initItem(
|
||||||
|
flatItem.getCollectionId(),
|
||||||
|
flatItem.getChainId(),
|
||||||
|
flatItem.getCollectionName(),
|
||||||
|
flatItem.getCollectionImageUrl(),
|
||||||
|
flatItem.getCollectionId(),
|
||||||
|
flatItem.getCollectionName(),
|
||||||
|
true
|
||||||
|
)
|
|
@ -19,5 +19,7 @@ proc collectibleToItem*(c: backend.CollectibleHeader, isPinned: bool = false) :
|
||||||
c.imageUrl,
|
c.imageUrl,
|
||||||
c.backgroundColor,
|
c.backgroundColor,
|
||||||
c.collectionName,
|
c.collectionName,
|
||||||
|
c.collectionSlug,
|
||||||
|
c.collectionImageUrl,
|
||||||
isPinned
|
isPinned
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,7 @@ QtObject:
|
||||||
chainIds: seq[int]
|
chainIds: seq[int]
|
||||||
|
|
||||||
requestId: int32
|
requestId: int32
|
||||||
|
autofetch: bool
|
||||||
|
|
||||||
proc setup(self: Controller) =
|
proc setup(self: Controller) =
|
||||||
self.QObject.setup
|
self.QObject.setup
|
||||||
|
@ -30,33 +31,15 @@ QtObject:
|
||||||
proc delete*(self: Controller) =
|
proc delete*(self: Controller) =
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc getModel*(self: Controller): QVariant {.slot.} =
|
proc getModel*(self: Controller): Model =
|
||||||
|
return self.model
|
||||||
|
|
||||||
|
proc getModelAsVariant*(self: Controller): QVariant {.slot.} =
|
||||||
return newQVariant(self.model)
|
return newQVariant(self.model)
|
||||||
|
|
||||||
QtProperty[QVariant] model:
|
QtProperty[QVariant] model:
|
||||||
read = getModel
|
read = getModelAsVariant
|
||||||
|
|
||||||
proc processFilterOwnedCollectiblesResponse(self: Controller, response: JsonNode) =
|
|
||||||
defer: self.model.setIsFetching(false)
|
|
||||||
|
|
||||||
let res = fromJson(response, backend_collectibles.FilterOwnedCollectiblesResponse)
|
|
||||||
|
|
||||||
let isError = res.errorCode != ErrorCodeSuccess
|
|
||||||
defer: self.model.setIsError(isError)
|
|
||||||
|
|
||||||
if isError:
|
|
||||||
error "error fetching collectibles entries: ", res.errorCode
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
let items = res.collectibles.map(header => collectibleToItem(header))
|
|
||||||
self.model.setItems(items, res.offset, res.hasMore)
|
|
||||||
except Exception as e:
|
|
||||||
error "Error converting activity entries: ", e.msg
|
|
||||||
|
|
||||||
proc resetModel*(self: Controller) {.slot.} =
|
|
||||||
self.model.setItems(@[], 0, true)
|
|
||||||
self.fetchFromStart = true
|
|
||||||
|
|
||||||
proc loadMoreItems(self: Controller) {.slot.} =
|
proc loadMoreItems(self: Controller) {.slot.} =
|
||||||
if self.model.getIsFetching():
|
if self.model.getIsFetching():
|
||||||
|
@ -77,6 +60,33 @@ QtObject:
|
||||||
self.fetchFromStart = true
|
self.fetchFromStart = true
|
||||||
error "error fetching collectibles entries: ", response.error
|
error "error fetching collectibles entries: ", response.error
|
||||||
|
|
||||||
|
proc processFilterOwnedCollectiblesResponse(self: Controller, response: JsonNode) =
|
||||||
|
defer: self.model.setIsFetching(false)
|
||||||
|
|
||||||
|
let res = fromJson(response, backend_collectibles.FilterOwnedCollectiblesResponse)
|
||||||
|
|
||||||
|
let isError = res.errorCode != ErrorCodeSuccess
|
||||||
|
defer: self.model.setIsError(isError)
|
||||||
|
|
||||||
|
if isError:
|
||||||
|
error "error fetching collectibles entries: ", res.errorCode
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
let items = res.collectibles.map(header => collectibleToItem(header))
|
||||||
|
self.model.setItems(items, res.offset, res.hasMore)
|
||||||
|
except Exception as e:
|
||||||
|
error "Error converting activity entries: ", e.msg
|
||||||
|
|
||||||
|
if self.autofetch and res.hasMore:
|
||||||
|
self.loadMoreItems()
|
||||||
|
|
||||||
|
proc resetModel*(self: Controller) {.slot.} =
|
||||||
|
self.model.setItems(@[], 0, true)
|
||||||
|
self.fetchFromStart = true
|
||||||
|
if self.autofetch:
|
||||||
|
self.loadMoreItems()
|
||||||
|
|
||||||
proc setupEventHandlers(self: Controller) =
|
proc setupEventHandlers(self: Controller) =
|
||||||
self.eventsHandler.onOwnedCollectiblesFilteringDone(proc (jsonObj: JsonNode) =
|
self.eventsHandler.onOwnedCollectiblesFilteringDone(proc (jsonObj: JsonNode) =
|
||||||
self.processFilterOwnedCollectiblesResponse(jsonObj)
|
self.processFilterOwnedCollectiblesResponse(jsonObj)
|
||||||
|
@ -87,14 +97,15 @@ QtObject:
|
||||||
)
|
)
|
||||||
|
|
||||||
self.eventsHandler.onCollectiblesOwnershipUpdateFinished(proc () =
|
self.eventsHandler.onCollectiblesOwnershipUpdateFinished(proc () =
|
||||||
self.resetModel()
|
|
||||||
self.model.setIsUpdating(false)
|
self.model.setIsUpdating(false)
|
||||||
|
self.resetModel()
|
||||||
)
|
)
|
||||||
|
|
||||||
proc newController*(requestId: int32, events: EventEmitter): Controller =
|
proc newController*(requestId: int32, autofetch: bool, events: EventEmitter): Controller =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
|
|
||||||
result.requestId = requestId
|
result.requestId = requestId
|
||||||
|
result.autofetch = autofetch
|
||||||
|
|
||||||
result.model = newModel()
|
result.model = newModel()
|
||||||
result.fetchFromStart = true
|
result.fetchFromStart = true
|
||||||
|
|
|
@ -12,6 +12,7 @@ type
|
||||||
CollectiblesRequestID* = enum
|
CollectiblesRequestID* = enum
|
||||||
WalletAccount
|
WalletAccount
|
||||||
ProfileShowcase
|
ProfileShowcase
|
||||||
|
WalletSend
|
||||||
|
|
||||||
# Declared in services/wallet/collectibles/service.go
|
# Declared in services/wallet/collectibles/service.go
|
||||||
const eventCollectiblesOwnershipUpdateStarted*: string = "wallet-collectibles-ownership-update-started"
|
const eventCollectiblesOwnershipUpdateStarted*: string = "wallet-collectibles-ownership-update-started"
|
||||||
|
@ -40,7 +41,6 @@ type
|
||||||
collectibles*: seq[CollectibleDetails]
|
collectibles*: seq[CollectibleDetails]
|
||||||
errorCode*: ErrorCode
|
errorCode*: ErrorCode
|
||||||
|
|
||||||
|
|
||||||
# Responses
|
# Responses
|
||||||
proc fromJson*(e: JsonNode, T: typedesc[FilterOwnedCollectiblesResponse]): FilterOwnedCollectiblesResponse {.inline.} =
|
proc fromJson*(e: JsonNode, T: typedesc[FilterOwnedCollectiblesResponse]): FilterOwnedCollectiblesResponse {.inline.} =
|
||||||
var collectibles: seq[CollectibleHeader]
|
var collectibles: seq[CollectibleHeader]
|
||||||
|
|
|
@ -54,6 +54,8 @@ type
|
||||||
animationMediaType*: string
|
animationMediaType*: string
|
||||||
backgroundColor*: string
|
backgroundColor*: string
|
||||||
collectionName*: string
|
collectionName*: string
|
||||||
|
collectionSlug*: string
|
||||||
|
collectionImageUrl*: string
|
||||||
|
|
||||||
# Mirrors services/wallet/collectibles/types.go CollectibleDetails
|
# Mirrors services/wallet/collectibles/types.go CollectibleDetails
|
||||||
CollectibleDetails* = ref object of RootObj
|
CollectibleDetails* = ref object of RootObj
|
||||||
|
@ -250,7 +252,9 @@ proc `$`*(self: CollectibleHeader): string =
|
||||||
animationUrl:{self.animationUrl},
|
animationUrl:{self.animationUrl},
|
||||||
animationMediaType:{self.animationMediaType},
|
animationMediaType:{self.animationMediaType},
|
||||||
backgroundColor:{self.backgroundColor},
|
backgroundColor:{self.backgroundColor},
|
||||||
collectionName:{self.collectionName}
|
collectionName:{self.collectionName},
|
||||||
|
collectionSlug:{self.collectionSlug},
|
||||||
|
collectionImageUrl:{self.collectionImageUrl}
|
||||||
)"""
|
)"""
|
||||||
|
|
||||||
proc fromJson*(t: JsonNode, T: typedesc[CollectibleHeader]): CollectibleHeader {.inline.} =
|
proc fromJson*(t: JsonNode, T: typedesc[CollectibleHeader]): CollectibleHeader {.inline.} =
|
||||||
|
@ -262,6 +266,8 @@ proc fromJson*(t: JsonNode, T: typedesc[CollectibleHeader]): CollectibleHeader {
|
||||||
result.animationMediaType = t["animation_media_type"].getStr()
|
result.animationMediaType = t["animation_media_type"].getStr()
|
||||||
result.backgroundColor = t["background_color"].getStr()
|
result.backgroundColor = t["background_color"].getStr()
|
||||||
result.collectionName = t["collection_name"].getStr()
|
result.collectionName = t["collection_name"].getStr()
|
||||||
|
result.collectionSlug = t["collection_slug"].getStr()
|
||||||
|
result.collectionImageUrl = t["collection_image_url"].getStr()
|
||||||
|
|
||||||
# CollectibleDetails
|
# CollectibleDetails
|
||||||
proc `$`*(self: CollectibleDetails): string =
|
proc `$`*(self: CollectibleDetails): string =
|
||||||
|
@ -276,7 +282,7 @@ proc `$`*(self: CollectibleDetails): string =
|
||||||
backgroundColor:{self.backgroundColor},
|
backgroundColor:{self.backgroundColor},
|
||||||
collectionName:{self.collectionName},
|
collectionName:{self.collectionName},
|
||||||
collectionSlug:{self.collectionSlug},
|
collectionSlug:{self.collectionSlug},
|
||||||
collectionImageUrl:{self.collectionImageUrl},
|
collectionImageUrl:{self.collectionImageUrl}
|
||||||
)"""
|
)"""
|
||||||
|
|
||||||
proc fromJson*(t: JsonNode, T: typedesc[CollectibleDetails]): CollectibleDetails {.inline.} =
|
proc fromJson*(t: JsonNode, T: typedesc[CollectibleDetails]): CollectibleDetails {.inline.} =
|
||||||
|
|
Loading…
Reference in New Issue