feat(@desktop/wallet2): New collectibles API
This commit is contained in:
parent
681291b4b1
commit
98943f6d72
|
@ -3,16 +3,18 @@ import NimQml, chronicles, stint
|
||||||
|
|
||||||
import
|
import
|
||||||
../../../status/[status, wallet],
|
../../../status/[status, wallet],
|
||||||
views/[accounts, account_list]
|
views/[accounts, account_list, collectibles]
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
WalletView* = ref object of QAbstractListModel
|
WalletView* = ref object of QAbstractListModel
|
||||||
status: Status
|
status: Status
|
||||||
accountsView: AccountsView
|
accountsView: AccountsView
|
||||||
|
collectiblesView: CollectiblesView
|
||||||
|
|
||||||
proc delete(self: WalletView) =
|
proc delete(self: WalletView) =
|
||||||
self.accountsView.delete
|
self.accountsView.delete
|
||||||
|
self.collectiblesView.delete
|
||||||
self.QAbstractListModel.delete
|
self.QAbstractListModel.delete
|
||||||
|
|
||||||
proc setup(self: WalletView) =
|
proc setup(self: WalletView) =
|
||||||
|
@ -22,21 +24,28 @@ QtObject:
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.status = status
|
result.status = status
|
||||||
result.accountsView = newAccountsView(status)
|
result.accountsView = newAccountsView(status)
|
||||||
|
result.collectiblesView = newCollectiblesView(status)
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
proc getAccounts(self: WalletView): QVariant {.slot.} = newQVariant(self.accountsView)
|
proc getAccounts(self: WalletView): QVariant {.slot.} = newQVariant(self.accountsView)
|
||||||
QtProperty[QVariant] accountsView:
|
QtProperty[QVariant] accountsView:
|
||||||
read = getAccounts
|
read = getAccounts
|
||||||
|
|
||||||
|
proc getCollectibles(self: WalletView): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.collectiblesView)
|
||||||
|
|
||||||
|
QtProperty[QVariant] collectiblesView:
|
||||||
|
read = getCollectibles
|
||||||
|
|
||||||
proc updateView*(self: WalletView) =
|
proc updateView*(self: WalletView) =
|
||||||
# TODO:
|
# TODO:
|
||||||
self.accountsView.triggerUpdateAccounts()
|
self.accountsView.triggerUpdateAccounts()
|
||||||
|
|
||||||
|
|
||||||
proc setCurrentAccountByIndex*(self: WalletView, index: int) {.slot.} =
|
proc setCurrentAccountByIndex*(self: WalletView, index: int) {.slot.} =
|
||||||
if self.accountsView.setCurrentAccountByIndex(index):
|
if self.accountsView.setCurrentAccountByIndex(index):
|
||||||
let selectedAccount = self.accountsView.accounts.getAccount(index)
|
let selectedAccount = self.accountsView.accounts.getAccount(index)
|
||||||
# TODO: load account details/transactions/collectibles/etc
|
self.collectiblesView.loadCollections(selectedAccount)
|
||||||
|
# TODO: load account details/transactions/etc
|
||||||
|
|
||||||
proc addAccountToList*(self: WalletView, account: WalletAccount) =
|
proc addAccountToList*(self: WalletView, account: WalletAccount) =
|
||||||
self.accountsView.addAccountToList(account)
|
self.accountsView.addAccountToList(account)
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
import NimQml, Tables
|
||||||
|
from ../../../../status/wallet import OpenseaAsset
|
||||||
|
|
||||||
|
type
|
||||||
|
AssetRoles {.pure.} = enum
|
||||||
|
Id = UserRole + 1,
|
||||||
|
Name = UserRole + 2,
|
||||||
|
Description = UserRole + 3,
|
||||||
|
Permalink = UserRole + 4,
|
||||||
|
ImageUrl = UserRole + 5,
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type AssetList* = ref object of QAbstractListModel
|
||||||
|
assets*: seq[OpenseaAsset]
|
||||||
|
|
||||||
|
proc setup(self: AssetList) = self.QAbstractListModel.setup
|
||||||
|
|
||||||
|
proc delete(self: AssetList) =
|
||||||
|
self.assets = @[]
|
||||||
|
self.QAbstractListModel.delete
|
||||||
|
|
||||||
|
proc newAssetList*(): AssetList =
|
||||||
|
new(result, delete)
|
||||||
|
result.assets = @[]
|
||||||
|
result.setup
|
||||||
|
|
||||||
|
proc assetsChanged*(self: AssetList) {.signal.}
|
||||||
|
|
||||||
|
proc getAsset*(self: AssetList, index: int): OpenseaAsset = self.assets[index]
|
||||||
|
|
||||||
|
proc rowData(self: AssetList, index: int, column: string): string {.slot.} =
|
||||||
|
if (index >= self.assets.len):
|
||||||
|
return
|
||||||
|
|
||||||
|
let asset = self.assets[index]
|
||||||
|
case column:
|
||||||
|
of "name": result = asset.name
|
||||||
|
of "imageUrl": result = asset.imageUrl
|
||||||
|
|
||||||
|
method rowCount*(self: AssetList, index: QModelIndex = nil): int =
|
||||||
|
return self.assets.len
|
||||||
|
|
||||||
|
method data(self: AssetList, index: QModelIndex, role: int): QVariant =
|
||||||
|
if not index.isValid:
|
||||||
|
return
|
||||||
|
|
||||||
|
if index.row < 0 or index.row >= self.assets.len:
|
||||||
|
return
|
||||||
|
|
||||||
|
let asset = self.assets[index.row]
|
||||||
|
let assetRole = role.AssetRoles
|
||||||
|
case assetRole:
|
||||||
|
of AssetRoles.Id: result = newQVariant(asset.id)
|
||||||
|
of AssetRoles.Name: result = newQVariant(asset.name)
|
||||||
|
of AssetRoles.Description: result = newQVariant(asset.description)
|
||||||
|
of AssetRoles.Permalink: result = newQVariant(asset.permalink)
|
||||||
|
of AssetRoles.ImageUrl: result = newQVariant(asset.imageUrl)
|
||||||
|
|
||||||
|
method roleNames(self: AssetList): Table[int, string] =
|
||||||
|
{ AssetRoles.Id.int:"id",
|
||||||
|
AssetRoles.Name.int:"name",
|
||||||
|
AssetRoles.Description.int:"description",
|
||||||
|
AssetRoles.Permalink.int:"permalink",
|
||||||
|
AssetRoles.ImageUrl.int:"imageUrl"}.toTable
|
||||||
|
|
||||||
|
proc setData*(self: AssetList, assets: seq[OpenseaAsset]) =
|
||||||
|
self.beginResetModel()
|
||||||
|
self.assets = assets
|
||||||
|
self.endResetModel()
|
||||||
|
self.assetsChanged()
|
|
@ -0,0 +1,120 @@
|
||||||
|
import NimQml, Tables, json, chronicles
|
||||||
|
|
||||||
|
import
|
||||||
|
../../../../status/[status, wallet],
|
||||||
|
../../../../status/tasks/[qt, task_runner_impl]
|
||||||
|
|
||||||
|
import collection_list, asset_list
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "collectibles-view"
|
||||||
|
|
||||||
|
type
|
||||||
|
LoadCollectionsTaskArg = ref object of QObjectTaskArg
|
||||||
|
address: string
|
||||||
|
|
||||||
|
const loadCollectionsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[LoadCollectionsTaskArg](argEncoded)
|
||||||
|
let output = wallet.getOpenseaCollections(arg.address)
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc loadCollections[T](self: T, slot: string, address: string) =
|
||||||
|
let arg = LoadCollectionsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](loadCollectionsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot, address: address,
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
type
|
||||||
|
LoadAssetsTaskArg = ref object of QObjectTaskArg
|
||||||
|
address: string
|
||||||
|
collectionSlug: string
|
||||||
|
limit: int
|
||||||
|
|
||||||
|
const loadAssetsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[LoadAssetsTaskArg](argEncoded)
|
||||||
|
let output = %*{
|
||||||
|
"collectionSlug": arg.collectionSlug,
|
||||||
|
"assets": parseJson(wallet.getOpenseaAssets(arg.address, arg.collectionSlug, arg.limit)),
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc loadAssets[T](self: T, slot: string, address: string, collectionSlug: string) =
|
||||||
|
let arg = LoadAssetsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](loadAssetsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot, address: address, collectionSlug: collectionSlug, limit: 200
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type CollectiblesView* = ref object of QObject
|
||||||
|
status: Status
|
||||||
|
collections: CollectionList
|
||||||
|
isLoading: bool
|
||||||
|
assets: Table[string, AssetList]
|
||||||
|
|
||||||
|
proc setup(self: CollectiblesView) = self.QObject.setup
|
||||||
|
|
||||||
|
proc delete(self: CollectiblesView) =
|
||||||
|
self.collections.delete
|
||||||
|
for list in self.assets.values:
|
||||||
|
list.delete
|
||||||
|
self.QObject.delete
|
||||||
|
|
||||||
|
proc newCollectiblesView*(status: Status): CollectiblesView =
|
||||||
|
new(result, delete)
|
||||||
|
result.status = status
|
||||||
|
result.collections = newCollectionList()
|
||||||
|
result.assets = initTable[string, AssetList]()
|
||||||
|
result.isLoading = false
|
||||||
|
result.setup
|
||||||
|
|
||||||
|
proc getIsLoading*(self: CollectiblesView): QVariant {.slot.} = newQVariant(self.isLoading)
|
||||||
|
|
||||||
|
proc isLoadingChanged*(self: CollectiblesView) {.signal.}
|
||||||
|
|
||||||
|
QtProperty[QVariant] isLoading:
|
||||||
|
read = getIsLoading
|
||||||
|
notify = isLoadingChanged
|
||||||
|
|
||||||
|
proc loadCollections*(self: CollectiblesView, account: WalletAccount) =
|
||||||
|
self.isLoading = true
|
||||||
|
self.isLoadingChanged()
|
||||||
|
self.assets = initTable[string, AssetList]()
|
||||||
|
self.loadCollections("setCollectionsList", account.address)
|
||||||
|
|
||||||
|
proc setCollectionsList(self: CollectiblesView, raw: string) {.slot.} =
|
||||||
|
var newData: seq[OpenseaCollection] = @[]
|
||||||
|
let collectionsJSON = parseJson(raw)
|
||||||
|
if collectionsJSON["result"].kind != JNull:
|
||||||
|
for jsonOpenseaCollection in collectionsJSON{"result"}:
|
||||||
|
let collection = jsonOpenseaCollection.toOpenseaCollection()
|
||||||
|
newData.add(collection)
|
||||||
|
self.assets[collection.slug] = newAssetList()
|
||||||
|
|
||||||
|
self.collections.setData(newData)
|
||||||
|
self.isLoading = false
|
||||||
|
self.isLoadingChanged()
|
||||||
|
|
||||||
|
proc getCollectionsList(self: CollectiblesView): QVariant {.slot.} =
|
||||||
|
return newQVariant(self.collections)
|
||||||
|
|
||||||
|
QtProperty[QVariant] collections:
|
||||||
|
read = getCollectionsList
|
||||||
|
|
||||||
|
proc loadAssets*(self: CollectiblesView, address: string, collectionSlug: string) {.slot.} =
|
||||||
|
self.loadAssets("setAssetsList", address, collectionSlug)
|
||||||
|
|
||||||
|
proc setAssetsList(self: CollectiblesView, raw: string) {.slot.} =
|
||||||
|
var newData: seq[OpenseaAsset] = @[]
|
||||||
|
let assetsJSON = parseJson(raw)
|
||||||
|
if assetsJSON{"assets"}{"result"}.kind != JNull:
|
||||||
|
for jsonOpenseaAsset in assetsJSON{"assets"}{"result"}:
|
||||||
|
newData.add(jsonOpenseaAsset.toOpenseaAsset())
|
||||||
|
|
||||||
|
self.assets[assetsJSON["collectionSlug"].getStr].setData(newData)
|
||||||
|
|
||||||
|
proc getAssetsList(self: CollectiblesView, collectionSlug: string): QObject {.slot.} =
|
||||||
|
return self.assets[collectionSlug]
|
|
@ -0,0 +1,66 @@
|
||||||
|
import NimQml, Tables
|
||||||
|
from ../../../../status/wallet import OpenseaCollection
|
||||||
|
|
||||||
|
type
|
||||||
|
CollectionRoles {.pure.} = enum
|
||||||
|
Name = UserRole + 1,
|
||||||
|
Slug = UserRole + 2,
|
||||||
|
ImageUrl = UserRole + 3,
|
||||||
|
OwnedAssetCount = UserRole + 4
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type CollectionList* = ref object of QAbstractListModel
|
||||||
|
collections*: seq[OpenseaCollection]
|
||||||
|
|
||||||
|
proc setup(self: CollectionList) = self.QAbstractListModel.setup
|
||||||
|
|
||||||
|
proc delete(self: CollectionList) =
|
||||||
|
self.collections = @[]
|
||||||
|
self.QAbstractListModel.delete
|
||||||
|
|
||||||
|
proc newCollectionList*(): CollectionList =
|
||||||
|
new(result, delete)
|
||||||
|
result.collections = @[]
|
||||||
|
result.setup
|
||||||
|
|
||||||
|
proc getCollection*(self: CollectionList, index: int): OpenseaCollection = self.collections[index]
|
||||||
|
|
||||||
|
proc rowData(self: CollectionList, index: int, column: string): string {.slot.} =
|
||||||
|
if (index >= self.collections.len):
|
||||||
|
return
|
||||||
|
|
||||||
|
let collection = self.collections[index]
|
||||||
|
case column:
|
||||||
|
of "name": result = collection.name
|
||||||
|
of "slug": result = collection.slug
|
||||||
|
of "imageUrl": result = collection.imageUrl
|
||||||
|
of "ownedAssetCount": result = $collection.ownedAssetCount
|
||||||
|
|
||||||
|
method rowCount*(self: CollectionList, index: QModelIndex = nil): int =
|
||||||
|
return self.collections.len
|
||||||
|
|
||||||
|
method data(self: CollectionList, index: QModelIndex, role: int): QVariant =
|
||||||
|
if not index.isValid:
|
||||||
|
return
|
||||||
|
|
||||||
|
if index.row < 0 or index.row >= self.collections.len:
|
||||||
|
return
|
||||||
|
|
||||||
|
let collection = self.collections[index.row]
|
||||||
|
let collectionRole = role.CollectionRoles
|
||||||
|
case collectionRole:
|
||||||
|
of CollectionRoles.Name: result = newQVariant(collection.name)
|
||||||
|
of CollectionRoles.Slug: result = newQVariant(collection.slug)
|
||||||
|
of CollectionRoles.ImageUrl: result = newQVariant(collection.imageUrl)
|
||||||
|
of CollectionRoles.OwnedAssetCount: result = newQVariant(collection.ownedAssetCount)
|
||||||
|
|
||||||
|
method roleNames(self: CollectionList): Table[int, string] =
|
||||||
|
{ CollectionRoles.Name.int:"name",
|
||||||
|
CollectionRoles.Slug.int:"slug",
|
||||||
|
CollectionRoles.ImageUrl.int:"imageUrl",
|
||||||
|
CollectionRoles.OwnedAssetCount.int:"ownedAssetCount"}.toTable
|
||||||
|
|
||||||
|
proc setData*(self: CollectionList, collections: seq[OpenseaCollection]) =
|
||||||
|
self.beginResetModel()
|
||||||
|
self.collections = collections
|
||||||
|
self.endResetModel()
|
|
@ -128,3 +128,11 @@ proc watchTransaction*(transactionHash: string): string =
|
||||||
proc checkRecentHistory*(addresses: seq[string]): string =
|
proc checkRecentHistory*(addresses: seq[string]): string =
|
||||||
let payload = %* [addresses]
|
let payload = %* [addresses]
|
||||||
result = callPrivateRPC("wallet_checkRecentHistory", payload)
|
result = callPrivateRPC("wallet_checkRecentHistory", payload)
|
||||||
|
|
||||||
|
proc getOpenseaCollections*(address: string): string =
|
||||||
|
let payload = %* [address]
|
||||||
|
result = callPrivateRPC("wallet_getOpenseaCollectionsByOwner", payload)
|
||||||
|
|
||||||
|
proc getOpenseaAssets*(address: string, collectionSlug: string, limit: int): string =
|
||||||
|
let payload = %* [address, collectionSlug, limit]
|
||||||
|
result = callPrivateRPC("wallet_getOpenseaAssetsByOwnerAndCollection", payload)
|
|
@ -398,3 +398,9 @@ proc watchTransaction*(transactionHash: string): string =
|
||||||
|
|
||||||
proc hex2Token*(self: WalletModel, input: string, decimals: int): string =
|
proc hex2Token*(self: WalletModel, input: string, decimals: int): string =
|
||||||
result = status_wallet.hex2Token(input, decimals)
|
result = status_wallet.hex2Token(input, decimals)
|
||||||
|
|
||||||
|
proc getOpenseaCollections*(address: string): string =
|
||||||
|
result = status_wallet.getOpenseaCollections(address)
|
||||||
|
|
||||||
|
proc getOpenseaAssets*(address: string, collectionSlug: string, limit: int): string =
|
||||||
|
result = status_wallet.getOpenseaAssets(address, collectionSlug, limit)
|
|
@ -1,6 +1,7 @@
|
||||||
|
import options, json, strformat
|
||||||
|
|
||||||
from ../../eventemitter import Args
|
from ../../eventemitter import Args
|
||||||
import ../types
|
import ../types
|
||||||
import options
|
|
||||||
|
|
||||||
type CollectibleList* = ref object
|
type CollectibleList* = ref object
|
||||||
collectibleType*, collectiblesJSON*, error*: string
|
collectibleType*, collectiblesJSON*, error*: string
|
||||||
|
@ -9,6 +10,14 @@ type CollectibleList* = ref object
|
||||||
type Collectible* = ref object
|
type Collectible* = ref object
|
||||||
name*, image*, id*, collectibleType*, description*, externalUrl*: string
|
name*, image*, id*, collectibleType*, description*, externalUrl*: string
|
||||||
|
|
||||||
|
type OpenseaCollection* = ref object
|
||||||
|
name*, slug*, imageUrl*: string
|
||||||
|
ownedAssetCount*: int
|
||||||
|
|
||||||
|
type OpenseaAsset* = ref object
|
||||||
|
id*: int
|
||||||
|
name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, address*: string
|
||||||
|
|
||||||
type CurrencyArgs* = ref object of Args
|
type CurrencyArgs* = ref object of Args
|
||||||
currency*: string
|
currency*: string
|
||||||
|
|
||||||
|
@ -26,3 +35,28 @@ type WalletAccount* = ref object
|
||||||
|
|
||||||
type AccountArgs* = ref object of Args
|
type AccountArgs* = ref object of Args
|
||||||
account*: WalletAccount
|
account*: WalletAccount
|
||||||
|
|
||||||
|
proc `$`*(self: OpenseaCollection): string =
|
||||||
|
return fmt"OpenseaCollection(name:{self.name}, slug:{self.slug}, owned asset count:{self.ownedAssetCount})"
|
||||||
|
|
||||||
|
proc `$`*(self: OpenseaAsset): string =
|
||||||
|
return fmt"OpenseaAsset(id:{self.id}, name:{self.name}, address:{self.address}, imageUrl: {self.imageUrl}, imageThumbnailUrl: {self.imageThumbnailUrl})"
|
||||||
|
|
||||||
|
proc toOpenseaCollection*(jsonCollection: JsonNode): OpenseaCollection =
|
||||||
|
return OpenseaCollection(
|
||||||
|
name: jsonCollection{"name"}.getStr,
|
||||||
|
slug: jsonCollection{"slug"}.getStr,
|
||||||
|
imageUrl: jsonCollection{"image_url"}.getStr,
|
||||||
|
ownedAssetCount: jsonCollection{"owned_asset_count"}.getInt
|
||||||
|
)
|
||||||
|
|
||||||
|
proc toOpenseaAsset*(jsonAsset: JsonNode): OpenseaAsset =
|
||||||
|
return OpenseaAsset(
|
||||||
|
id: jsonAsset{"id"}.getInt,
|
||||||
|
name: jsonAsset{"name"}.getStr,
|
||||||
|
description: jsonAsset{"description"}.getStr,
|
||||||
|
permalink: jsonAsset{"permalink"}.getStr,
|
||||||
|
imageThumbnailUrl: jsonAsset{"image_thumbnail_url"}.getStr,
|
||||||
|
imageUrl: jsonAsset{"image_url"}.getStr,
|
||||||
|
address: jsonAsset{"asset_contract"}{"address"}.getStr
|
||||||
|
)
|
|
@ -0,0 +1,96 @@
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
import QtGraphicalEffects 1.13
|
||||||
|
import "../../../imports"
|
||||||
|
import "../../../shared"
|
||||||
|
import "../../../shared/status/core"
|
||||||
|
import "./components"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: contentLoader
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
|
||||||
|
sourceComponent: {
|
||||||
|
if (walletV2Model.collectiblesView.isLoading) {
|
||||||
|
return loading
|
||||||
|
}
|
||||||
|
if (walletV2Model.collectiblesView.collections.rowCount() == 0) {
|
||||||
|
return empty
|
||||||
|
}
|
||||||
|
|
||||||
|
return loaded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loading
|
||||||
|
|
||||||
|
Item {
|
||||||
|
StatusLoadingIndicator {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: empty
|
||||||
|
Item {
|
||||||
|
StyledText {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: Style.current.secondaryText
|
||||||
|
text: qsTr("Collectibles will appear here")
|
||||||
|
font.pixelSize: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectibleModal {
|
||||||
|
id: collectibleModalComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loaded
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scrollView
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: collectiblesSection
|
||||||
|
spacing: Style.current.halfPadding
|
||||||
|
width: root.width
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: collectionsRepeater
|
||||||
|
model: walletV2Model.collectiblesView.collections
|
||||||
|
|
||||||
|
CollectibleCollection {
|
||||||
|
name: model.name
|
||||||
|
imageUrl: model.imageUrl
|
||||||
|
ownedAssetCount: model.ownedAssetCount
|
||||||
|
slug: model.slug
|
||||||
|
collectibleModal: collectibleModalComponent
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Style.current.bigPadding
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Style.current.bigPadding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*##^##
|
||||||
|
Designer {
|
||||||
|
D{i:0;autoSize:true;formeditorColor:"#ffffff";height:480;width:640}
|
||||||
|
}
|
||||||
|
##^##*/
|
|
@ -69,8 +69,36 @@ Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
StyledText {
|
TabBar {
|
||||||
text: "TODO"
|
id: walletTabBar
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Style.current.bigPadding
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Style.current.bigPadding
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: Style.current.padding
|
||||||
|
height: collectiblesBtn.height
|
||||||
|
background: Rectangle {
|
||||||
|
color: Style.current.transparent
|
||||||
|
}
|
||||||
|
StatusTabButton {
|
||||||
|
id: collectiblesBtn
|
||||||
|
btnText: qsTr("Collectibles")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StackLayout {
|
||||||
|
id: stackLayout
|
||||||
|
anchors.top: walletTabBar.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.topMargin: Style.current.bigPadding
|
||||||
|
currentIndex: walletTabBar.currentIndex
|
||||||
|
|
||||||
|
CollectiblesTab {
|
||||||
|
id: collectiblesTab
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
import QtGraphicalEffects 1.13
|
||||||
|
import "../../../../imports"
|
||||||
|
import "../../../../shared"
|
||||||
|
import "../../../../shared/status/core"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property string imageUrl: ""
|
||||||
|
property string name: "CryptoKitties"
|
||||||
|
property string slug: "cryptokitties"
|
||||||
|
property int ownedAssetCount: 0
|
||||||
|
property var collectibleModal
|
||||||
|
property bool isOpened: false
|
||||||
|
property bool assetsLoaded: false
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: {
|
||||||
|
if (!isOpened) {
|
||||||
|
return header.height
|
||||||
|
}
|
||||||
|
|
||||||
|
return header.height + contentLoader.height
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCollection() {
|
||||||
|
if (root.isOpened) {
|
||||||
|
root.isOpened = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
walletV2Model.collectiblesView.loadAssets(walletV2Model.accountsView.currentAccount.address, root.slug)
|
||||||
|
root.isOpened = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: walletV2Model.collectiblesView.getAssetsList(root.slug)
|
||||||
|
onAssetsChanged: {
|
||||||
|
root.assetsLoaded = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: header
|
||||||
|
property bool hovered: false
|
||||||
|
height: 64
|
||||||
|
width: parent.width
|
||||||
|
color: hovered ? Style.current.backgroundHover : Style.current.transparent
|
||||||
|
border.width: 0
|
||||||
|
radius: Style.current.radius
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
source: root.imageUrl
|
||||||
|
width: 40
|
||||||
|
height: 40
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Style.current.padding
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.name
|
||||||
|
anchors.left: image.right
|
||||||
|
anchors.leftMargin: Style.current.padding
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
font.pixelSize: 17
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.right: header.right
|
||||||
|
anchors.rightMargin: Style.current.padding
|
||||||
|
anchors.verticalCenter: header.verticalCenter
|
||||||
|
width: childrenRect.width
|
||||||
|
height: count.height
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: count
|
||||||
|
color: Style.current.secondaryText
|
||||||
|
text: root.ownedAssetCount
|
||||||
|
font.pixelSize: 15
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
SVGImage {
|
||||||
|
id: caretImg
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
source: "../../../img/caret.svg"
|
||||||
|
width: 11
|
||||||
|
anchors.left: count.right
|
||||||
|
anchors.leftMargin: Style.current.padding
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorOverlay {
|
||||||
|
anchors.fill: caretImg
|
||||||
|
source: caretImg
|
||||||
|
color: Style.current.black
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
onEntered: {
|
||||||
|
header.hovered = true
|
||||||
|
}
|
||||||
|
onExited: {
|
||||||
|
header.hovered = false
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
root.toggleCollection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: contentLoader
|
||||||
|
active: root.isOpened
|
||||||
|
width: parent.width
|
||||||
|
anchors.top: header.bottom
|
||||||
|
anchors.topMargin: Style.current.halfPadding
|
||||||
|
sourceComponent: root.assetsLoaded ? loaded : loading
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loading
|
||||||
|
Item {
|
||||||
|
id: loadingIndicator
|
||||||
|
height: 164
|
||||||
|
StatusLoadingIndicator {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loaded
|
||||||
|
ScrollView {
|
||||||
|
height: contentRow.height
|
||||||
|
width: parent.width
|
||||||
|
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
|
||||||
|
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: contentRow
|
||||||
|
bottomPadding: Style.current.padding
|
||||||
|
spacing: Style.current.padding
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: walletV2Model.collectiblesView.getAssetsList(root.slug)
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: image.width
|
||||||
|
height: image.height
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
RoundedImage {
|
||||||
|
id: image
|
||||||
|
width: 164
|
||||||
|
height: 164
|
||||||
|
border.width: 1
|
||||||
|
border.color: Style.current.border
|
||||||
|
radius: 16
|
||||||
|
source: model.imageUrl
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
onClicked: {
|
||||||
|
collectibleModal.openModal({
|
||||||
|
name: model.name,
|
||||||
|
collectibleId: model.id,
|
||||||
|
description: model.description,
|
||||||
|
permalink: model.permalink,
|
||||||
|
imageUrl: model.imageUrl
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*##^##
|
||||||
|
Designer {
|
||||||
|
D{i:0;autoSize:true;height:480;width:640}
|
||||||
|
}
|
||||||
|
##^##*/
|
|
@ -0,0 +1,69 @@
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtGraphicalEffects 1.13
|
||||||
|
import "../../../../imports"
|
||||||
|
import "../../../../shared"
|
||||||
|
import "../../../../shared/status"
|
||||||
|
|
||||||
|
ModalPopup {
|
||||||
|
id: root
|
||||||
|
property string name: "Furbeard"
|
||||||
|
property string collectibleId: "1423"
|
||||||
|
property url imageUrl: ""
|
||||||
|
property string description: "Avast ye! I'm the dread pirate Furbeard, and I'll most likely sleep"
|
||||||
|
property string permalink: "https://www.cryptokitties.co/"
|
||||||
|
property var openModal: function (options) {
|
||||||
|
root.name = options.name
|
||||||
|
root.collectibleId = options.collectibleId
|
||||||
|
root.description = options.description
|
||||||
|
root.imageUrl = options.imageUrl
|
||||||
|
root.permalink = options.permalink
|
||||||
|
root.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
title: root.name || qsTr("unnamed")
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
RoundedImage {
|
||||||
|
id: collectibleImage
|
||||||
|
width: 248
|
||||||
|
height: 248
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
source: root.imageUrl
|
||||||
|
radius: 16
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithLabel {
|
||||||
|
id: idText
|
||||||
|
label: qsTr("id")
|
||||||
|
text: root.collectibleId
|
||||||
|
anchors.top: collectibleImage.bottom
|
||||||
|
anchors.topMargin:0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextWithLabel {
|
||||||
|
id: description
|
||||||
|
visible: !!root.description
|
||||||
|
label: qsTr("description")
|
||||||
|
text: root.description
|
||||||
|
anchors.top: idText.bottom
|
||||||
|
anchors.topMargin: 0
|
||||||
|
wrap: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: StatusButton {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Style.current.padding
|
||||||
|
text: qsTr("View in Opensea")
|
||||||
|
anchors.top: parent.top
|
||||||
|
onClicked: {
|
||||||
|
appMain.openLink(root.permalink)
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
SendModalContent 1.0 SendModalContent.qml
|
|
||||||
SetCurrencyModalContent 1.0 SetCurrencyModalContent.qml
|
|
||||||
TokenSettingsModalContent 1.0 TokenSettingsModalContent.qml
|
|
||||||
AddAccount 1.0 AddAccount.qml
|
AddAccount 1.0 AddAccount.qml
|
||||||
GenerateAccountModal 1.0 GenerateAccountModal.qml
|
HeaderButton 1.0 HeaderButton.qml
|
||||||
AddAccountWithSeed 1.0 AddAccountWithSeed.qml
|
CollectibleCollection 1.0 CollectibleCollection.qml
|
||||||
AddAccountWithPrivateKey 1.0 AddAccountWithPrivateKey.qml
|
CollectibleModal 1.0 CollectibleModal.qml
|
||||||
AddWatchOnlyAccount 1.0 AddWatchOnlyAccount.qml
|
|
||||||
TransactionModal 1.0 TransactionModal.qml
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit b8959e3f66159b142fb6706b89f4ad8295944ee4
|
Subproject commit 37484b28ebdab47092a96362d5a08f31ea88a4f3
|
Loading…
Reference in New Issue