feat(@desktop/wallet): Make images match their aspect ratio but still have min width and height in collectible details

Also make images zoom to cropped when visible in the collectibles list view

fixes #14203
This commit is contained in:
Khushboo Mehta 2024-04-11 11:00:42 +02:00 committed by Khushboo-dev-cpp
parent 195cb55e8d
commit 8d8268db2f
5 changed files with 54 additions and 16 deletions

View File

@ -71,6 +71,20 @@ StatusRoundedComponent {
*/ */
property url fallbackImageUrl property url fallbackImageUrl
/*!
\qmlproperty url StatusRoundedMedia::fillMode
helps set fillModel for the Media file loaded
*/
property int fillMode: Image.PreserveAspectFit
/*!
\qmlproperty url StatusRoundedMedia::maxDimension
is used to set dimension for the image in case of portrait or landscape
when fillMode = Image.PreserveAspectFit
if not set the width/height of parent will be considered
*/
property int manualMaxDimension: 0
readonly property int componentMediaType: { readonly property int componentMediaType: {
if (root.mediaType.startsWith("image")) { if (root.mediaType.startsWith("image")) {
return StatusRoundedMedia.MediaType.Image return StatusRoundedMedia.MediaType.Image
@ -112,11 +126,19 @@ StatusRoundedComponent {
} }
} }
Loader { implicitWidth: {
id: mediaLoader // Use Painted width so that the rectangle follow width of the image actually painted
anchors.fill: parent if(!!mediaLoader.item && (mediaLoader.item.paintedWidth > 0 || mediaLoader.item.paintedHeight > 0)) {
asynchronous: true return mediaLoader.item.paintedWidth
visible: !root.isError && !root.isLoading }
else return root.manualMaxDimension
}
implicitHeight: {
// Use Painted height so that the rectangle follows height of the image actually painted
if(!!mediaLoader.item && (mediaLoader.item.paintedWidth > 0 || mediaLoader.item.paintedHeight > 0)) {
return mediaLoader.item.paintedHeight
}
else return root.manualMaxDimension
} }
Component.onCompleted: updateMediaLoader() Component.onCompleted: updateMediaLoader()
@ -124,19 +146,31 @@ StatusRoundedComponent {
onComponentMediaTypeChanged: updateMediaLoader() onComponentMediaTypeChanged: updateMediaLoader()
onFallbackImageUrlChanged: updateMediaLoader() onFallbackImageUrlChanged: updateMediaLoader()
Loader {
id: mediaLoader
anchors.centerIn: parent
// In case manualMaxDimension is not defined then use parent width and height instead
width: root.manualMaxDimension === 0 ? parent.width : root.manualMaxDimension
height: root.manualMaxDimension === 0 ? parent.height : root.manualMaxDimension
asynchronous: true
visible: !root.isError && !root.isLoading
}
function updateMediaLoader() { function updateMediaLoader() {
d.reset() d.reset()
if (root.mediaUrl !== "") { if (root.mediaUrl !== "") {
if (componentMediaType === StatusRoundedMedia.MediaType.Image) { if (componentMediaType === StatusRoundedMedia.MediaType.Image) {
mediaLoader.setSource("StatusAnimatedImage.qml", mediaLoader.setSource("StatusAnimatedImage.qml",
{ {
"source": root.mediaUrl "source": root.mediaUrl,
"fillMode": root.fillMode
}); });
return return
} else if (componentMediaType === StatusRoundedMedia.MediaType.Video) { } else if (componentMediaType === StatusRoundedMedia.MediaType.Video) {
mediaLoader.setSource("StatusVideo.qml", mediaLoader.setSource("StatusVideo.qml",
{ {
"player.source": root.mediaUrl "player.source": root.mediaUrl,
"fillMode": root.fillMode
}); });
return return
} }
@ -150,7 +184,8 @@ StatusRoundedComponent {
if (componentMediaType === StatusRoundedMedia.MediaType.Image && d.errorCounter <= 1) { if (componentMediaType === StatusRoundedMedia.MediaType.Image && d.errorCounter <= 1) {
mediaLoader.setSource("StatusImage.qml", mediaLoader.setSource("StatusImage.qml",
{ {
"source": root.mediaUrl "source": root.mediaUrl,
"fillMode": root.fillMode
}) })
return return
} else if (root.fallbackImageUrl !== "") { } else if (root.fallbackImageUrl !== "") {
@ -165,14 +200,16 @@ StatusRoundedComponent {
d.isFallback = true d.isFallback = true
mediaLoader.setSource("StatusImage.qml", mediaLoader.setSource("StatusImage.qml",
{ {
"source": root.fallbackImageUrl "source": root.fallbackImageUrl,
"fillMode": root.fillMode
}) })
} }
function setEmptyComponent() { function setEmptyComponent() {
mediaLoader.setSource("StatusImage.qml", mediaLoader.setSource("StatusImage.qml",
{ {
"source": "" "source": "",
"fillMode": root.fillMode
}); });
} }
} }

View File

@ -33,6 +33,7 @@ Item {
property alias player: player property alias player: player
property alias output: output property alias output: output
property alias fillMode: output.fillMode
MediaPlayer { MediaPlayer {
id: player id: player

View File

@ -16,6 +16,7 @@ Control {
property bool showTag: false property bool showTag: false
property int size: PrivilegedTokenArtworkPanel.Size.Small property int size: PrivilegedTokenArtworkPanel.Size.Small
property int fillMode: Image.PreserveAspectFit
property alias artwork: image.source property alias artwork: image.source
property alias color: icon.color property alias color: icon.color
@ -86,7 +87,7 @@ Control {
anchors.centerIn: parent anchors.centerIn: parent
width: d.imageSize width: d.imageSize
height: width height: width
fillMode: Image.PreserveAspectFit fillMode: root.fillMode
layer.enabled: true layer.enabled: true
layer.effect: OpacityMask { layer.effect: OpacityMask {
maskSource: Rectangle { maskSource: Rectangle {

View File

@ -292,15 +292,12 @@ Item {
StatusRoundedMedia { StatusRoundedMedia {
id: collectibleImage id: collectibleImage
readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString() readonly property bool isEmpty: !mediaUrl.toString() && !fallbackImageUrl.toString()
width: 248
height: width
radius: Style.current.radius radius: Style.current.radius
color: isError || isEmpty ? Theme.palette.baseColor5 : collectible.backgroundColor color: isError || isEmpty ? Theme.palette.baseColor5 : collectible.backgroundColor
border.color: Theme.palette.directColor8
border.width: 1
mediaUrl: collectible.mediaUrl ?? "" mediaUrl: collectible.mediaUrl ?? ""
mediaType: modelIndex === 0 && !!collectible ? collectible.mediaType : "" mediaType: !!collectible ? (modelIndex > 0 && collectible.mediaType.startsWith("video")) ? "" : collectible.mediaType: ""
fallbackImageUrl: collectible.imageUrl fallbackImageUrl: collectible.imageUrl
manualMaxDimension: 240
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent

View File

@ -92,6 +92,7 @@ Control {
fallbackImageUrl: root.fallbackImageUrl fallbackImageUrl: root.fallbackImageUrl
showLoadingIndicator: true showLoadingIndicator: true
color: root.isLoading ? "transparent" : root.backgroundColor color: root.isLoading ? "transparent" : root.backgroundColor
fillMode: Image.PreserveAspectCrop
Loader { Loader {
anchors.fill: parent anchors.fill: parent
@ -119,6 +120,7 @@ Control {
size: PrivilegedTokenArtworkPanel.Size.Medium size: PrivilegedTokenArtworkPanel.Size.Medium
artwork: root.fallbackImageUrl artwork: root.fallbackImageUrl
color: root.ornamentColor color: root.ornamentColor
fillMode: Image.PreserveAspectCrop
isOwner: root.privilegesLevel === Constants.TokenPrivilegesLevel.Owner isOwner: root.privilegesLevel === Constants.TokenPrivilegesLevel.Owner
Loader { Loader {