feat(@desktop/wallet): add support for more NFTs media types
Fixes #9836
This commit is contained in:
parent
99a9f2ace0
commit
ed6ea5d90c
|
@ -65,113 +65,91 @@ QtObject:
|
|||
read = getNetworkIconUrl
|
||||
notify = networkIconUrlChanged
|
||||
|
||||
proc currentCollectibleChanged(self: View) {.signal.}
|
||||
|
||||
proc getName(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getName())
|
||||
|
||||
proc nameChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] name:
|
||||
read = getName
|
||||
notify = nameChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getID(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getId())
|
||||
|
||||
proc idChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] id:
|
||||
read = getID
|
||||
notify = idChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getTokenID(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getTokenId().toString())
|
||||
|
||||
proc tokenIdChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] tokenId:
|
||||
read = getTokenID
|
||||
notify = tokenIdChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getDescription(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getDescription())
|
||||
|
||||
proc descriptionChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] description:
|
||||
read = getDescription
|
||||
notify = descriptionChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getBackgroundColor(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getBackgroundColor())
|
||||
|
||||
proc backgroundColorChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] backgroundColor:
|
||||
read = getBackgroundColor
|
||||
notify = backgroundColorChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getMediaUrl(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getMediaUrl())
|
||||
QtProperty[QVariant] mediaUrl:
|
||||
read = getMediaUrl
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getMediaType(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getMediaType())
|
||||
QtProperty[QVariant] mediaType:
|
||||
read = getMediaType
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getImageUrl(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getImageUrl())
|
||||
|
||||
proc imageUrlChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] imageUrl:
|
||||
read = getImageUrl
|
||||
notify = imageUrlChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getCollectionName(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getCollectionName())
|
||||
|
||||
proc collectionNameChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] collectionName:
|
||||
read = getCollectionName
|
||||
notify = collectionNameChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getCollectionImageUrl(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getCollectionImageUrl())
|
||||
|
||||
proc collectionImageUrlChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] collectionImageUrl:
|
||||
read = getCollectionImageUrl
|
||||
notify = collectionImageUrlChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getPermalink(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.collectible.getPermalink())
|
||||
|
||||
proc permalinkChanged(self: View) {.signal.}
|
||||
|
||||
QtProperty[QVariant] permalink:
|
||||
read = getPermalink
|
||||
notify = permalinkChanged
|
||||
|
||||
proc propertiesChanged(self: View) {.signal.}
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getProperties*(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.propertiesModel)
|
||||
|
||||
QtProperty[QVariant] properties:
|
||||
read = getProperties
|
||||
notify = propertiesChanged
|
||||
|
||||
proc rankingsChanged(self: View) {.signal.}
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getRankings*(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.rankingsModel)
|
||||
|
||||
QtProperty[QVariant] rankings:
|
||||
read = getRankings
|
||||
notify = rankingsChanged
|
||||
|
||||
proc statsChanged(self: View) {.signal.}
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc getStats*(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.statsModel)
|
||||
|
||||
QtProperty[QVariant] stats:
|
||||
read = getStats
|
||||
notify = statsChanged
|
||||
notify = currentCollectibleChanged
|
||||
|
||||
proc update*(self: View, address: string, tokenId: string) {.slot.} =
|
||||
self.delegate.update(address, parse(tokenId, Uint256))
|
||||
|
@ -190,20 +168,8 @@ QtObject:
|
|||
self.networkIconUrlChanged()
|
||||
|
||||
self.collectible = collectible
|
||||
self.collectionNameChanged()
|
||||
self.collectionImageUrlChanged()
|
||||
self.nameChanged()
|
||||
self.idChanged()
|
||||
self.tokenIdChanged()
|
||||
self.descriptionChanged()
|
||||
self.backgroundColorChanged()
|
||||
self.imageUrlChanged()
|
||||
|
||||
self.propertiesModel.setItems(collectible.getProperties())
|
||||
self.propertiesChanged()
|
||||
|
||||
self.rankingsModel.setItems(collectible.getRankings())
|
||||
self.rankingsChanged()
|
||||
|
||||
self.statsModel.setItems(collectible.getStats())
|
||||
self.statsChanged()
|
||||
|
||||
self.currentCollectibleChanged()
|
|
@ -7,6 +7,8 @@ type
|
|||
address: string
|
||||
tokenId: UInt256
|
||||
name: string
|
||||
mediaUrl: string
|
||||
mediaType: string
|
||||
imageUrl: string
|
||||
backgroundColor: string
|
||||
description: string
|
||||
|
@ -25,6 +27,8 @@ proc initItem*(
|
|||
address: string,
|
||||
tokenId: UInt256,
|
||||
name: string,
|
||||
mediaUrl: string,
|
||||
mediaType: string,
|
||||
imageUrl: string,
|
||||
backgroundColor: string,
|
||||
description: string,
|
||||
|
@ -41,6 +45,8 @@ proc initItem*(
|
|||
result.address = address
|
||||
result.tokenId = tokenId
|
||||
result.name = if (name != ""): name else: ("#" & tokenId.toString())
|
||||
result.mediaUrl = mediaUrl
|
||||
result.mediaType = mediaType
|
||||
result.imageUrl = imageUrl
|
||||
result.backgroundColor = if (backgroundColor == ""): "transparent" else: ("#" & backgroundColor)
|
||||
result.description = description
|
||||
|
@ -55,7 +61,7 @@ proc initItem*(
|
|||
result.isPinned = isPinned
|
||||
|
||||
proc initItem*: Item =
|
||||
result = initItem(-1, "", u256(0), "", "", "transparent", "Collectibles", "", @[], @[], @[], "", "", "", false)
|
||||
result = initItem(-1, "", u256(0), "", "", "", "", "transparent", "Collectibles", "", @[], @[], @[], "", "", "", false)
|
||||
|
||||
proc initLoadingItem*: Item =
|
||||
result = initItem()
|
||||
|
@ -67,6 +73,8 @@ proc `$`*(self: Item): string =
|
|||
address: {self.address},
|
||||
tokenId: {self.tokenId},
|
||||
name: {self.name},
|
||||
mediaUrl: {self.mediaUrl},
|
||||
mediaType: {self.mediaType},
|
||||
imageUrl: {self.imageUrl},
|
||||
backgroundColor: {self.backgroundColor},
|
||||
description: {self.description},
|
||||
|
@ -90,6 +98,12 @@ proc getTokenId*(self: Item): UInt256 =
|
|||
proc getName*(self: Item): string =
|
||||
return self.name
|
||||
|
||||
proc getMediaUrl*(self: Item): string =
|
||||
return self.mediaUrl
|
||||
|
||||
proc getMediaType*(self: Item): string =
|
||||
return self.mediaType
|
||||
|
||||
proc getImageUrl*(self: Item): string =
|
||||
return self.imageUrl
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ type
|
|||
Address
|
||||
TokenId
|
||||
Name
|
||||
MediaUrl
|
||||
MediaType
|
||||
ImageUrl
|
||||
BackgroundColor
|
||||
Description
|
||||
|
@ -118,6 +120,8 @@ QtObject:
|
|||
CollectibleRole.Address.int:"address",
|
||||
CollectibleRole.TokenId.int:"tokenId",
|
||||
CollectibleRole.Name.int:"name",
|
||||
CollectibleRole.MediaUrl.int:"mediaUrl",
|
||||
CollectibleRole.MediaType.int:"mediaType",
|
||||
CollectibleRole.ImageUrl.int:"imageUrl",
|
||||
CollectibleRole.BackgroundColor.int:"backgroundColor",
|
||||
CollectibleRole.Description.int:"description",
|
||||
|
@ -151,6 +155,10 @@ QtObject:
|
|||
result = newQVariant(item.getTokenId().toString())
|
||||
of CollectibleRole.Name:
|
||||
result = newQVariant(item.getName())
|
||||
of CollectibleRole.MediaUrl:
|
||||
result = newQVariant(item.getMediaUrl())
|
||||
of CollectibleRole.MediaType:
|
||||
result = newQVariant(item.getMediaType())
|
||||
of CollectibleRole.ImageUrl:
|
||||
result = newQVariant(item.getImageUrl())
|
||||
of CollectibleRole.BackgroundColor:
|
||||
|
|
|
@ -3,11 +3,19 @@ import ../../../../../../app_service/service/collectible/dto
|
|||
import collectibles_item, collectible_trait_item
|
||||
|
||||
proc collectibleToItem*(c: CollectibleDto, co: CollectionDto, isPinned: bool = false) : Item =
|
||||
var mediaUrl = c.animationUrl
|
||||
var mediaType = c.animationMediaType
|
||||
if mediaUrl == "":
|
||||
mediaUrl = c.imageUrl
|
||||
mediaType = "image"
|
||||
|
||||
return initItem(
|
||||
c.id,
|
||||
c.address,
|
||||
c.tokenId,
|
||||
c.name,
|
||||
mediaUrl,
|
||||
mediaType,
|
||||
c.imageUrl,
|
||||
c.backgroundColor,
|
||||
c.description,
|
||||
|
|
|
@ -24,7 +24,7 @@ type CollectibleTrait* = ref object
|
|||
type CollectibleDto* = ref object
|
||||
id*: int
|
||||
tokenId*: Uint256
|
||||
address*, collectionSlug*, name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, backgroundColor*: string
|
||||
address*, collectionSlug*, name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, animationUrl*, animationMediaType*, backgroundColor*: string
|
||||
properties*, rankings*, statistics*: seq[CollectibleTrait]
|
||||
|
||||
proc newCollectibleDto*: CollectibleDto =
|
||||
|
@ -51,10 +51,27 @@ proc isNumeric(s: string): bool =
|
|||
result = false
|
||||
|
||||
proc `$`*(self: CollectionDto): string =
|
||||
return fmt"CollectionDto(name:{self.name}, slug:{self.slug})"
|
||||
return fmt"""CollectionDto(
|
||||
name:{self.name},
|
||||
slug:{self.slug},
|
||||
imageUrl:{self.imageUrl}
|
||||
"""
|
||||
|
||||
proc `$`*(self: CollectibleDto): string =
|
||||
return fmt"CollectibleDto(id:{self.id}, address:{self.address}, tokenId:{self.tokenId}, collectionSlug:{self.collectionSlug}, name:{self.name}, description:{self.description}, permalink:{self.permalink}, imageUrl: {self.imageUrl}, imageThumbnailUrl: {self.imageThumbnailUrl}, backgroundColor: {self.backgroundColor})"
|
||||
return fmt"""CollectibleDto(
|
||||
id:{self.id},
|
||||
address:{self.address},
|
||||
tokenId:{self.tokenId},
|
||||
collectionSlug:{self.collectionSlug},
|
||||
name:{self.name},
|
||||
description:{self.description},
|
||||
permalink:{self.permalink},
|
||||
imageUrl: {self.imageUrl},
|
||||
imageThumbnailUrl: {self.imageThumbnailUrl},
|
||||
animationUrl: {self.animationUrl},
|
||||
animationMediaType: {self.animationMediaType},
|
||||
backgroundColor: {self.backgroundColor})
|
||||
"""
|
||||
|
||||
proc getCollectionTraits*(jsonCollection: JsonNode): Table[string, CollectionTrait] =
|
||||
var traitList: Table[string, CollectionTrait] = initTable[string, CollectionTrait]()
|
||||
|
@ -98,6 +115,8 @@ proc toCollectibleDto*(jsonAsset: JsonNode): CollectibleDto =
|
|||
permalink: jsonAsset{"permalink"}.getStr,
|
||||
imageThumbnailUrl: jsonAsset{"image_thumbnail_url"}.getStr,
|
||||
imageUrl: jsonAsset{"image_url"}.getStr,
|
||||
animationUrl: jsonAsset{"animation_url"}.getStr,
|
||||
animationMediaType: jsonAsset{"animation_media_type"}.getStr,
|
||||
backgroundColor: jsonAsset{"background_color"}.getStr,
|
||||
properties: getTrait(jsonAsset, CollectibleTraitType.Properties),
|
||||
rankings: getTrait(jsonAsset, CollectibleTraitType.Rankings),
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
\list
|
||||
\li \l{StatusAddress}
|
||||
\li \l{StatusAnimatedImage}
|
||||
\li \l{StatusBadge}
|
||||
\li \l{StatusChatInfoToolBar}
|
||||
\li \l{StatusChatListAndCategories}
|
||||
|
@ -22,6 +23,7 @@
|
|||
\li \l{StatusExpandableItem}
|
||||
\li \l{StatusFlowSelector}
|
||||
\li \l{StatusGroupBox}
|
||||
\li \l{StatusImage}
|
||||
\li \l{StatusImageSettings}
|
||||
\li \l{StatusItemSelector}
|
||||
\li \l{StatusLetterIdenticon}
|
||||
|
@ -37,7 +39,9 @@
|
|||
\li \l{StatusNavigationListItem}
|
||||
\li \l{StatusNavigationPanelHeadline}
|
||||
\li \l{StatusRoundIcon}
|
||||
\li \l{StatusRoundedComponent}
|
||||
\li \l{StatusRoundedImage}
|
||||
\li \l{StatusRoundedMedia}
|
||||
\li \l{StatusMacWindowButtons}
|
||||
\li \l{StatusListItemBadge}
|
||||
\li \l{StatusExpandableItem}
|
||||
|
@ -45,6 +49,7 @@
|
|||
\li \l{StatusSmartIdenticon}
|
||||
\li \l{StatusTagSelector}
|
||||
\li \l{StatusToastMessage}
|
||||
\li \l{StatusVideo}
|
||||
\li \l{StatusWizardStepper}
|
||||
\endlist
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import QtQuick 2.13
|
||||
|
||||
/*!
|
||||
\qmltype StatusAnimatedImage
|
||||
\inherits AnimatedImage
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Draws an animated image. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-animatedimage.html}{AnimatedImage}.
|
||||
|
||||
This is a plain wrapper for the AnimatedImage QML type. It sets some default property values and
|
||||
adds some properties common to other media type wrappers.
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusAnimatedImage {
|
||||
width: 100
|
||||
height: 100
|
||||
source: "qrc:/demoapp/data/logo-test-image.gif"
|
||||
}
|
||||
\endqml
|
||||
|
||||
*/
|
||||
AnimatedImage {
|
||||
id: root
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusAnimatedImage::isLoading
|
||||
|
||||
\c true when the image is currently being loaded (status === AnimatedImage.Loading).
|
||||
\c false otherwise.
|
||||
|
||||
*/
|
||||
readonly property bool isLoading: status === AnimatedImage.Loading
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusAnimatedImage::isError
|
||||
|
||||
\c true when an error occurred while loading the image (status === AnimatedImage.Error).
|
||||
\c false otherwise.
|
||||
\note Setting an empty source is not considered an error.
|
||||
|
||||
*/
|
||||
readonly property bool isError: status === AnimatedImage.Error
|
||||
|
||||
fillMode: AnimatedImage.PreserveAspectFit
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import QtQuick 2.13
|
||||
|
||||
/*!
|
||||
\qmltype StatusImage
|
||||
\inherits Image
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Draws an image. Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-image.html}{Image}.
|
||||
|
||||
This is a plain wrapper for the Image QML type. It sets some default property values and
|
||||
adds some properties common to other media type wrappers.
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusImage {
|
||||
anchors.fill: parent
|
||||
|
||||
width: 100
|
||||
height: 100
|
||||
source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
}
|
||||
\endqml
|
||||
|
||||
*/
|
||||
Image {
|
||||
id: root
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusAnimatedImage::isLoading
|
||||
|
||||
\c true when the image is currently being loaded (status === Image.Loading).
|
||||
\c false otherwise.
|
||||
|
||||
*/
|
||||
readonly property bool isLoading: status === Image.Loading
|
||||
/*!
|
||||
\qmlproperty bool StatusAnimatedImage::isError
|
||||
|
||||
\c true when an error occurred while loading the image (status === Image.Error).
|
||||
\c false otherwise.
|
||||
\note Setting an empty source is not considered an error.
|
||||
|
||||
*/
|
||||
readonly property bool isError: status === Image.Error
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
onSourceChanged: {
|
||||
if (sourceSize.width < width || sourceSize.height < height) {
|
||||
sourceSize = Qt.binding(() => Qt.size(width * 2, height * 2))
|
||||
} else {
|
||||
sourceSize = undefined
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import QtQuick 2.13
|
||||
import QtGraphicalEffects 1.0
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusRoundedComponent
|
||||
\inherits Rectangle
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Base component . Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-rectangle.html}{Rectangle}.
|
||||
|
||||
This is a base component for content wrapped by a Rectangle with an optional Loading animation.
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusRoundedComponent {
|
||||
isLoading: image.isLoading
|
||||
isError: image.isError
|
||||
showLoadingIndicator: true
|
||||
|
||||
image.source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
|
||||
StatusImage {
|
||||
id: image
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
\endqml
|
||||
|
||||
*/
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusRoundedComponent::showLoadingIndicator
|
||||
|
||||
Set to \c true to enable the Loading animation.
|
||||
Set to \c false to disable the Loading animation.
|
||||
\note When enabled, the animation will be shown only when isLoading is \c true and
|
||||
isError is \c false.
|
||||
*/
|
||||
property bool showLoadingIndicator: false
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusRoundedComponent::isLoading
|
||||
|
||||
Set to \c true when the content is loading.
|
||||
Set to \c false when the content is finished loading.
|
||||
*/
|
||||
property bool isLoading: false
|
||||
|
||||
/*!
|
||||
\qmlproperty bool StatusRoundedComponent::isError
|
||||
|
||||
Set to \c true when some error occured while loading the content.
|
||||
Set to \c false when if the content's state is normal.
|
||||
*/
|
||||
property bool isError: false
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
color: "transparent"
|
||||
radius: width / 2
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
x: root.x; y: root.y
|
||||
width: root.width
|
||||
height: root.height
|
||||
radius: root.radius
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: itemSelector
|
||||
anchors.centerIn: parent
|
||||
active: showLoadingIndicator && !isError && isLoading
|
||||
sourceComponent: StatusLoadingIndicator {
|
||||
color: Theme.palette.directColor6
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,53 +3,31 @@ import QtGraphicalEffects 1.0
|
|||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
/*!
|
||||
\qmltype StatusRoundedImage
|
||||
\inherits StatusRoundedComponent
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Specialization of StatusRoundedComponent with a StatusImage as content.
|
||||
|
||||
property bool showLoadingIndicator: false
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusRoundedImage {
|
||||
image.source: "qrc:/demoapp/data/logo-test-image.png"
|
||||
}
|
||||
\endqml
|
||||
*/
|
||||
StatusRoundedComponent {
|
||||
id: root
|
||||
|
||||
property alias image: image
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
color: "transparent"
|
||||
radius: width / 2
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
x: root.x; y: root.y
|
||||
width: root.width
|
||||
height: root.height
|
||||
radius: root.radius
|
||||
}
|
||||
}
|
||||
isLoading: image.isLoading
|
||||
isError: image.isError
|
||||
|
||||
Image {
|
||||
StatusImage {
|
||||
id: image
|
||||
|
||||
width: root.width
|
||||
height: root.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.centerIn: parent
|
||||
|
||||
onSourceChanged: {
|
||||
if (sourceSize.width < width || sourceSize.height < height) {
|
||||
sourceSize = Qt.binding(() => Qt.size(width * 2, height * 2))
|
||||
} else {
|
||||
sourceSize = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: itemSelector
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
active: showLoadingIndicator && image.status === Image.Loading
|
||||
|
||||
sourceComponent: StatusLoadingIndicator {
|
||||
color: Theme.palette.directColor6
|
||||
}
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
import QtQuick 2.15
|
||||
import QtQml 2.15
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
/*!
|
||||
\qmltype StatusRoundedMedia
|
||||
\inherits StatusRoundedComponent
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Specialization of StatusRoundedComponent which handles different media types as content.
|
||||
|
||||
This component is a StatusRoundedComponent which is able to display several types of media using
|
||||
the corresponding component according to the provided \l{https://www.iana.org/assignments/media-types/media-types.xhtml}{media type},
|
||||
with the posibility of diplaying a fallback image if the media fails to load properly.
|
||||
|
||||
The list of supported media types and how the component to display them is chosen is the following:
|
||||
|
||||
- \c image
|
||||
Initially, we try to display the media using StatusAnimatedImage. If loading fails, we try using
|
||||
StatusImage. If that results in an error as well, we display the fallback image using StatusImage.
|
||||
|
||||
- \c video
|
||||
Initially, we try to display the media using StatusVideo. If that results in an error,
|
||||
we display the fallback image using StatusImage.
|
||||
|
||||
- For any other media type, we default to showing the fallback image using StatusImage.
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusRoundedMedia {
|
||||
width: 100
|
||||
height: 100
|
||||
mediaUrl: "qrc:/demoapp/data/test-video.avi"
|
||||
mediaType: "video"
|
||||
fallbackImageUrl: "qrc:/demoapp/data/test-image.png"
|
||||
}
|
||||
\endqml
|
||||
*/
|
||||
StatusRoundedComponent {
|
||||
id: root
|
||||
|
||||
enum MediaType {
|
||||
Image,
|
||||
Video,
|
||||
Unknown
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlproperty url StatusRoundedMedia::mediaUrl
|
||||
|
||||
Used to set the source for the main media we want to display.
|
||||
|
||||
*/
|
||||
property url mediaUrl
|
||||
|
||||
/*!
|
||||
\qmlproperty string StatusRoundedMedia::mediaType
|
||||
|
||||
\l{https://www.iana.org/assignments/media-types/media-types.xhtml}{Media type} corresponding to the media pointed to by mediaUrl.
|
||||
|
||||
*/
|
||||
property string mediaType
|
||||
|
||||
/*!
|
||||
\qmlproperty url StatusRoundedMedia::fallbackImageUrl
|
||||
|
||||
Image shown in case attempting to load the media pointed to by mediaUrl results in an error.
|
||||
|
||||
*/
|
||||
property url fallbackImageUrl
|
||||
|
||||
readonly property int componentMediaType: {
|
||||
if (root.mediaType.startsWith("image")) {
|
||||
return StatusRoundedMedia.MediaType.Image
|
||||
} else if (root.mediaType.startsWith("video")) {
|
||||
return StatusRoundedMedia.MediaType.Video
|
||||
}
|
||||
return StatusRoundedMedia.MediaType.Unknown
|
||||
}
|
||||
|
||||
isLoading: {
|
||||
if (mediaLoader.status === Loader.Ready) {
|
||||
return mediaLoader.item.isLoading
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
Binding on isError {
|
||||
when: mediaLoader.status === Loader.Ready
|
||||
value: mediaLoader.item ? mediaLoader.item.isError : true
|
||||
delayed: true
|
||||
restoreMode: Binding.RestoreBindingOrValue
|
||||
}
|
||||
|
||||
onIsErrorChanged: {
|
||||
if (isError) {
|
||||
d.errorCounter = d.errorCounter + 1
|
||||
processError()
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property bool isFallback: false
|
||||
property int errorCounter: 0
|
||||
|
||||
function reset() {
|
||||
isFallback = false
|
||||
errorCounter = 0
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: mediaLoader
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
visible: !root.isError && !root.isLoading
|
||||
}
|
||||
|
||||
Component.onCompleted: updateMediaLoader()
|
||||
onMediaUrlChanged: updateMediaLoader()
|
||||
onComponentMediaTypeChanged: updateMediaLoader()
|
||||
onFallbackImageUrlChanged: updateMediaLoader()
|
||||
|
||||
function updateMediaLoader() {
|
||||
d.reset()
|
||||
if (root.mediaUrl !== "") {
|
||||
if (componentMediaType === StatusRoundedMedia.MediaType.Image) {
|
||||
mediaLoader.setSource("StatusAnimatedImage.qml",
|
||||
{
|
||||
"source": root.mediaUrl
|
||||
});
|
||||
return
|
||||
} else if (componentMediaType === StatusRoundedMedia.MediaType.Video) {
|
||||
mediaLoader.setSource("StatusVideo.qml",
|
||||
{
|
||||
"player.source": root.mediaUrl
|
||||
});
|
||||
return
|
||||
}
|
||||
}
|
||||
setFallbackImage()
|
||||
}
|
||||
|
||||
function processError() {
|
||||
if (!d.isFallback) {
|
||||
// AnimatedImage sometimes cannot load stuff that plan Image can, try that first
|
||||
if (componentMediaType === StatusRoundedMedia.MediaType.Image && d.errorCounter <= 1) {
|
||||
mediaLoader.setSource("StatusImage.qml",
|
||||
{
|
||||
"source": root.mediaUrl
|
||||
})
|
||||
return
|
||||
} else if (root.fallbackImageUrl !== "") {
|
||||
setFallbackImage()
|
||||
return
|
||||
}
|
||||
}
|
||||
setEmptyComponent()
|
||||
}
|
||||
|
||||
function setFallbackImage() {
|
||||
d.isFallback = true
|
||||
mediaLoader.setSource("StatusImage.qml",
|
||||
{
|
||||
"source": root.fallbackImageUrl
|
||||
})
|
||||
}
|
||||
|
||||
function setEmptyComponent() {
|
||||
mediaLoader.setSource("StatusImage.qml",
|
||||
{
|
||||
"source": ""
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import QtQuick 2.13
|
||||
import QtMultimedia 5.15
|
||||
|
||||
/*!
|
||||
\qmltype StatusVideo
|
||||
\inherits Item
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief Displays a video. Bundles \l{https://doc.qt.io/qt-5/qml-qtmultimedia-mediaplayer.html}{MediaPlayer} and
|
||||
\l{https://doc.qt.io/qt-5/qml-qtmultimedia-video.html}{Video}.
|
||||
|
||||
This is a plain wrapper for the MediaPlayer and Video QML types, providing an interface similar to the Image QML type. It
|
||||
sets some default property values and adds some properties common to other media type wrappers.
|
||||
|
||||
Example of how to use it:
|
||||
|
||||
\qml
|
||||
StatusVideo {
|
||||
anchors.fill: parent
|
||||
|
||||
width: 100
|
||||
height: 100
|
||||
player.source: "qrc:/demoapp/data/test-video.avi"
|
||||
}
|
||||
\endqml
|
||||
|
||||
*/
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property bool isLoading: player.playbackState !== MediaPlayer.PlayingState
|
||||
readonly property bool isError: player.status === MediaPlayer.InvalidMedia
|
||||
|
||||
property alias player: player
|
||||
property alias output: output
|
||||
|
||||
MediaPlayer {
|
||||
id: player
|
||||
autoPlay: true
|
||||
muted: true
|
||||
loops: MediaPlayer.Infinite
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
id: output
|
||||
anchors.fill: parent
|
||||
fillMode: VideoOutput.PreserveAspectFit
|
||||
source: player
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ module StatusQ.Components
|
|||
|
||||
StatusAddress 0.1 StatusAddress.qml
|
||||
StatusAddressPanel 0.1 StatusAddressPanel.qml
|
||||
StatusAnimatedImage 0.1 StatusAnimatedImage.qml
|
||||
StatusBadge 0.1 StatusBadge.qml
|
||||
StatusChatInfoToolBar 0.1 StatusChatInfoToolBar.qml
|
||||
StatusChatList 0.1 StatusChatList.qml
|
||||
|
@ -10,6 +11,7 @@ StatusChatListCategory 0.1 StatusChatListCategory.qml
|
|||
StatusChatListCategoryItem 0.1 StatusChatListCategoryItem.qml
|
||||
StatusChatListAndCategories 0.1 StatusChatListAndCategories.qml
|
||||
StatusCursorDelegate 0.1 StatusCursorDelegate.qml
|
||||
StatusImage 0.1 StatusImage.qml
|
||||
StatusToolBar 0.1 StatusToolBar.qml
|
||||
StatusContactRequestsIndicatorListItem 0.1 StatusContactRequestsIndicatorListItem.qml
|
||||
StatusEmoji 0.1 StatusEmoji.qml
|
||||
|
@ -26,7 +28,9 @@ StatusMemberListItem 0.1 StatusMemberListItem.qml
|
|||
StatusNavigationListItem 0.1 StatusNavigationListItem.qml
|
||||
StatusNavigationPanelHeadline 0.1 StatusNavigationPanelHeadline.qml
|
||||
StatusRoundIcon 0.1 StatusRoundIcon.qml
|
||||
StatusRoundedComponent 0.1 StatusRoundedComponent.qml
|
||||
StatusRoundedImage 0.1 StatusRoundedImage.qml
|
||||
StatusRoundedMedia 0.1 StatusRoundedMedia.qml
|
||||
StatusMacWindowButtons 0.1 StatusMacWindowButtons.qml
|
||||
StatusListItemBadge 0.1 StatusListItemBadge.qml
|
||||
StatusListItemTag 0.1 StatusListItemTag.qml
|
||||
|
@ -40,6 +44,7 @@ StatusMessageDetails 0.1 StatusMessageDetails.qml
|
|||
StatusMessageSenderDetails 0.1 StatusMessageSenderDetails.qml
|
||||
StatusTagSelector 0.1 StatusTagSelector.qml
|
||||
StatusToastMessage 0.1 StatusToastMessage.qml
|
||||
StatusVideo 0.1 StatusVideo.qml
|
||||
StatusWizardStepper 0.1 StatusWizardStepper.qml
|
||||
StatusImageCropPanel 0.1 StatusImageCropPanel.qml
|
||||
StatusColorSpace 0.0 StatusColorSpace.qml
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<file>StatusQ/Components/qmldir</file>
|
||||
<file>StatusQ/Components/StatusAddress.qml</file>
|
||||
<file>StatusQ/Components/StatusAddressPanel.qml</file>
|
||||
<file>StatusQ/Components/StatusAnimatedImage.qml</file>
|
||||
<file>StatusQ/Components/StatusBadge.qml</file>
|
||||
<file>StatusQ/Components/StatusCard.qml</file>
|
||||
<file>StatusQ/Components/StatusChatInfoToolBar.qml</file>
|
||||
|
@ -19,6 +20,7 @@
|
|||
<file>StatusQ/Components/StatusChatListAndCategories.qml</file>
|
||||
<file>StatusQ/Components/StatusChatListCategoryItem.qml</file>
|
||||
<file>StatusQ/Components/StatusChatListItem.qml</file>
|
||||
<file>StatusQ/Components/StatusImage.qml</file>
|
||||
<file>StatusQ/Components/StatusToolBar.qml</file>
|
||||
<file>StatusQ/Components/StatusColorSpace.qml</file>
|
||||
<file>StatusQ/Components/StatusCommunityCard.qml</file>
|
||||
|
@ -46,11 +48,14 @@
|
|||
<file>StatusQ/Components/StatusMessageHeader.qml</file>
|
||||
<file>StatusQ/Components/StatusNavigationListItem.qml</file>
|
||||
<file>StatusQ/Components/StatusNavigationPanelHeadline.qml</file>
|
||||
<file>StatusQ/Components/StatusRoundedComponent.qml</file>
|
||||
<file>StatusQ/Components/StatusRoundedImage.qml</file>
|
||||
<file>StatusQ/Components/StatusRoundedMedia.qml</file>
|
||||
<file>StatusQ/Components/StatusRoundIcon.qml</file>
|
||||
<file>StatusQ/Components/StatusSmartIdenticon.qml</file>
|
||||
<file>StatusQ/Components/StatusTagSelector.qml</file>
|
||||
<file>StatusQ/Components/StatusToastMessage.qml</file>
|
||||
<file>StatusQ/Components/StatusVideo.qml</file>
|
||||
<file>StatusQ/Components/StatusWizardStepper.qml</file>
|
||||
<file>StatusQ/Controls/Validators/qmldir</file>
|
||||
<file>StatusQ/Controls/Validators/StatusAddressOrEnsValidator.qml</file>
|
||||
|
|
|
@ -71,7 +71,7 @@ StatusScrollView {
|
|||
width: gridView.cellWidth
|
||||
title: model.name ? model.name : "..."
|
||||
subTitle: d.getStateText(model.deployState)
|
||||
imageUrl: model.image ? model.image : ""
|
||||
fallbackImageUrl: model.image ? model.image : ""
|
||||
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent" // TODO BACKEND
|
||||
isLoading: false
|
||||
navigationIconVisible: true
|
||||
|
|
|
@ -56,7 +56,9 @@ Item {
|
|||
width: gridView.cellWidth
|
||||
title: model.name ? model.name : "..."
|
||||
subTitle: model.collectionName ? model.collectionName : ""
|
||||
imageUrl: model.imageUrl ? model.imageUrl : ""
|
||||
mediaUrl: model.mediaUrl ? model.mediaUrl : ""
|
||||
mediaType: model.mediaType ? model.mediaType : ""
|
||||
fallbackImageUrl: model.imageUrl
|
||||
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent"
|
||||
isLoading: model.isLoading
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ Item {
|
|||
Layout.preferredWidth: parent.width
|
||||
spacing: 24
|
||||
|
||||
StatusRoundedImage {
|
||||
StatusRoundedMedia {
|
||||
id: collectibleimage
|
||||
readonly property int size : root.isNarrowMode ? 132 : 253
|
||||
width: size
|
||||
|
@ -60,7 +60,9 @@ Item {
|
|||
color: currentCollectible.backgroundColor
|
||||
border.color: Theme.palette.directColor8
|
||||
border.width: 1
|
||||
image.source: currentCollectible.imageUrl
|
||||
mediaUrl: currentCollectible.mediaUrl
|
||||
mediaType: currentCollectible.mediaType
|
||||
fallbackImageUrl: currentCollectible.imageUrl
|
||||
}
|
||||
|
||||
Column {
|
||||
|
|
|
@ -15,7 +15,9 @@ Control {
|
|||
property string title: ""
|
||||
property string subTitle: ""
|
||||
property string backgroundColor: "transparent"
|
||||
property url imageUrl : ""
|
||||
property url mediaUrl : ""
|
||||
property string mediaType: ""
|
||||
property url fallbackImageUrl : ""
|
||||
property bool isLoading: false
|
||||
property bool navigationIconVisible: false
|
||||
|
||||
|
@ -35,7 +37,7 @@ Control {
|
|||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
StatusRoundedImage {
|
||||
StatusRoundedMedia {
|
||||
id: image
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
@ -43,7 +45,9 @@ Control {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
radius: 12
|
||||
image.source: root.imageUrl
|
||||
mediaUrl: root.mediaUrl
|
||||
mediaType: root.mediaType
|
||||
fallbackImageUrl: root.fallbackImageUrl
|
||||
border.color: Theme.palette.baseColor2
|
||||
border.width: 1
|
||||
showLoadingIndicator: true
|
||||
|
|
Loading…
Reference in New Issue