feat(@desktop/wallet): implement collectible details activity tab

Fixes #12311
This commit is contained in:
Dario Gabriel Lipicar 2024-02-25 23:32:59 -03:00 committed by dlipicar
parent 82e197da88
commit 10c44b8038
13 changed files with 627 additions and 35 deletions

View File

@ -198,6 +198,9 @@ QtObject:
error "error fetching collectibles: ", res.error error "error fetching collectibles: ", res.error
return return
proc resetFilter*(self: Controller) {.slot.} =
self.currentActivityFilter = backend_activity.getIncludeAllActivityFilter()
proc setFilterTime*(self: Controller, startTimestamp: int, endTimestamp: int) {.slot.} = proc setFilterTime*(self: Controller, startTimestamp: int, endTimestamp: int) {.slot.} =
self.currentActivityFilter.period = backend_activity.newPeriod(startTimestamp, endTimestamp) self.currentActivityFilter.period = backend_activity.newPeriod(startTimestamp, endTimestamp)
@ -424,7 +427,7 @@ QtObject:
var addresses = newSeq[string]() var addresses = newSeq[string]()
for i in 0 ..< addressesJson.len: for i in 0 ..< addressesJson.len:
if addressesJson[i].kind != JString: if addressesJson[i].kind != JString:
error "not string entry in the json adday for index ", i error "not string entry in the addresses json array for index ", i
return return
addresses.add(addressesJson[i].getStr()) addresses.add(addressesJson[i].getStr())
@ -441,6 +444,21 @@ QtObject:
self.status.emitFilterChainsChanged() self.status.emitFilterChainsChanged()
self.updateAssetsIdentities() self.updateAssetsIdentities()
proc setFilterChainsJson*(self: Controller, jsonArray: string, allChainsSelected: bool) {.slot.} =
let chainsJson = parseJson(jsonArray)
if chainsJson.kind != JArray:
error "invalid array of json ints"
return
var chains = newSeq[int]()
for i in 0 ..< chainsJson.len:
if chainsJson[i].kind != JInt:
error "not int entry in the chains json array for index ", i
return
chains.add(chainsJson[i].getInt())
self.setFilterChains(chains, allChainsSelected)
proc updateRecipientsModel*(self: Controller) {.slot.} = proc updateRecipientsModel*(self: Controller) {.slot.} =
self.status.setLoadingRecipients(true) self.status.setLoadingRecipients(true)
let res = backend_activity.getRecipientsAsync(self.requestId, self.chainIds, self.addresses, 0, FETCH_RECIPIENTS_BATCH_COUNT_DEFAULT) let res = backend_activity.getRecipientsAsync(self.requestId, self.chainIds, self.addresses, 0, FETCH_RECIPIENTS_BATCH_COUNT_DEFAULT)

View File

@ -51,7 +51,8 @@ export io_interface
type type
ActivityID = enum ActivityID = enum
History History
Temporary Temporary0
Temporary1
Module* = ref object of io_interface.AccessInterface Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface delegate: delegate_interface.AccessInterface
@ -84,8 +85,11 @@ type
activityController: activityc.Controller activityController: activityc.Controller
collectibleDetailsController: collectible_detailsc.Controller collectibleDetailsController: collectible_detailsc.Controller
# instance to be used in temporary, short-lived, workflows (e.g. send popup) # Instances to be used in temporary, short-lived, workflows (e.g. send popup). There's probably tidier ways of
tmpActivityController: activityc.Controller # doing this (one for each required module, create them dynamically) but for now this will do.
# We need one for each app "layer" that simultaneously needs to show a different list of activity
# entries (e.g. send popup is one "layer" above the collectible details activity tab)
tmpActivityControllers: ActivityControllerArray
wcController: wcc.Controller wcController: wcc.Controller
@ -139,14 +143,18 @@ proc newModule*(
result.transactionService = transactionService result.transactionService = transactionService
result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService, result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService,
savedAddressService, events) savedAddressService, events)
result.tmpActivityController = activityc.newController(int32(ActivityID.Temporary), currencyService, tokenService, result.tmpActivityControllers = [
activityc.newController(int32(ActivityID.Temporary0), currencyService, tokenService,
savedAddressService, events),
activityc.newController(int32(ActivityID.Temporary1), currencyService, tokenService,
savedAddressService, events) savedAddressService, 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)
result.wcController = wcc.newController(events, walletAccountService) result.wcController = wcc.newController(events, walletAccountService)
result.view = newView(result, result.activityController, result.tmpActivityController, result.collectibleDetailsController, result.wcController) result.view = newView(result, result.activityController, result.tmpActivityControllers, result.collectibleDetailsController, result.wcController)
method delete*(self: Module) = method delete*(self: Module) =
self.accountsModule.delete self.accountsModule.delete
@ -159,7 +167,8 @@ method delete*(self: Module) =
self.controller.delete self.controller.delete
self.view.delete self.view.delete
self.activityController.delete self.activityController.delete
self.tmpActivityController.delete for i in 0..self.tmpActivityControllers.len-1:
self.tmpActivityControllers[i].delete
self.collectibleDetailsController.delete self.collectibleDetailsController.delete
self.wcController.delete self.wcController.delete

View File

@ -6,6 +6,9 @@ import ./io_interface
import ../../shared_models/currency_amount import ../../shared_models/currency_amount
import ./wallet_connect/controller as wcc import ./wallet_connect/controller as wcc
type
ActivityControllerArray* = array[2, activityc.Controller]
QtObject: QtObject:
type type
View* = ref object of QObject View* = ref object of QObject
@ -16,7 +19,7 @@ QtObject:
tmpAmount: float # shouldn't be used anywhere except in prepare*/getPrepared* procs tmpAmount: float # shouldn't be used anywhere except in prepare*/getPrepared* procs
tmpSymbol: string # shouldn't be used anywhere except in prepare*/getPrepared* procs tmpSymbol: string # shouldn't be used anywhere except in prepare*/getPrepared* procs
activityController: activityc.Controller activityController: activityc.Controller
tmpActivityController: activityc.Controller tmpActivityControllers: ActivityControllerArray
collectibleDetailsController: collectible_detailsc.Controller collectibleDetailsController: collectible_detailsc.Controller
isNonArchivalNode: bool isNonArchivalNode: bool
keypairOperabilityForObservedAccount: string keypairOperabilityForObservedAccount: string
@ -31,11 +34,11 @@ QtObject:
proc delete*(self: View) = proc delete*(self: View) =
self.QObject.delete self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface, activityController: activityc.Controller, tmpActivityController: activityc.Controller, collectibleDetailsController: collectible_detailsc.Controller, wcController: wcc.Controller): View = proc newView*(delegate: io_interface.AccessInterface, activityController: activityc.Controller, tmpActivityControllers: ActivityControllerArray, collectibleDetailsController: collectible_detailsc.Controller, wcController: wcc.Controller): View =
new(result, delete) new(result, delete)
result.delegate = delegate result.delegate = delegate
result.activityController = activityController result.activityController = activityController
result.tmpActivityController = tmpActivityController result.tmpActivityControllers = tmpActivityControllers
result.collectibleDetailsController = collectibleDetailsController result.collectibleDetailsController = collectibleDetailsController
result.wcController = wcController result.wcController = wcController
@ -151,10 +154,15 @@ QtObject:
QtProperty[QVariant] collectibleDetailsController: QtProperty[QVariant] collectibleDetailsController:
read = getCollectibleDetailsController read = getCollectibleDetailsController
proc getTmpActivityController(self: View): QVariant {.slot.} = proc getTmpActivityController0(self: View): QVariant {.slot.} =
return newQVariant(self.tmpActivityController) return newQVariant(self.tmpActivityControllers[0])
QtProperty[QVariant] tmpActivityController: QtProperty[QVariant] tmpActivityController0:
read = getTmpActivityController read = getTmpActivityController0
proc getTmpActivityController1(self: View): QVariant {.slot.} =
return newQVariant(self.tmpActivityControllers[1])
QtProperty[QVariant] tmpActivityController1:
read = getTmpActivityController1
proc getLatestBlockNumber*(self: View, chainId: int): string {.slot.} = proc getLatestBlockNumber*(self: View, chainId: int): string {.slot.} =
return self.delegate.getLatestBlockNumber(chainId) return self.delegate.getLatestBlockNumber(chainId)

View File

@ -0,0 +1,134 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Storybook 1.0
import AppLayouts.Wallet 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStores
import AppLayouts.Wallet.views.collectibles 1.0
import StatusQ.Core.Utils 0.1
import shared.controls 1.0
import shared.stores 1.0
import Models 1.0
import utils 1.0
SplitView {
id: root
QtObject {
id: d
readonly property QtObject collectiblesModel: WalletCollectiblesModel {
Component.onCompleted: {
d.refreshCurrentCollectible()
}
}
property var currentCollectible
function refreshCurrentCollectible() {
currentCollectible = ModelUtils.get(collectiblesModel, collectibleComboBox.currentIndex)
}
readonly property QtObject transactionsModel: WalletTransactionsModel{}
}
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
Rectangle {
anchors.fill: viewLoader
anchors.margins: -1
color: "transparent"
border.width: 1
border.color: "#808080"
}
Loader {
id: viewLoader
anchors.fill: parent
anchors.margins: 50
active: false
sourceComponent: CollectibleDetailView {
collectible: d.currentCollectible
isCollectibleLoading: isLoadingCheckbox.checked
activityModel: d.transactionsModel
rootStore: QtObject {
readonly property string currentCurrency: "EUR"
function getFiatValue(cryptoValue, symbol) {
return cryptoValue * 0.1;
}
function formatCurrencyAmount(cryptoValue, symbol) {
return "%L1 %2".arg(cryptoValue).arg(symbol)
}
function getNetworkFullName(chainId) {
return chainId
}
function getNetworkColor(chainId) {
return "pink"
}
}
walletRootStore: QtObject {
function getNameForAddress(address) {
return "NAMEFOR: %1".arg(address)
}
readonly property bool showAllAccounts: true
}
communitiesStore: QtObject {
function getCommunityDetailsAsJson(communityId) {
return ""
}
}
}
Component.onCompleted: viewLoader.active = true
}
}
LogsAndControlsPanel {
SplitView.minimumHeight: 100
SplitView.preferredHeight: 150
SplitView.fillWidth: true
}
}
Pane {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
ColumnLayout {
Label {
text: "Collectible:"
}
ComboBox {
id: collectibleComboBox
Layout.fillWidth: true
textRole: "name"
model: d.collectiblesModel
currentIndex: 0
onCurrentIndexChanged: d.refreshCurrentCollectible()
}
CheckBox {
id: isLoadingCheckbox
text: "isLoading"
checked: false
}
}
}
}
// category: Wallet

View File

@ -1,5 +1,8 @@
import QtQuick 2.15 import QtQuick 2.15
import StatusQ.Core 0.1
import utils 1.0
ListModel { ListModel {
readonly property var rootData: [ readonly property var rootData: [
{ {
@ -9,8 +12,29 @@ ListModel {
tokenId: "1", tokenId: "1",
name: "Furbeard", name: "Furbeard",
imageUrl: ModelsData.collectibles.kitty1Big, imageUrl: ModelsData.collectibles.kitty1Big,
backgroundColor: "#f5f5f5",
description: "Furbeard is a very rare CryptoKitty. It's a Gen 0 cat and has a lot of special traits.",
collectionUid: "cryptokitties", collectionUid: "cryptokitties",
collectionName: "CryptoKitties", collectionName: "CryptoKitties",
collectionImageUrl: ModelsData.collectibles.cryptoKitties,
traits: [
{
traitType: "Fur",
value: "White"
},
{
traitType: "Eyes",
value: "Green"
},
{
traitType: "Pattern",
value: "Tigerpunk"
}
],
communityId: "",
networkShortName: "ETH",
networkColor: "blue",
networkIconUrl: ModelsData.networks.ethereum
}, },
{ {
uid: "ID-Kitty2", uid: "ID-Kitty2",
@ -19,8 +43,29 @@ ListModel {
tokenId: "2", tokenId: "2",
name: "Magicat", name: "Magicat",
imageUrl: ModelsData.collectibles.kitty2Big, imageUrl: ModelsData.collectibles.kitty2Big,
backgroundColor: "transparent",
description: "Magicat is a very rare CryptoKitty. It's a Gen 0 cat and has a lot of special traits.",
collectionUid: "cryptokitties", collectionUid: "cryptokitties",
collectionName: "CryptoKitties", collectionName: "CryptoKitties",
collectionImageUrl: ModelsData.collectibles.cryptoKitties,
traits: [
{
traitType: "Fur",
value: "White"
},
{
traitType: "Eyes",
value: "Blue"
},
{
traitType: "Pattern",
value: "Tigerpunk"
}
],
communityId: "",
networkShortName: "ETH",
networkColor: "blue",
networkIconUrl: ModelsData.networks.ethereum
}, },
{ {
uid: "ID-Kitty3", uid: "ID-Kitty3",
@ -29,8 +74,29 @@ ListModel {
tokenId: "3", tokenId: "3",
name: "Happy Meow", name: "Happy Meow",
imageUrl: ModelsData.collectibles.kitty3Big, imageUrl: ModelsData.collectibles.kitty3Big,
backgroundColor: "blue",
description: "Happy Meow is a very rare CryptoKitty. It's a Gen 0 cat and has a lot of special traits.",
collectionUid: "cryptokitties", collectionUid: "cryptokitties",
collectionName: "CryptoKitties", collectionName: "CryptoKitties",
collectionImageUrl: ModelsData.collectibles.cryptoKitties,
traits: [
{
traitType: "Fur",
value: "White"
},
{
traitType: "Eyes",
value: "Green"
},
{
traitType: "Pattern",
value: "Tigerpunk"
}
],
communityId: "",
networkShortName: "ETH",
networkColor: "blue",
networkIconUrl: ModelsData.networks.ethereum
}, },
{ {
uid: "ID-Kitty4", uid: "ID-Kitty4",
@ -39,8 +105,29 @@ ListModel {
tokenId: "4", tokenId: "4",
name: "Furbeard-2", name: "Furbeard-2",
imageUrl: ModelsData.collectibles.kitty4Big, imageUrl: ModelsData.collectibles.kitty4Big,
backgroundColor: "red",
description: "Furbeard-2 is a very rare CryptoKitty. It's a Gen 0 cat and has a lot of special traits.",
collectionUid: "cryptokitties", collectionUid: "cryptokitties",
collectionName: "CryptoKitties", collectionName: "CryptoKitties",
collectionImageUrl: ModelsData.collectibles.cryptoKitties,
traits: [
{
traitType: "Fur",
value: "White"
},
{
traitType: "Eyes",
value: "Green"
},
{
traitType: "Pattern",
value: "Tigerpunk"
}
],
communityId: "",
networkShortName: "ETH",
networkColor: "blue",
networkIconUrl: ModelsData.networks.ethereum
}, },
{ {
uid: "ID-Kitty5", uid: "ID-Kitty5",
@ -49,8 +136,29 @@ ListModel {
tokenId: "4", tokenId: "4",
name: "Magicat-3", name: "Magicat-3",
imageUrl: ModelsData.collectibles.kitty5Big, imageUrl: ModelsData.collectibles.kitty5Big,
backgroundColor: "yellow",
description: "Magicat-3 is a very rare CryptoKitty. It's a Gen 0 cat and has a lot of special traits.",
collectionUid: "cryptokitties", collectionUid: "cryptokitties",
collectionName: "CryptoKitties" collectionName: "CryptoKitties",
collectionImageUrl: ModelsData.collectibles.cryptoKitties,
traits: [
{
traitType: "Fur",
value: "White"
},
{
traitType: "Eyes",
value: "Blue"
},
{
traitType: "Pattern",
value: "Tigerpunk"
}
],
communityId: "",
networkShortName: "ETH",
networkColor: "blue",
networkIconUrl: ModelsData.networks.ethereum
}, },
{ {
uid: "ID-Anniversary", uid: "ID-Anniversary",
@ -59,8 +167,21 @@ ListModel {
tokenId: "1", tokenId: "1",
name: "Anniversary", name: "Anniversary",
imageUrl: ModelsData.collectibles.anniversary, imageUrl: ModelsData.collectibles.anniversary,
backgroundColor: "black",
description: "This is a special collectible to celebrate the anniversary of the platform.",
collectionUid: "anniversary", collectionUid: "anniversary",
collectionName: "Anniversary", collectionName: "Anniversary",
collectionImageUrl: ModelsData.collectibles.anniversary,
traits: [
{
traitType: "Type",
value: "Special"
}
],
communityId: "",
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism
}, },
{ {
uid: "ID-SuperRare", uid: "ID-SuperRare",
@ -69,8 +190,21 @@ ListModel {
tokenId: "101", tokenId: "101",
name: "SuperRare", name: "SuperRare",
imageUrl: ModelsData.collectibles.superRare, imageUrl: ModelsData.collectibles.superRare,
backgroundColor: "transparent",
description: "This is a very rare collectible. It's a unique piece of art.",
collectionUid: "super-rare", collectionUid: "super-rare",
collectionName: "SuperRare", collectionName: "SuperRare",
collectionImageUrl: ModelsData.collectibles.doodles,
traits: [
{
traitType: "Type",
value: "Rare"
}
],
communityId: "",
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism
}, },
{ {
uid: "ID-Custom", uid: "ID-Custom",
@ -79,8 +213,34 @@ ListModel {
tokenId: "403", tokenId: "403",
name: "Custom Collectible", name: "Custom Collectible",
imageUrl: ModelsData.collectibles.custom, imageUrl: ModelsData.collectibles.custom,
backgroundColor: "transparent",
description: "This is a custom collectible. It's a unique piece of art.",
collectionUid: "custom", collectionUid: "custom",
collectionName: "Custom", collectionName: "Custom",
collectionImageUrl: "",
traits: [],
communityId: "",
networkShortName: "ARB",
networkColor: "blue",
networkIconUrl: ModelsData.networks.arbitrum
},
{
uid: "ID-MissingMetadata",
chainId: 1,
contractAddress: "0x05",
tokenId: "405",
name: "",
imageUrl: "",
backgroundColor: "transparent",
description: "",
collectionUid: "missing",
collectionName: "",
collectionImageUrl: "",
traits: [],
communityId: "",
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism
} }
] ]

View File

@ -0,0 +1,187 @@
import QtQuick 2.15
import StatusQ 0.1
import StatusQ.Core 0.1
import utils 1.0
ListModel {
readonly property var rootData: [
{
activityEntry: {
timestamp: Date.now() / 1000,
status: 0,
amount: 123.45,
inAmount: 123.45,
outAmount: 123.45,
symbol: "SNT",
inSymbol: "SNT",
outSymbol: "SNT",
isMultiTransaction: false,
txType: 0,
sender: "0xfB8131c260749c7835a08ccBdb64728De432858E",
recipient: "0x3fb81384583b3910BB14Cc72582E8e8a56E83ae9",
isNFT: false,
isCommunityAssetViaAirdrop: false,
communityName: "Doodles",
communityImageUrl: Style.png("collectibles/HappyMeow"),
tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337",
tokenAddress: "0xdeadbeef",
tokenInAddress: "0xdeadbeef-00",
tokenOutAddress: "0xdeadbeef-00",
nftName: "Happy Meow NFT",
nftImageUrl: Style.png("collectibles/HappyMeow"),
chainId: "NETWORKID",
chainIdIn: "NETWORKID-IN",
chainIdOut: "NETWORKID-OUT"
}
},
{
activityEntry: {
timestamp: Date.now() / 1000,
status: 0,
amount: 123.45,
inAmount: 123.45,
outAmount: 123.45,
symbol: "SNT",
inSymbol: "SNT",
outSymbol: "SNT",
isMultiTransaction: false,
txType: 0,
sender: "0xfB8131c260749c7835a08ccBdb64728De432858E",
recipient: "0x3fb81384583b3910BB14Cc72582E8e8a56E83ae9",
isNFT: false,
isCommunityAssetViaAirdrop: false,
communityName: "Doodles",
communityImageUrl: Style.png("collectibles/HappyMeow"),
tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337",
tokenAddress: "0xdeadbeef",
tokenInAddress: "0xdeadbeef-00",
tokenOutAddress: "0xdeadbeef-00",
nftName: "Happy Meow NFT",
nftImageUrl: Style.png("collectibles/HappyMeow"),
chainId: "NETWORKID",
chainIdIn: "NETWORKID-IN",
chainIdOut: "NETWORKID-OUT"
}
},
{
activityEntry: {
timestamp: Date.now() / 1000,
status: 0,
amount: 123.45,
inAmount: 123.45,
outAmount: 123.45,
symbol: "SNT",
inSymbol: "SNT",
outSymbol: "SNT",
isMultiTransaction: false,
txType: 0,
sender: "0xfB8131c260749c7835a08ccBdb64728De432858E",
recipient: "0x3fb81384583b3910BB14Cc72582E8e8a56E83ae9",
isNFT: false,
isCommunityAssetViaAirdrop: false,
communityName: "Doodles",
communityImageUrl: Style.png("collectibles/HappyMeow"),
tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337",
tokenAddress: "0xdeadbeef",
tokenInAddress: "0xdeadbeef-00",
tokenOutAddress: "0xdeadbeef-00",
nftName: "Happy Meow NFT",
nftImageUrl: Style.png("collectibles/HappyMeow"),
chainId: "NETWORKID",
chainIdIn: "NETWORKID-IN",
chainIdOut: "NETWORKID-OUT"
}
},
{
activityEntry: {
timestamp: Date.now() / 1000,
status: 0,
amount: 123.45,
inAmount: 123.45,
outAmount: 123.45,
symbol: "SNT",
inSymbol: "SNT",
outSymbol: "SNT",
isMultiTransaction: false,
txType: 0,
sender: "0xfB8131c260749c7835a08ccBdb64728De432858E",
recipient: "0x3fb81384583b3910BB14Cc72582E8e8a56E83ae9",
isNFT: false,
isCommunityAssetViaAirdrop: false,
communityName: "Doodles",
communityImageUrl: Style.png("collectibles/HappyMeow"),
tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337",
tokenAddress: "0xdeadbeef",
tokenInAddress: "0xdeadbeef-00",
tokenOutAddress: "0xdeadbeef-00",
nftName: "Happy Meow NFT",
nftImageUrl: Style.png("collectibles/HappyMeow"),
chainId: "NETWORKID",
chainIdIn: "NETWORKID-IN",
chainIdOut: "NETWORKID-OUT"
}
},
{
activityEntry: {
timestamp: Date.now() / 1000,
status: 0,
amount: 123.45,
inAmount: 123.45,
outAmount: 123.45,
symbol: "SNT",
inSymbol: "SNT",
outSymbol: "SNT",
isMultiTransaction: false,
txType: 0,
sender: "0xfB8131c260749c7835a08ccBdb64728De432858E",
recipient: "0x3fb81384583b3910BB14Cc72582E8e8a56E83ae9",
isNFT: false,
isCommunityAssetViaAirdrop: false,
communityName: "Doodles",
communityImageUrl: Style.png("collectibles/HappyMeow"),
tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337",
tokenAddress: "0xdeadbeef",
tokenInAddress: "0xdeadbeef-00",
tokenOutAddress: "0xdeadbeef-00",
nftName: "Happy Meow NFT",
nftImageUrl: Style.png("collectibles/HappyMeow"),
chainId: "NETWORKID",
chainIdIn: "NETWORKID-IN",
chainIdOut: "NETWORKID-OUT"
}
},
{
activityEntry: {
timestamp: Date.now() / 1000,
status: 0,
amount: 123.45,
inAmount: 123.45,
outAmount: 123.45,
symbol: "SNT",
inSymbol: "SNT",
outSymbol: "SNT",
isMultiTransaction: false,
txType: 0,
sender: "0xfB8131c260749c7835a08ccBdb64728De432858E",
recipient: "0x3fb81384583b3910BB14Cc72582E8e8a56E83ae9",
isNFT: false,
isCommunityAssetViaAirdrop: false,
communityName: "Doodles",
communityImageUrl: Style.png("collectibles/HappyMeow"),
tokenID: "4981676894159712808201908443964193325271219637660871887967796332739046670337",
tokenAddress: "0xdeadbeef",
tokenInAddress: "0xdeadbeef-00",
tokenOutAddress: "0xdeadbeef-00",
nftName: "Happy Meow NFT",
nftImageUrl: Style.png("collectibles/HappyMeow"),
chainId: "NETWORKID",
chainIdIn: "NETWORKID-IN",
chainIdOut: "NETWORKID-OUT"
}
},
]
Component.onCompleted: append(rootData)
}

View File

@ -19,6 +19,7 @@ WalletAccountsModel 1.0 WalletAccountsModel.qml
WalletCollectiblesModel 1.0 WalletCollectiblesModel.qml WalletCollectiblesModel 1.0 WalletCollectiblesModel.qml
WalletKeyPairModel 1.0 WalletKeyPairModel.qml WalletKeyPairModel 1.0 WalletKeyPairModel.qml
WalletNestedCollectiblesModel 1.0 WalletNestedCollectiblesModel.qml WalletNestedCollectiblesModel 1.0 WalletNestedCollectiblesModel.qml
WalletTransactionsModel 1.0 WalletTransactionsModel.qml
GroupedAccountsAssetsModel 1.0 GroupedAccountsAssetsModel.qml GroupedAccountsAssetsModel 1.0 GroupedAccountsAssetsModel.qml
TokensBySymbolModel 1.0 TokensBySymbolModel.qml TokensBySymbolModel 1.0 TokensBySymbolModel.qml
CommunitiesModel 1.0 CommunitiesModel.qml CommunitiesModel 1.0 CommunitiesModel.qml

View File

@ -50,7 +50,8 @@ QtObject {
property var walletSectionSavedAddressesInst: walletSectionSavedAddresses property var walletSectionSavedAddressesInst: walletSectionSavedAddresses
property var totalCurrencyBalance: walletSectionInst.totalCurrencyBalance property var totalCurrencyBalance: walletSectionInst.totalCurrencyBalance
property var activityController: walletSectionInst.activityController property var activityController: walletSectionInst.activityController
property var tmpActivityController: walletSectionInst.tmpActivityController property var tmpActivityController0: walletSectionInst.tmpActivityController0
property var tmpActivityController1: walletSectionInst.tmpActivityController1
property string signingPhrase: walletSectionInst.signingPhrase property string signingPhrase: walletSectionInst.signingPhrase
property string mnemonicBackedUp: walletSectionInst.isMnemonicBackedUp property string mnemonicBackedUp: walletSectionInst.isMnemonicBackedUp
property var walletConnectController: walletSectionInst.walletConnectController property var walletConnectController: walletSectionInst.walletConnectController

View File

@ -8,7 +8,7 @@ import StatusQ.Core.Theme 0.1
import utils 1.0 import utils 1.0
import shared.controls 1.0 import shared.controls 1.0
import shared.views 1.0 import shared.views 1.0
import shared.stores 1.0 import shared.stores 1.0 as SharedStores
import shared.panels 1.0 import shared.panels 1.0
import "./" import "./"
@ -69,6 +69,8 @@ RightTabBaseView {
return "" return ""
} }
} }
readonly property var detailedCollectibleActivityController: RootStore.tmpActivityController0
} }
ColumnLayout { ColumnLayout {
@ -174,6 +176,12 @@ RightTabBaseView {
onCollectibleClicked: { onCollectibleClicked: {
RootStore.collectiblesStore.getDetailedCollectible(chainId, contractAddress, tokenId) RootStore.collectiblesStore.getDetailedCollectible(chainId, contractAddress, tokenId)
RootStore.setCurrentViewedHolding(uid, Constants.TokenType.ERC721) RootStore.setCurrentViewedHolding(uid, Constants.TokenType.ERC721)
d.detailedCollectibleActivityController.resetFilter()
d.detailedCollectibleActivityController.setFilterAddressesJson(JSON.stringify(RootStore.addressFilters.split(":")), RootStore.showAllAccounts)
d.detailedCollectibleActivityController.setFilterChainsJson(JSON.stringify([chainId]), false)
d.detailedCollectibleActivityController.setFilterCollectibles(JSON.stringify([uid]))
d.detailedCollectibleActivityController.updateFilter()
stack.currentIndex = 1 stack.currentIndex = 1
} }
onSendRequested: (symbol) => { onSendRequested: (symbol) => {
@ -212,10 +220,15 @@ RightTabBaseView {
CollectibleDetailView { CollectibleDetailView {
collectible: RootStore.collectiblesStore.detailedCollectible collectible: RootStore.collectiblesStore.detailedCollectible
isCollectibleLoading: RootStore.collectiblesStore.isDetailedCollectibleLoading isCollectibleLoading: RootStore.collectiblesStore.isDetailedCollectibleLoading
activityModel: d.detailedCollectibleActivityController.model
rootStore: SharedStores.RootStore
walletRootStore: RootStore
communitiesStore: root.communitiesStore
onVisibleChanged: { onVisibleChanged: {
if (!visible) if (!visible) {
RootStore.resetCurrentViewedHolding(Constants.TokenType.ERC721) RootStore.resetCurrentViewedHolding(Constants.TokenType.ERC721)
}
} }
} }
AssetsDetailView { AssetsDetailView {

View File

@ -11,6 +11,7 @@ import AppLayouts.Communities.panels 1.0
import utils 1.0 import utils 1.0
import shared.controls 1.0 import shared.controls 1.0
import shared.views 1.0
import "../../stores" import "../../stores"
import "../../controls" import "../../controls"
@ -18,7 +19,12 @@ import "../../controls"
Item { Item {
id: root id: root
property var collectible required property var rootStore
required property var walletRootStore
required property var communitiesStore
required property var collectible
property var activityModel
property bool isCollectibleLoading property bool isCollectibleLoading
readonly property int isNarrowMode : width < 700 readonly property int isNarrowMode : width < 700
@ -70,7 +76,7 @@ Item {
visible: root.isCommunityCollectible && (root.isOwnerTokenType || root.isTMasterTokenType) visible: root.isCommunityCollectible && (root.isOwnerTokenType || root.isTMasterTokenType)
size: root.isNarrowMode ? PrivilegedTokenArtworkPanel.Size.Medium : PrivilegedTokenArtworkPanel.Size.Large size: root.isNarrowMode ? PrivilegedTokenArtworkPanel.Size.Medium : PrivilegedTokenArtworkPanel.Size.Large
artwork: collectible.imageUrl artwork: collectible.imageUrl
color: !!collectible ? collectible.communityColor : "transparent" color: !!collectible && root.isCommunityCollectible? collectible.communityColor : "transparent"
isOwner: root.isOwnerTokenType isOwner: root.isOwnerTokenType
} }
@ -86,8 +92,8 @@ Item {
color: collectible.backgroundColor color: collectible.backgroundColor
border.color: Theme.palette.directColor8 border.color: Theme.palette.directColor8
border.width: 1 border.width: 1
mediaUrl: collectible.mediaUrl mediaUrl: collectible.mediaUrl ?? ""
mediaType: collectible.mediaType mediaType: collectible.mediaType ?? ""
fallbackImageUrl: collectible.imageUrl fallbackImageUrl: collectible.imageUrl
} }
@ -147,6 +153,11 @@ Item {
width: implicitWidth width: implicitWidth
text: qsTr("Properties") text: qsTr("Properties")
} }
StatusTabButton {
rightPadding: 0
width: implicitWidth
text: qsTr("Activity")
}
} }
StatusScrollView { StatusScrollView {
@ -154,15 +165,56 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
contentWidth: availableWidth contentWidth: availableWidth
Flow {
width: scrollView.availableWidth Loader {
spacing: 10 id: tabLoader
Repeater { Layout.fillWidth: true
model: collectible.traits Layout.fillHeight: true
InformationTile { sourceComponent: {
maxWidth: parent.width switch (collectiblesDetailsTab.currentIndex) {
primaryText: model.traitType case 0: return traitsView
secondaryText: model.value case 1: return activityView
}
}
Component {
id: traitsView
Flow {
width: scrollView.availableWidth
spacing: 10
Repeater {
model: collectible.traits
InformationTile {
maxWidth: parent.width
primaryText: model.traitType
secondaryText: model.value
}
}
}
}
Component {
id: activityView
StatusListView {
width: scrollView.availableWidth
height: scrollView.availableHeight
model: root.activityModel
delegate: TransactionDelegate {
required property var model
required property int index
width: parent.width
modelData: model.activityEntry
timeStampText: isModelDataValid ? LocaleUtils.formatRelativeTimestamp(modelData.timestamp * 1000, true) : ""
rootStore: root.rootStore
walletRootStore: root.walletRootStore
showAllAccounts: root.walletRootStore.showAllAccounts
displayValues: true
community: isModelDataValid && !!communityId && !!root.communitiesStore ? root.communitiesStore.getCommunityDetailsAsJson(communityId) : null
loading: false
onClicked: {
// TODO: Implement switch to transaction details screen
}
}
} }
} }
} }

View File

@ -1 +1,2 @@
CollectibleDetailView 1.0 CollectibleDetailView.qml
CollectibleView 1.0 CollectibleView.qml CollectibleView 1.0 CollectibleView.qml

View File

@ -37,6 +37,13 @@ Item {
None None
} }
QtObject {
id: d
// Use Layer1 controller since this could go on top of other activity lists
readonly property var activityController: root.store.tmpActivityController1
}
StatusTabBar { StatusTabBar {
id: accountSelectionTabBar id: accountSelectionTabBar
anchors.top: parent.top anchors.top: parent.top
@ -174,7 +181,7 @@ Item {
onClicked: recipientSelected(entry, TabAddressSelectorView.Type.RecentsAddress) onClicked: recipientSelected(entry, TabAddressSelectorView.Type.RecentsAddress)
} }
model: root.store.tmpActivityController.model model: d.activityController.model
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
@ -193,9 +200,9 @@ Item {
function updateRecentsActivity() { function updateRecentsActivity() {
if(root.selectedAccount) { if(root.selectedAccount) {
root.store.tmpActivityController.setFilterAddressesJson(JSON.stringify([root.selectedAccount.address], false)) d.activityController.setFilterAddressesJson(JSON.stringify([root.selectedAccount.address]), false)
} }
root.store.tmpActivityController.updateFilter() d.activityController.updateFilter()
} }
} }
} }

View File

@ -30,7 +30,8 @@ QtObject {
property var collectiblesModel: walletSectionSendInst.collectiblesModel property var collectiblesModel: walletSectionSendInst.collectiblesModel
property var nestedCollectiblesModel: walletSectionSendInst.nestedCollectiblesModel property var nestedCollectiblesModel: walletSectionSendInst.nestedCollectiblesModel
property bool areTestNetworksEnabled: networksModule.areTestNetworksEnabled property bool areTestNetworksEnabled: networksModule.areTestNetworksEnabled
property var tmpActivityController: walletSection.tmpActivityController property var tmpActivityController0: walletSection.tmpActivityController0
property var tmpActivityController1: walletSection.tmpActivityController1
property var savedAddressesModel: SortFilterProxyModel { property var savedAddressesModel: SortFilterProxyModel {
sourceModel: walletSectionSavedAddresses.model sourceModel: walletSectionSavedAddresses.model
filters: [ filters: [