moment/src/gui/Pages/Chat/Timeline/EventImage.qml
miruka 465d31790f Image viewer: handle images without known w/h
There's no way to know in advance the real size for
HTTP image previews and m.image events sent by some clients
2020-07-19 15:50:10 -04:00

195 lines
5.7 KiB
QML

// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import "../../../Base"
HMxcImage {
id: image
property EventMediaLoader loader
readonly property bool isEncrypted: ! utils.isEmptyObject(cryptDict)
readonly property real maxHeight:
eventList.height * theme.chat.message.thumbnailMaxHeightRatio
readonly property size fitSize: utils.fitSize(
// Minimum display size
theme.chat.message.thumbnailMinSize.width,
theme.chat.message.thumbnailMinSize.height,
// Real size
(
loader.singleMediaInfo.thumbnail_width ||
loader.singleMediaInfo.media_width ||
implicitWidth ||
800
) * theme.uiScale,
(
loader.singleMediaInfo.thumbnail_height ||
loader.singleMediaInfo.media_height ||
implicitHeight ||
600
) * theme.uiScale,
// Maximum display size
Math.min(
Math.max(maxHeight, theme.chat.message.thumbnailMinSize.width),
pureMedia ? Infinity : eventContent.maxMessageWidth,
eventDelegate.width - eventContent.spacing - avatarWrapper.width -
eventContent.spacing * 2, // padding
),
Math.max(maxHeight, theme.chat.message.thumbnailMinSize.height),
)
function getOpenUrl(callback) {
if (image.isEncrypted && loader.mediaUrl) {
loader.download(callback)
return
}
if (image.isEncrypted) {
callback(image.cachedPath)
return
}
const toOpen = loader.mediaUrl || loader.thumbnailMxc
const isMxc = toOpen.startsWith("mxc://")
isMxc ?
py.callClientCoro(chat.userId, "mxc_to_http", [toOpen], callback) :
callback(toOpen)
}
function openUrlExternally() {
getOpenUrl(Qt.openUrlExternally)
}
function openImageViewer() {
utils.makePopup(
"Popups/ImageViewerPopup.qml",
{
thumbnailTitle: loader.thumbnailTitle,
thumbnailMxc: loader.thumbnailMxc,
thumbnailPath: image.cachedPath,
thumbnailCryptDict:
JSON.parse(loader.singleMediaInfo.thumbnail_crypt_dict),
fullTitle: loader.title,
// The thumbnail/cached path will be the full GIF
fullMxc: animated ? "" : loader.mediaUrl,
fullCryptDict:
JSON.parse(loader.singleMediaInfo.media_crypt_dict),
overallSize: Qt.size(
loader.singleMediaInfo.media_width ||
loader.singleMediaInfo.thumbnail_width ||
implicitWidth ||
800,
loader.singleMediaInfo.media_height ||
loader.singleMediaInfo.thumbnail_height ||
implicitHeight ||
600,
)
},
obj => { obj.openExternallyRequested.connect(openUrlExternally) },
)
}
width: fitSize.width
height: fitSize.height
horizontalAlignment: Image.AlignLeft
title: thumbnail ? loader.thumbnailTitle : loader.title
animated: loader.singleMediaInfo.media_mime === "image/gif" ||
utils.urlExtension(loader.mediaUrl).toLowerCase() === "gif"
thumbnail: ! animated && loader.thumbnailMxc
mxc: thumbnail ?
(loader.thumbnailMxc || loader.mediaUrl) :
(loader.mediaUrl || loader.thumbnailMxc)
cryptDict: JSON.parse(
thumbnail && loader.thumbnailMxc ?
loader.singleMediaInfo.thumbnail_crypt_dict :
loader.singleMediaInfo.media_crypt_dict
)
TapHandler {
acceptedButtons: Qt.LeftButton
acceptedModifiers: Qt.NoModifier
onTapped:
eventList.selectedCount ?
eventDelegate.toggleChecked() :
openImageViewer()
gesturePolicy: TapHandler.ReleaseWithinBounds
}
TapHandler {
acceptedButtons: Qt.MiddleButton
acceptedModifiers: Qt.NoModifier
onTapped: getOpenUrl(Qt.openUrlExternally)
gesturePolicy: TapHandler.ReleaseWithinBounds
}
TapHandler {
acceptedModifiers: Qt.ShiftModifier
onTapped:
eventList.checkFromLastToHere(singleMediaInfo.index)
gesturePolicy: TapHandler.ReleaseWithinBounds
}
HoverHandler {
id: hover
onHoveredChanged: {
if (! hovered) {
eventDelegate.hoveredMediaTypeUrl = []
return
}
eventDelegate.hoveredMediaTypeUrl = [
EventDelegate.Media.Image,
loader.downloadedPath.replace(/^file:\/\//, "") ||
loader.mediaUrl
]
}
}
EventImageTextBubble {
anchors.left: parent.left
anchors.top: parent.top
text: loader.showSender
textFormat: Text.StyledText
opacity: hover.hovered ? 0 : 1
visible: opacity > 0
Behavior on opacity { HNumberAnimation {} }
}
EventImageTextBubble {
anchors.right: parent.right
anchors.bottom: parent.bottom
text: [loader.showDate, loader.showLocalEcho].join(" ").trim()
textFormat: Text.StyledText
opacity: hover.hovered ? 0 : 1
visible: opacity > 0
Behavior on opacity { HNumberAnimation {} }
}
Rectangle {
anchors.fill: parent
visible: opacity > 0
color: theme.chat.message.checkedBackground
opacity:
eventDelegate.checked ?
theme.chat.message.thumbnailCheckedOverlayOpacity :
0
Behavior on opacity { HNumberAnimation {} }
}
}