diff --git a/src/app/commoncomponents/DataTransferMessageDelegate.qml b/src/app/commoncomponents/DataTransferMessageDelegate.qml index a87ee3447bff8baad2122d5c264ca1ab112c72fd..31fc011430300435c419f5e5af65b0a52e857724 100644 --- a/src/app/commoncomponents/DataTransferMessageDelegate.qml +++ b/src/app/commoncomponents/DataTransferMessageDelegate.qml @@ -22,7 +22,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects - import net.jami.Models 1.1 import net.jami.Constants 1.1 import net.jami.Adapters 1.1 @@ -44,12 +43,12 @@ Loader { property int transferStatus: TransferStatus onTidChanged: { if (tid === "") { - sourceComponent = deletedMsgComp + sourceComponent = deletedMsgComp; } } onTransferStatusChanged: { if (tid === "") { - sourceComponent = deletedMsgComp + sourceComponent = deletedMsgComp; return; } else if (transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED) { mediaInfo = MessagesAdapter.getMediaInfo(root.body); @@ -64,7 +63,11 @@ Loader { width: ListView.view ? ListView.view.width : 0 opacity: 0 - Behavior on opacity { NumberAnimation { duration: 100 } } + Behavior on opacity { + NumberAnimation { + duration: 100 + } + } onLoaded: opacity = 1 Component { @@ -93,9 +96,9 @@ Loader { bottomPadding: 6 topPadding: 6 leftPadding: 10 - text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + " " + JamiStrings.deletedMedia ; + text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + " " + JamiStrings.deletedMedia horizontalAlignment: Text.AlignLeft - width: Math.min((2 / 3) * parent.width, implicitWidth + 18, innerContent.width - senderMargin + 18) + width: Math.min((2 / 3) * parent.width, implicitWidth + 18, innerContent.width - senderMargin + 18) font.pointSize: JamiTheme.smallFontSize font.hintingPreference: Font.PreferNoHinting @@ -107,8 +110,8 @@ Loader { opacity: 0.5 function getBaseColor() { - bubble.isDeleted = true - return UtilsAdapter.luma(bubble.color) ? "white" : "dark" + bubble.isDeleted = true; + return UtilsAdapter.luma(bubble.color) ? "white" : "dark"; } } ] @@ -124,9 +127,7 @@ Loader { transferId: Id property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus) property bool canOpen: root.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing - property real maxMsgWidth: root.width - senderMargin - - 2 * hPadding - avatarBlockWidth - - buttonsLoader.width - 24 - 6 - 24 + property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth - buttonsLoader.width - 24 - 6 - 24 isOutgoing: Author === CurrentAccount.uri showTime: root.showTime @@ -150,14 +151,12 @@ Loader { enabled: canOpen onHoveredChanged: { if (enabled && hovered) { - dataTransferItem.hoveredLink = UtilsAdapter.urlFromLocalPath(location) + dataTransferItem.hoveredLink = UtilsAdapter.urlFromLocalPath(location); } else { - dataTransferItem.hoveredLink = "" + dataTransferItem.hoveredLink = ""; } } - cursorShape: enabled ? - Qt.PointingHandCursor : - Qt.ArrowCursor + cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor } Loader { id: buttonsLoader @@ -171,21 +170,21 @@ Loader { switch (root.transferStatus) { case Interaction.TransferStatus.TRANSFER_CREATED: case Interaction.TransferStatus.TRANSFER_FINISHED: - iconSource = JamiResources.link_black_24dp_svg - return terminatedComp + iconSource = JamiResources.link_black_24dp_svg; + return terminatedComp; case Interaction.TransferStatus.TRANSFER_CANCELED: case Interaction.TransferStatus.TRANSFER_ERROR: case Interaction.TransferStatus.TRANSFER_UNJOINABLE_PEER: case Interaction.TransferStatus.TRANSFER_TIMEOUT_EXPIRED: case Interaction.TransferStatus.TRANSFER_AWAITING_HOST: - iconSource = JamiResources.download_black_24dp_svg - return optionsComp + iconSource = JamiResources.download_black_24dp_svg; + return optionsComp; case Interaction.TransferStatus.TRANSFER_ONGOING: - iconSource = JamiResources.close_black_24dp_svg - return optionsComp + iconSource = JamiResources.close_black_24dp_svg; + return optionsComp; default: - iconSource = JamiResources.error_outline_black_24dp_svg - return terminatedComp + iconSource = JamiResources.error_outline_black_24dp_svg; + return terminatedComp; } } Component { @@ -216,9 +215,9 @@ Loader { imageColor: JamiTheme.chatviewButtonColor onClicked: { if (root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) { - return MessagesAdapter.cancelFile(transferId) + return MessagesAdapter.cancelFile(transferId); } else { - return MessagesAdapter.acceptFile(transferId) + return MessagesAdapter.acceptFile(transferId); } } } @@ -230,27 +229,21 @@ Loader { TextEdit { width: Math.min(implicitWidth, maxMsgWidth) topPadding: 10 - text: CurrentConversation.isSwarm ? - transferName : - location + text: CurrentConversation.isSwarm ? transferName : location wrapMode: Label.WrapAtWordBoundaryOrAnywhere font.pointSize: 11 renderType: Text.NativeRendering readOnly: true - color: UtilsAdapter.luma(bubble.color) - ? JamiTheme.chatviewTextColorLight - : JamiTheme.chatviewTextColorDark + color: UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark MouseArea { anchors.fill: parent - cursorShape: canOpen ? - Qt.PointingHandCursor : - Qt.ArrowCursor + cursorShape: canOpen ? Qt.PointingHandCursor : Qt.ArrowCursor onClicked: function (mouse) { if (canOpen) { - dataTransferItem.hoveredLink = UtilsAdapter.urlFromLocalPath(location) - Qt.openUrlExternally(new URL(dataTransferItem.hoveredLink)) + dataTransferItem.hoveredLink = UtilsAdapter.urlFromLocalPath(location); + Qt.openUrlExternally(new URL(dataTransferItem.hoveredLink)); } else { - dataTransferItem.hoveredLink = "" + dataTransferItem.hoveredLink = ""; } } } @@ -261,23 +254,20 @@ Loader { width: Math.min(implicitWidth, maxMsgWidth) bottomPadding: 10 text: { - var res = "" + var res = ""; if (transferStats.totalSize !== undefined) { - if (transferStats.progress !== 0 && - transferStats.progress !== transferStats.totalSize) { - res += UtilsAdapter.humanFileSize(transferStats.progress) + " / " + if (transferStats.progress !== 0 && transferStats.progress !== transferStats.totalSize) { + res += UtilsAdapter.humanFileSize(transferStats.progress) + " / "; } - var totalSize = transferStats.totalSize !== 0 ? transferStats.totalSize : TotalSize - res += UtilsAdapter.humanFileSize(totalSize) + var totalSize = transferStats.totalSize !== 0 ? transferStats.totalSize : TotalSize; + res += UtilsAdapter.humanFileSize(totalSize); } - return res + return res; } wrapMode: Label.WrapAtWordBoundaryOrAnywhere font.pointSize: 10 renderType: Text.NativeRendering - color: UtilsAdapter.luma(bubble.color) - ? JamiTheme.chatviewTextColorLight - : JamiTheme.chatviewTextColorDark + color: UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark } } }, @@ -316,23 +306,23 @@ Loader { Component.onCompleted: { if (transferStats.totalSize !== undefined) { - var totalSize = transferStats.totalSize !== 0 ? transferStats.totalSize : TotalSize - var txt = UtilsAdapter.humanFileSize(totalSize) + var totalSize = transferStats.totalSize !== 0 ? transferStats.totalSize : TotalSize; + var txt = UtilsAdapter.humanFileSize(totalSize); } - bubble.timestampItem.timeLabel.text += " - " + txt - bubble.color = "transparent" + bubble.timestampItem.timeLabel.text += " - " + txt; + bubble.color = "transparent"; if (mediaInfo.isImage) - bubble.z = 1 + bubble.z = 1; else - timeUnderBubble = true + timeUnderBubble = true; } onContentWidthChanged: { if (bubble.timestampItem.timeLabel.width > contentWidth) - timeUnderBubble = true + timeUnderBubble = true; else { - bubble.timestampItem.timeColor = JamiTheme.whiteColor - bubble.timestampItem.timeLabel.opacity = 1 + bubble.timestampItem.timeColor = JamiTheme.whiteColor; + bubble.timestampItem.timeLabel.opacity = 1; } } @@ -346,10 +336,10 @@ Loader { height: sourceComponent.height sourceComponent: { if (mediaInfo.isImage) - return imageComp + return imageComp; if (mediaInfo.isAnimatedImage) - return animatedImageComp - return avComp + return animatedImageComp; + return avComp; } Component { @@ -357,10 +347,11 @@ Loader { Loader { Component.onCompleted: { - var qml = WITH_WEBENGINE ? - "qrc:/webengine/MediaPreviewBase.qml" : - "qrc:/nowebengine/MediaPreviewBase.qml" - setSource( qml, { isVideo: mediaInfo.isVideo, html: mediaInfo.html } ) + var qml = WITH_WEBENGINE ? "qrc:/webengine/MediaPreviewBase.qml" : "qrc:/nowebengine/MediaPreviewBase.qml"; + setSource(qml, { + isVideo: mediaInfo.isVideo, + html: mediaInfo.html + }); } } } @@ -381,9 +372,7 @@ Loader { asynchronous: true source: UtilsAdapter.urlFromLocalPath(Body) property real aspectRatio: implicitWidth / implicitHeight - property real adjustedWidth: Math.min(maxSize, - Math.max(minSize, - innerContent.width - senderMargin)) + property real adjustedWidth: Math.min(maxSize, Math.max(minSize, innerContent.width - senderMargin)) width: adjustedWidth height: Math.ceil(adjustedWidth / aspectRatio) Rectangle { @@ -403,7 +392,7 @@ Loader { } onWidthChanged: { - localMediaMsgItem.contentWidth = width + localMediaMsgItem.contentWidth = width; } Component.onCompleted: localMediaMsgItem.bubble.imgSource = source @@ -429,71 +418,54 @@ Loader { Component { id: imageComp - Image { - id: img - + Rectangle { + border.color: img.useBox ? (JamiTheme.darkTheme ? "white" : JamiTheme.blackColor) : JamiTheme.transparentColor + color: JamiTheme.transparentColor anchors.right: isOutgoing ? parent.right : undefined - cache: true - fillMode: Image.PreserveAspectFit - mipmap: true - antialiasing: true - autoTransform: true - asynchronous: true + border.width: 1 + radius: msgRadius - Component.onCompleted: { - source = UtilsAdapter.urlFromLocalPath(Body); - localMediaMsgItem.bubble.imgSource = source; + implicitWidth: img.width + (img.useBox ? 20 : 0) + implicitHeight: img.height + (img.useBox ? 20 : 0) + onWidthChanged: { + localMediaMsgItem.contentWidth = width; } - // The sourceSize represents the maximum source dimensions. - // This should not be a dynamic binding, as property changes - // (resizing the chat view) here will trigger a reload of the image. - sourceSize: Qt.size(256, 256) - - // Now we setup bindings for the destination image component size. - // This based on the width available (width of the chat view), and - // a restriction on the height. - readonly property real aspectRatio: paintedWidth / paintedHeight - readonly property real idealWidth: innerContent.width - senderMargin - onStatusChanged: { - if (img.status == Image.Ready && aspectRatio) { - height = Qt.binding(() => JamiQmlUtils.clamp(idealWidth / aspectRatio, 64, 256)) - width = Qt.binding(() => height * aspectRatio) - } - } + Image { + id: img - onWidthChanged: { - localMediaMsgItem.contentWidth = width - } + anchors.centerIn: parent + cache: true + fillMode: Image.PreserveAspectFit + mipmap: true + antialiasing: true + autoTransform: true + asynchronous: true - Rectangle { - color: JamiTheme.previewImageBackgroundColor - z: -1 - anchors.fill: parent - } - layer.enabled: true - layer.effect: OpacityMask { - maskSource: MessageBubble { - out: isOutgoing - type: seq - width: img.width - height: img.height - radius: msgRadius + Component.onCompleted: { + source = UtilsAdapter.urlFromLocalPath(Body); + localMediaMsgItem.bubble.imgSource = source; } - } - LinearGradient { - id: gradient - anchors.fill: parent - start: Qt.point(0, height / 3) - gradient: Gradient { - GradientStop { - position: 0.0 - color: JamiTheme.transparentColor - } - GradientStop { - position: 1.0 - color: JamiTheme.darkGreyColorOpacityFade + // Scale down the image if it's too wide or too tall. + property real maxWidth: localMediaMsgItem.width - 170 + property bool xOverflow: sourceSize.width > maxWidth + property bool yOverflow: sourceSize.height > JamiTheme.maxImageHeight + property real scaleFactor: (xOverflow || yOverflow) ? Math.min(maxWidth / sourceSize.width, JamiTheme.maxImageHeight / sourceSize.height) : 1 + width: sourceSize.width * scaleFactor + height: sourceSize.height * scaleFactor + + // Add a bounding box around the image if it's small (along at least one + // dimension) to ensure that it's easy for users to see it and click on it. + property bool useBox: (paintedWidth < 40) || (paintedHeight < 40) + layer.enabled: !useBox + layer.effect: OpacityMask { + maskSource: MessageBubble { + out: isOutgoing + type: seq + width: img.width + height: img.height + radius: msgRadius } } } diff --git a/src/app/net/jami/Constants/JamiTheme.qml b/src/app/net/jami/Constants/JamiTheme.qml index 2f148072cb3bf13d0b0b1d0be3724ab77087a034..649ccc0d4eedbff6638ed67c7932a3922aa8d829 100644 --- a/src/app/net/jami/Constants/JamiTheme.qml +++ b/src/app/net/jami/Constants/JamiTheme.qml @@ -255,6 +255,7 @@ Item { property color messageWebViewFooterButtonImageColor: darkTheme ? "#838383" : "#656565" property color chatviewSecondaryInformationColor: "#A7A7A7" property color draftIconColor: "#707070" + property real maxImageHeight: 375 // ChatView Footer property color chatViewFooterListColor: darkTheme ? blackColor : "#E5E5E5"