fix(wallet): Update collectibles media management (#16080)

This commit is contained in:
Cuteivist 2024-08-28 15:58:33 +02:00 committed by GitHub
parent ef9c2598cc
commit 658fe2a5b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 271 additions and 63 deletions

View File

@ -348,6 +348,14 @@ QtObject:
read = getTwitterHandle
notify = twitterHandleChanged
proc isMetadataValidChanged*(self: CollectiblesEntry) {.signal.}
proc getIsMetaDataValid*(self: CollectiblesEntry): bool {.slot.} =
return self.hasCollectibleData()
QtProperty[bool] isMetadataValid:
read = getIsMetaDataValid
notify = isMetadataValidChanged
proc updateDataIfSameID*(self: CollectiblesEntry, update: backend.Collectible): bool =
if self.id != update.id:
return false

View File

@ -39,8 +39,8 @@ QtObject:
read = getDetailedEntry
notify = detailedEntryChanged
proc getIsDetailedEntryLoading*(self: Controller): QVariant {.slot.} =
return newQVariant(self.detailedEntry)
proc getIsDetailedEntryLoading*(self: Controller): bool {.slot.} =
return self.isDetailedEntryLoading
proc isDetailedEntryLoadingChanged(self: Controller) {.signal.}

View File

@ -0,0 +1,129 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Storybook 1.0
import AppLayouts.Communities.stores 1.0 as CommunitiesStores
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 as SharedStores
import Models 1.0
import utils 1.0
SplitView {
id: root
// QtObject {
// function isValidURL(url) {
// return true
// }
// Component.onCompleted: {
// Utils.globalUtilsInst = this
// }
// Component.onDestruction: {
// Utils.globalUtilsInst = {}
// }
// }
QtObject {
id: d
readonly property QtObject collectiblesModel: ManageCollectiblesModel {
Component.onCompleted: {
d.refreshCurrentCollectible()
}
}
property var currentCollectible
function refreshCurrentCollectible() {
currentCollectible = ModelUtils.get(collectiblesModel, collectibleComboBox.currentIndex)
}
}
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: CollectibleMedia {
backgroundColor: d.currentCollectible.backgroundColor
isCollectibleLoading: isLoadingCheckbox.checked
isMetadataValid: !d.currentCollectible.isMetadataValid
mediaUrl: d.currentCollectible.mediaUrl ?? ""
fallbackImageUrl: d.currentCollectible.imageUrl
interactive: isInteractiveCheckbox.checked
enabled: isEnabledCheckbox.checked
}
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 { // Loading state when model is loading, it doesn't affect internal image loading state
id: isLoadingCheckbox
text: "isLoading"
checked: false
}
CheckBox {
id: isInteractiveCheckbox
text: "isInteractive"
checked: true
}
CheckBox {
id: isEnabledCheckbox
text: "isEnabled"
checked: true
}
}
}
}
// category: Wallet

View File

@ -134,7 +134,7 @@ Item {
const lvOther = findChild(controlUnderTest, "otherTokensListView")
verify(!!lvOther)
tryCompare(lvOther, "count", 9)
tryCompare(lvOther, "count", 10)
const delegate0 = findChild(lvOther, "manageTokensDelegate-0")
verify(!!delegate0)
const title = delegate0.title
@ -144,7 +144,7 @@ Item {
tryCompare(notificationSpy, "count", 1)
// verify we now have -1 regular tokens after the "hide" operation
tryCompare(lvOther, "count", 8)
tryCompare(lvOther, "count", 9)
}
function test_showHideCommunityGroup() {

View File

@ -64,7 +64,8 @@ ListModel {
],
tokenId: "403",
twitterHandle: "@punxNotDead",
website: "www.punxnotdead.com"
website: "www.punxnotdead.com",
isMetadataValid: true
},
{
uid: "pp23",
@ -109,7 +110,8 @@ ListModel {
],
tokenId: "123",
twitterHandle: "@pepepunks",
website: "www.pepepunks.com"
website: "www.pepepunks.com",
isMetadataValid: true
},
{
uid: "34545656768",
@ -154,7 +156,8 @@ ListModel {
],
tokenId: "7123",
twitterHandle: "@kitties",
website: "www.kitties.com"
website: "www.kitties.com",
isMetadataValid: true
},
{
uid: "123456",
@ -202,7 +205,8 @@ ListModel {
],
tokenId: "403123",
twitterHandle: "",
website: "www.kitties.com"
website: "www.kitties.com",
isMetadataValid: true
},
{
uid: "12345645459537432",
@ -252,7 +256,8 @@ ListModel {
],
tokenId: "1",
twitterHandle: "@kitties",
website: ""
website: "",
isMetadataValid: true
},
{
uid: "pp21",
@ -289,7 +294,8 @@ ListModel {
],
tokenId: "12568",
twitterHandle: "@pepepunks",
website: "www.pepepunks.com"
website: "www.pepepunks.com",
isMetadataValid: true
},
{
uid: "lp#666a",
@ -326,8 +332,42 @@ ListModel {
],
tokenId: "1445",
twitterHandle: "@lonelyPanda",
website: "www.lonelyPanda.com"
website: "www.lonelyPanda.com",
isMetadataValid: true
},
{
uid: "invalid#123",
chainId: 421613,
userHas: 0,
name: "",
collectionUid: "",
collectionName: "",
collectionImageUrl: "",
communityId: "",
communityName: "",
communityImage: "",
imageUrl: "",
isLoading: false,
backgroundColor: "",
permalink:"",
domain:"",
ownership: [
{
accountAddress: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
balance: "1",
txTimestamp: 19
},
],
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism,
description: "",
traits: [],
tokenId: "2121",
twitterHandle: "",
website: "",
isMetadataValid: false
}
]
readonly property var communityData: [
@ -356,7 +396,8 @@ ListModel {
networkIconUrl: ModelsData.networks.optimism,
description: "Frenly Pandas is a community for all the fiendly pandas! Welcome onboard and enjoy :)",
traits: [],
tokenId: "4"
tokenId: "4",
isMetadataValid: true
},
{
uid: "691",
@ -383,7 +424,8 @@ ListModel {
networkIconUrl: ModelsData.networks.optimism,
description: "Bearz is a community for all the ferocious Bearz! Welcome onboard and enjoy :)",
traits: [],
tokenId: "3"
tokenId: "3",
isMetadataValid: true
},
{
uid: "8876",
@ -410,7 +452,8 @@ ListModel {
networkIconUrl: ModelsData.networks.ethereum,
description: "Bearz is a community for all the ferocious Bearz! Welcome onboard and enjoy :)",
traits: [],
tokenId: "341"
tokenId: "341",
isMetadataValid: true
},
{
uid: "fp#3195",
@ -437,7 +480,8 @@ ListModel {
networkIconUrl: ModelsData.networks.ethereum,
description: "Frenly Pandas is a community for all the fiendly pandas! Welcome onboard and enjoy :)",
traits: [],
tokenId: "765"
tokenId: "765",
isMetadataValid: true
},
{
uid: "fp#4297",
@ -464,7 +508,8 @@ ListModel {
networkIconUrl: ModelsData.networks.ethereum,
description: "Frenly Pandas is a community for all the fiendly pandas! Welcome onboard and enjoy :)",
traits: [],
tokenId: "166"
tokenId: "166",
isMetadataValid: true
},
{
uid: "fp#909",
@ -491,7 +536,8 @@ ListModel {
networkIconUrl: ModelsData.networks.optimism,
description: "Frenly Pandas is a community for all the fiendly pandas! Welcome onboard and enjoy :)",
traits: [],
tokenId: "1111"
tokenId: "1111",
isMetadataValid: true
},
{
uid: "lb#666",
@ -523,7 +569,8 @@ ListModel {
networkIconUrl: ModelsData.networks.optimism,
description: "Bearz is a community for all the ferocious Bearz! Welcome onboard and enjoy",
traits: [],
tokenId: "6"
tokenId: "6",
isMetadataValid: true
},
{
uid: "lb#777",
@ -550,7 +597,8 @@ ListModel {
networkIconUrl: ModelsData.networks.optimism,
description: "Lonely Turtle is a community for all of us to talk and communicate! Welcome onboard and enjoy",
traits: [],
tokenId: "7"
tokenId: "7",
isMetadataValid: true
},
{
uid: "ID-Custom",
@ -575,7 +623,8 @@ ListModel {
communityId: "",
networkShortName: "ARB",
networkColor: "blue",
networkIconUrl: ModelsData.networks.arbitrum
networkIconUrl: ModelsData.networks.arbitrum,
isMetadataValid: true
},
{
uid: "ID-MissingMetadata",
@ -600,7 +649,8 @@ ListModel {
communityId: "",
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism
networkIconUrl: ModelsData.networks.optimism,
isMetadataValid: true
},
{
uid: "ID-Community1",
@ -625,7 +675,8 @@ ListModel {
communityId: "community-id-1",
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism
networkIconUrl: ModelsData.networks.optimism,
isMetadataValid: true
},
{
uid: "ID-Community-Unknown",
@ -650,7 +701,8 @@ ListModel {
communityId: "community-id-unknown",
networkShortName: "OPT",
networkColor: "red",
networkIconUrl: ModelsData.networks.optimism
networkIconUrl: ModelsData.networks.optimism,
isMetadataValid: true
}
]

View File

@ -238,7 +238,7 @@ StatusScrollView {
delegate: CollectibleView {
height: collectiblesGrid.cellHeight
width: collectiblesGrid.cellWidth
title: model.name ? model.name : "..."
title: model.name ?? ""
subTitle: deployState === Constants.ContractTransactionStatus.Completed ?
d.getRemainingInfo(model.privilegesLevel === Constants.TokenPrivilegesLevel.Owner,
model.privilegesLevel === Constants.TokenPrivilegesLevel.TMaster,
@ -251,6 +251,7 @@ StatusScrollView {
fallbackImageUrl: model.image ? model.image : ""
backgroundColor: "transparent"
isLoading: false
isMetadataValid: true
navigationIconVisible: false
privilegesLevel: model.privilegesLevel
ornamentColor: model.color

View File

@ -92,7 +92,7 @@ ColumnLayout {
clear()
if (d.isLoading) {
for (let i = 0; i < 10; i++) {
append({ isLoading: true })
append({ isLoading: true, name: qsTr("Loading collectible...") })
}
}
}
@ -497,13 +497,14 @@ ColumnLayout {
CollectibleView {
width: d.cellWidth
height: isCommunityCollectible ? d.communityCellHeight : d.cellHeight
title: model.name ? model.name : "..."
title: model.name ?? ""
subTitle: model.collectionName ? model.collectionName : model.collectionUid ? model.collectionUid : ""
mediaUrl: model.mediaUrl ?? ""
mediaType: model.mediaType ?? ""
fallbackImageUrl: model.imageUrl ?? ""
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent"
isLoading: !!model.isLoading
isMetadataValid: !!model.isMetadataValid
privilegesLevel: model.communityPrivilegesLevel ?? Constants.TokenPrivilegesLevel.Community
ornamentColor: model.communityColor ?? "transparent"
communityId: model.communityId ?? ""

View File

@ -361,11 +361,11 @@ Item {
Component {
id: collectibleimageComponent
StatusRoundedMedia {
CollectibleMedia {
id: collectibleImage
readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString()
radius: Style.current.radius
color: isError || isEmpty ? Theme.palette.baseColor5 : collectible.backgroundColor
backgroundColor: collectible.backgroundColor
isCollectibleLoading: root.isCollectibleLoading
isMetadataValid: !collectible.isMetadataValid
mediaUrl: collectible.mediaUrl ?? ""
mediaType: !!collectible ? (modelIndex > 0 && collectible.mediaType.startsWith("video")) ? "" : collectible.mediaType: ""
fallbackImageUrl: collectible.imageUrl
@ -377,29 +377,6 @@ Item {
onOpenImageContextMenu: (url, isGif) => Global.openMenu(imageContextMenu, collectibleImage, { imageSource: url, isGif: isGif, isVideo: false })
onOpenVideoContextMenu: (url) => Global.openMenu(imageContextMenu, collectibleImage, { imageSource: url, url: url, isVideo: true, isGif: false })
Loader {
anchors.fill: parent
active: collectibleImage.isLoading
sourceComponent: LoadingComponent {radius: collectibleImage.radius}
}
Loader {
anchors.fill: parent
active: collectibleImage.isError || collectibleImage.isEmpty
sourceComponent: LoadingErrorComponent {
radius: collectibleImage.radius
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")
}
}
}
Component {
id: imageContextMenu
ImageContextMenu {

View File

@ -0,0 +1,42 @@
import QtQuick 2.14
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
StatusRoundedMedia {
id: root
readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString()
property color backgroundColor: Theme.palette.baseColor5
property bool isCollectibleLoading: false
property bool isMetadataValid: false
radius: Style.current.radius
color: isError || isEmpty ? Theme.palette.baseColor5 : backgroundColor
Loader {
id: loadingCompLoader
anchors.fill: parent
active: root.isCollectibleLoading || root.isLoading
sourceComponent: LoadingComponent {radius: root.radius}
}
Loader {
anchors.fill: parent
active: (root.isError || root.isEmpty) && !loadingCompLoader.active
sourceComponent: LoadingErrorComponent {
radius: root.radius
text: {
if (root.isError && root.componentMediaType === StatusRoundedMedia.MediaType.Unkown) {
return qsTr("Unsupported\nfile format")
}
if (!root.isMetadataValid) {
return qsTr("Info can't\nbe fetched")
}
return qsTr("Failed\nto load")
}
}
}
}

View File

@ -16,6 +16,7 @@ Control {
id: root
property string title: ""
property string unknownTitle: "..."
property string subTitle: ""
property alias subTitleColor: subTitleItem.customColor
property string backgroundColor: "transparent"
@ -24,6 +25,7 @@ Control {
property url fallbackImageUrl : ""
property bool isLoading: false
property bool navigationIconVisible: false
property bool isMetadataValid: false
property string communityId: ""
property string communityName
property string communityImage
@ -77,7 +79,7 @@ Control {
contentItem: ColumnLayout {
spacing: 0
StatusRoundedMedia {
CollectibleMedia {
id: image
Layout.alignment: Qt.AlignHCenter
@ -85,21 +87,16 @@ Control {
Layout.fillWidth: true
Layout.preferredHeight: width
backgroundColor: root.isLoading ? "transparent" : root.backgroundColor
visible: !specialCollectible.visible
radius: Style.current.radius
isMetadataValid: root.isMetadataValid
mediaUrl: root.mediaUrl
mediaType: root.mediaType
fallbackImageUrl: root.fallbackImageUrl
showLoadingIndicator: true
color: root.isLoading ? "transparent" : root.backgroundColor
isCollectibleLoading: root.isLoading
fillMode: Image.PreserveAspectCrop
Loader {
anchors.fill: parent
active: root.isLoading
sourceComponent: LoadingComponent {radius: image.radius}
}
Loader {
anchors.top: parent.top
anchors.left: parent.left
@ -150,7 +147,7 @@ Control {
customColor: Theme.palette.directColor1
font.weight: Font.DemiBold
elide: Text.ElideRight
text: root.isLoading ? Constants.dummyText : root.title
text: root.isLoading ? Constants.dummyText : root.title || root.unknownTitle
loading: root.isLoading
}

View File

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