2022-11-28 21:05:57 +00:00
|
|
|
import QtQuick 2.14
|
2021-10-21 08:22:05 +00:00
|
|
|
import QtQuick.Layouts 1.13
|
2024-03-27 21:49:46 +00:00
|
|
|
import SortFilterProxyModel 0.2
|
2021-10-21 08:22:05 +00:00
|
|
|
|
2024-03-27 21:49:46 +00:00
|
|
|
import StatusQ 0.1
|
2021-10-21 08:22:05 +00:00
|
|
|
import StatusQ.Components 0.1
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
import StatusQ.Core 0.1
|
|
|
|
import StatusQ.Controls 0.1
|
2023-03-06 16:46:32 +00:00
|
|
|
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
2021-10-21 08:22:05 +00:00
|
|
|
|
2023-09-20 13:01:37 +00:00
|
|
|
import AppLayouts.Communities.panels 1.0
|
|
|
|
|
2022-07-28 20:56:44 +00:00
|
|
|
import utils 1.0
|
|
|
|
import shared.controls 1.0
|
2024-02-26 02:32:59 +00:00
|
|
|
import shared.views 1.0
|
2022-07-28 20:56:44 +00:00
|
|
|
|
2021-12-06 21:10:54 +00:00
|
|
|
import "../../stores"
|
2021-10-21 08:22:05 +00:00
|
|
|
import "../../controls"
|
|
|
|
|
2022-07-28 20:56:44 +00:00
|
|
|
Item {
|
2021-10-21 08:22:05 +00:00
|
|
|
id: root
|
|
|
|
|
2024-02-29 14:53:08 +00:00
|
|
|
signal launchTransactionDetail(string txID)
|
|
|
|
|
2024-02-26 02:32:59 +00:00
|
|
|
required property var rootStore
|
|
|
|
required property var walletRootStore
|
|
|
|
required property var communitiesStore
|
|
|
|
|
|
|
|
required property var collectible
|
|
|
|
property var activityModel
|
2023-07-17 23:56:40 +00:00
|
|
|
property bool isCollectibleLoading
|
2024-03-27 21:49:46 +00:00
|
|
|
required property string addressFilters
|
2022-11-22 19:31:07 +00:00
|
|
|
|
2023-09-20 13:01:37 +00:00
|
|
|
// Community related token props:
|
2023-09-27 14:03:49 +00:00
|
|
|
readonly property bool isCommunityCollectible: !!collectible ? collectible.communityId !== "" : false
|
2023-09-20 13:01:37 +00:00
|
|
|
readonly property bool isOwnerTokenType: !!collectible ? (collectible.communityPrivilegesLevel === Constants.TokenPrivilegesLevel.Owner) : false
|
|
|
|
readonly property bool isTMasterTokenType: !!collectible ? (collectible.communityPrivilegesLevel === Constants.TokenPrivilegesLevel.TMaster) : false
|
|
|
|
|
2024-03-11 10:08:40 +00:00
|
|
|
readonly property var communityDetails: isCommunityCollectible ? root.communitiesStore.getCommunityDetailsAsJson(collectible.communityId) : null
|
|
|
|
|
2024-03-26 15:00:16 +00:00
|
|
|
QtObject {
|
|
|
|
id: d
|
2024-03-27 21:49:46 +00:00
|
|
|
readonly property string collectibleLink: !!collectible ? root.walletRootStore.getOpenSeaCollectibleUrl(collectible.networkShortName, collectible.contractAddress, collectible.tokenId): ""
|
|
|
|
readonly property string collectionLink: !!collectible ? root.walletRootStore.getOpenSeaCollectionUrl(collectible.networkShortName, collectible.contractAddress): ""
|
|
|
|
readonly property string blockExplorerLink: !!collectible ? root.walletRootStore.getExplorerUrl(collectible.networkShortName, collectible.contractAddress, collectible.tokenId): ""
|
|
|
|
readonly property var addrFilters: root.addressFilters.split(":").map((addr) => addr.toLowerCase())
|
|
|
|
readonly property int imageStackSpacing: 4
|
|
|
|
|
|
|
|
property Component balanceTag: Component {
|
|
|
|
CollectibleBalanceTag {
|
|
|
|
balance: d.balanceAggregator.value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
property SortFilterProxyModel filteredBalances: SortFilterProxyModel {
|
|
|
|
sourceModel: !!collectible ? collectible.ownership : null
|
|
|
|
filters: [
|
|
|
|
FastExpressionFilter {
|
|
|
|
expression: {
|
|
|
|
d.addrFilters
|
|
|
|
return d.addrFilters.includes(model.accountAddress.toLowerCase())
|
|
|
|
}
|
|
|
|
expectedRoles: ["accountAddress"]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
property SumAggregator balanceAggregator: SumAggregator {
|
|
|
|
model: d.filteredBalances
|
|
|
|
roleName: "balance"
|
|
|
|
}
|
2024-03-26 15:00:16 +00:00
|
|
|
}
|
|
|
|
|
2021-10-21 08:22:05 +00:00
|
|
|
CollectibleDetailsHeader {
|
|
|
|
id: collectibleHeader
|
2022-07-28 20:56:44 +00:00
|
|
|
anchors.top: parent.top
|
2021-10-21 08:22:05 +00:00
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
2024-03-27 21:49:46 +00:00
|
|
|
collectibleName: !!collectible && !!collectible.name ? collectible.name : qsTr("Unknown")
|
|
|
|
collectibleId: !!collectible ? "#" + collectible.tokenId : ""
|
2024-04-02 08:23:20 +00:00
|
|
|
communityName: !!communityDetails ? communityDetails.name : ""
|
2024-03-27 21:49:46 +00:00
|
|
|
communityId: !!collectible ? collectible.communityId : ""
|
|
|
|
collectionName: !!collectible ? collectible.collectionName : ""
|
|
|
|
communityImage: !!communityDetails ? communityDetails.image : ""
|
|
|
|
networkShortName: !!collectible ? collectible.networkShortName : ""
|
|
|
|
networkColor: !!collectible ?collectible.networkColor : ""
|
|
|
|
networkIconURL: !!collectible ? collectible.networkIconUrl : ""
|
|
|
|
networkExplorerName: !!collectible ? root.walletRootStore.getExplorerNameForNetwork(collectible.networkShortName): ""
|
2024-03-26 15:00:16 +00:00
|
|
|
collectibleLinkEnabled: Utils.getUrlStatus(d.collectibleLink)
|
|
|
|
collectionLinkEnabled: (!!communityDetails && communityDetails.name) || Utils.getUrlStatus(d.collectionLink)
|
|
|
|
explorerLinkEnabled: Utils.getUrlStatus(d.blockExplorerLink)
|
2024-03-11 10:08:40 +00:00
|
|
|
onCollectionTagClicked: {
|
|
|
|
if (root.isCommunityCollectible) {
|
|
|
|
Global.switchToCommunity(collectible.communityId)
|
|
|
|
}
|
2024-03-26 15:00:16 +00:00
|
|
|
else {
|
|
|
|
Global.openLinkWithConfirmation(d.collectionLink, root.walletRootStore.getOpenseaDomainName())
|
|
|
|
}
|
2024-03-11 10:08:40 +00:00
|
|
|
}
|
2024-03-26 15:00:16 +00:00
|
|
|
onOpenCollectibleExternally: Global.openLinkWithConfirmation(d.collectibleLink, root.walletRootStore.getOpenseaDomainName())
|
|
|
|
onOpenCollectibleOnExplorer: Global.openLinkWithConfirmation(d.blockExplorerLink, root.walletRootStore.getExplorerDomain(networkShortName))
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|
|
|
|
|
2024-03-26 15:00:16 +00:00
|
|
|
Column {
|
2022-11-28 21:05:57 +00:00
|
|
|
id: collectibleBody
|
2021-10-21 08:22:05 +00:00
|
|
|
anchors.top: collectibleHeader.bottom
|
2022-11-28 21:05:57 +00:00
|
|
|
anchors.topMargin: 25
|
2022-07-28 20:56:44 +00:00
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
|
|
|
|
spacing: Style.current.padding
|
2021-10-21 08:22:05 +00:00
|
|
|
|
|
|
|
Row {
|
|
|
|
id: collectibleImageDetails
|
2023-09-20 13:01:37 +00:00
|
|
|
|
2024-03-27 21:49:46 +00:00
|
|
|
readonly property real visibleImageHeight: artwork.height
|
|
|
|
readonly property real visibleImageWidth: artwork.width
|
2023-09-20 13:01:37 +00:00
|
|
|
|
2024-03-26 15:00:16 +00:00
|
|
|
height: collectibleImageDetails.visibleImageHeight
|
|
|
|
width: parent.width
|
2021-10-21 08:22:05 +00:00
|
|
|
spacing: 24
|
|
|
|
|
2024-03-27 21:49:46 +00:00
|
|
|
ColumnLayout {
|
|
|
|
id: artwork
|
|
|
|
spacing: 0
|
|
|
|
Repeater {
|
|
|
|
id: repeater
|
|
|
|
model: Math.min(3, d.balanceAggregator.value)
|
|
|
|
Item {
|
|
|
|
Layout.preferredWidth: childrenRect.width
|
|
|
|
Layout.preferredHeight: childrenRect.height
|
|
|
|
Layout.leftMargin: index * d.imageStackSpacing
|
|
|
|
Layout.topMargin: index === 0 ? 0 : -Layout.preferredHeight + d.imageStackSpacing
|
|
|
|
opacity: index === 0 ? 1: 0.4/index
|
|
|
|
// so that the first item remains on top in the stack
|
|
|
|
z: -index
|
|
|
|
Loader {
|
|
|
|
property int modelIndex: index
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.left: parent.left
|
|
|
|
sourceComponent: root.isCommunityCollectible && (root.isOwnerTokenType || root.isTMasterTokenType) ? privilegedCollectibleImage: collectibleimage
|
|
|
|
active: root.visible
|
|
|
|
}
|
|
|
|
Loader {
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.margins: Style.current.padding
|
|
|
|
sourceComponent: d.balanceTag
|
|
|
|
// only show balance tag on top of the first image in stack
|
|
|
|
active: index === 0 && d.balanceAggregator.value > 1 && root.visible
|
2024-03-30 05:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|
2022-11-28 21:05:57 +00:00
|
|
|
|
|
|
|
Column {
|
|
|
|
id: collectibleNameAndDescription
|
|
|
|
spacing: 12
|
|
|
|
|
2023-09-20 13:01:37 +00:00
|
|
|
width: parent.width - collectibleImageDetails.visibleImageWidth - Style.current.bigPadding
|
2022-11-28 21:05:57 +00:00
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
id: collectibleName
|
|
|
|
width: parent.width
|
|
|
|
height: 24
|
|
|
|
|
2024-03-27 21:49:46 +00:00
|
|
|
text: root.isCommunityCollectible && !!communityDetails ? qsTr("Minted by %1").arg(root.communityDetails.name):
|
|
|
|
!!collectible ? collectible.collectionName: ""
|
2022-11-28 21:05:57 +00:00
|
|
|
color: Theme.palette.directColor1
|
|
|
|
font.pixelSize: 17
|
|
|
|
lineHeight: 24
|
2024-03-11 10:08:40 +00:00
|
|
|
lineHeightMode: Text.FixedHeight
|
2022-11-28 21:05:57 +00:00
|
|
|
elide: Text.ElideRight
|
|
|
|
wrapMode: Text.WordWrap
|
|
|
|
}
|
|
|
|
|
2024-03-26 15:00:16 +00:00
|
|
|
StatusBaseText {
|
|
|
|
id: descriptionText
|
2022-11-28 21:05:57 +00:00
|
|
|
width: parent.width
|
|
|
|
height: collectibleImageDetails.height - collectibleName.height - parent.spacing
|
|
|
|
|
2024-03-26 15:00:16 +00:00
|
|
|
clip: true
|
2024-03-27 21:49:46 +00:00
|
|
|
text: !!collectible ? collectible.description : ""
|
2024-03-26 15:00:16 +00:00
|
|
|
textFormat: Text.MarkdownText
|
|
|
|
color: Theme.palette.directColor4
|
|
|
|
font.pixelSize: 15
|
|
|
|
lineHeight: 22
|
|
|
|
lineHeightMode: Text.FixedHeight
|
|
|
|
elide: Text.ElideRight
|
|
|
|
wrapMode: Text.Wrap
|
2022-11-28 21:05:57 +00:00
|
|
|
}
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-28 20:56:44 +00:00
|
|
|
StatusTabBar {
|
|
|
|
id: collectiblesDetailsTab
|
2024-03-26 15:00:16 +00:00
|
|
|
width: parent.width
|
|
|
|
topPadding: Style.current.xlPadding
|
2024-03-27 21:49:46 +00:00
|
|
|
visible: !!collectible && collectible.traits.count > 0
|
2021-10-21 08:22:05 +00:00
|
|
|
|
2022-07-28 20:56:44 +00:00
|
|
|
StatusTabButton {
|
|
|
|
leftPadding: 0
|
|
|
|
width: implicitWidth
|
|
|
|
text: qsTr("Properties")
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|
2024-02-26 02:32:59 +00:00
|
|
|
StatusTabButton {
|
|
|
|
rightPadding: 0
|
|
|
|
width: implicitWidth
|
|
|
|
text: qsTr("Activity")
|
|
|
|
}
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|
|
|
|
|
2022-11-28 21:05:57 +00:00
|
|
|
StatusScrollView {
|
|
|
|
id: scrollView
|
2024-03-26 15:00:16 +00:00
|
|
|
width: parent.width
|
|
|
|
height: parent.height
|
2023-05-31 20:58:23 +00:00
|
|
|
contentWidth: availableWidth
|
2024-02-26 02:32:59 +00:00
|
|
|
|
|
|
|
Loader {
|
|
|
|
id: tabLoader
|
2024-03-26 15:00:16 +00:00
|
|
|
width: parent.width
|
|
|
|
height: parent.height
|
|
|
|
|
2024-02-26 02:32:59 +00:00
|
|
|
sourceComponent: {
|
|
|
|
switch (collectiblesDetailsTab.currentIndex) {
|
|
|
|
case 0: return traitsView
|
|
|
|
case 1: return activityView
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: traitsView
|
|
|
|
Flow {
|
|
|
|
width: scrollView.availableWidth
|
|
|
|
spacing: 10
|
|
|
|
Repeater {
|
2024-03-27 21:49:46 +00:00
|
|
|
model: !!collectible ? collectible.traits: null
|
2024-02-26 02:32:59 +00:00
|
|
|
InformationTile {
|
|
|
|
maxWidth: parent.width
|
|
|
|
primaryText: model.traitType
|
|
|
|
secondaryText: model.value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: activityView
|
2024-03-27 21:49:46 +00:00
|
|
|
StatusListView {
|
2024-02-26 02:32:59 +00:00
|
|
|
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: {
|
2024-02-29 14:53:08 +00:00
|
|
|
if (mouse.button === Qt.RightButton) {
|
|
|
|
// TODO: Implement context menu
|
|
|
|
} else {
|
|
|
|
root.launchTransactionDetail(modelData.id)
|
|
|
|
}
|
2024-02-26 02:32:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-27 21:49:46 +00:00
|
|
|
Component {
|
|
|
|
id: privilegedCollectibleImage
|
|
|
|
// Special artwork representation for community `Owner and Master Token` token types:
|
|
|
|
PrivilegedTokenArtworkPanel {
|
|
|
|
size: PrivilegedTokenArtworkPanel.Size.Large
|
|
|
|
artwork: collectible.imageUrl ?? ""
|
|
|
|
color: !!root.collectible && !!root.communityDetails ? root.communityDetails.color : "transparent"
|
|
|
|
isOwner: root.isOwnerTokenType
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: collectibleimage
|
|
|
|
StatusRoundedMedia {
|
|
|
|
id: collectibleImage
|
|
|
|
readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString()
|
|
|
|
width: 248
|
|
|
|
height: width
|
|
|
|
radius: Style.current.radius
|
|
|
|
color: isError || isEmpty ? Theme.palette.baseColor5 : collectible.backgroundColor
|
|
|
|
border.color: Theme.palette.directColor8
|
|
|
|
border.width: 1
|
|
|
|
mediaUrl: collectible.mediaUrl ?? ""
|
|
|
|
mediaType: modelIndex === 0 && !!collectible ? collectible.mediaType : ""
|
|
|
|
fallbackImageUrl: collectible.imageUrl
|
|
|
|
|
|
|
|
Column {
|
|
|
|
anchors.centerIn: parent
|
|
|
|
visible: collectibleImage.isError || collectibleImage.isEmpty
|
|
|
|
spacing: 10
|
|
|
|
|
|
|
|
StatusIcon {
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
icon: "frowny"
|
|
|
|
opacity: 0.1
|
|
|
|
color: Theme.palette.directColor1
|
|
|
|
}
|
|
|
|
StatusBaseText {
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
|
|
color: Theme.palette.directColor6
|
|
|
|
text: {
|
|
|
|
if (collectibleImage.isError && collectibleImage.componentMediaType === StatusRoundedMedia.MediaType.Unkown) {
|
|
|
|
return qsTr("Unsupported\nfile format")
|
|
|
|
}
|
|
|
|
if (!collectible.description && !collectible.name) {
|
|
|
|
return qsTr("Info can't\nbe fetched")
|
|
|
|
}
|
|
|
|
return qsTr("Failed\nto load")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-21 08:22:05 +00:00
|
|
|
}
|