diff --git a/src/qml/Base/HTile.qml b/src/qml/Base/HTile.qml index 764bd54b..7122dd6a 100644 --- a/src/qml/Base/HTile.qml +++ b/src/qml/Base/HTile.qml @@ -71,7 +71,8 @@ HButton { TapHandler { + enabled: contextMenu.count > 0 acceptedButtons: Qt.RightButton - onTapped: if (contextMenu.count > 0) contextMenu.popup() + onTapped: contextMenu.popup() } } diff --git a/src/qml/Chat/Timeline/EventContent.qml b/src/qml/Chat/Timeline/EventContent.qml index 6778650a..4f33058c 100644 --- a/src/qml/Chat/Timeline/EventContent.qml +++ b/src/qml/Chat/Timeline/EventContent.qml @@ -7,26 +7,16 @@ Row { id: eventContent spacing: theme.spacing / 1.25 + readonly property string eventText: Utils.processedEventText(model) readonly property string eventTime: Utils.formatTime(model.date, false) readonly property string hoveredLink: nameLabel.hoveredLink || contentLabel.hoveredLink - property string hoveredImage: "" + readonly property bool hoveredSelectable: + nameHover.hovered || contentHover.hovered - readonly property int cursorShape: - hoveredLink || hoveredImage ? Qt.PointingHandCursor : - nameHover.hovered || contentHover.hovered ? Qt.IBeamCursor : - Qt.ArrowCursor - - - // Needed because of eventList's MouseArea which steals the - // HSelectableLabel's MouseArea hover events - onCursorShapeChanged: eventList.cursorShape = cursorShape - - - HoverHandler { id: hover } Item { width: hideAvatar ? 0 : 58 diff --git a/src/qml/Chat/Timeline/EventDelegate.qml b/src/qml/Chat/Timeline/EventDelegate.qml index b1cd20f0..2ec034da 100644 --- a/src/qml/Chat/Timeline/EventDelegate.qml +++ b/src/qml/Chat/Timeline/EventDelegate.qml @@ -14,11 +14,14 @@ Column { theme.spacing * 2 + enum Media { Page, File, Image, Video, Audio } + + property var hoveredMediaTypeUrl: [] + // Remember timeline goes from newest message at index 0 to oldest property var previousItem: eventList.model.get(model.index + 1) property var nextItem: eventList.model.get(model.index - 1) readonly property QtObject currentItem: model - property int modelIndex: model.index onModelIndexChanged: { previousItem = eventList.model.get(model.index + 1) @@ -48,6 +51,18 @@ Column { readonly property bool unselectableNameLine: hideNameLine && ! (onRight && ! combine) + readonly property int cursorShape: + eventContent.hoveredLink || hoveredMediaTypeUrl.length > 0 ? + Qt.PointingHandCursor : + + eventContent.hoveredSelectable ? Qt.IBeamCursor : + + Qt.ArrowCursor + + // Needed because of eventList's MouseArea which steals the + // HSelectableLabel's MouseArea hover events + onCursorShapeChanged: eventList.cursorShape = cursorShape + function json() { return JSON.stringify( @@ -84,8 +99,8 @@ Column { TapHandler { acceptedButtons: Qt.RightButton onTapped: { + contextMenu.media = eventDelegate.hoveredMediaTypeUrl contextMenu.link = eventContent.hoveredLink - contextMenu.image = eventContent.hoveredImage contextMenu.popup() } } @@ -93,17 +108,36 @@ Column { HMenu { id: contextMenu + property var media: [] property string link: "" - property string image: "" - onClosed: { link = ""; image = "" } + onClosed: { media = []; link = "" } HMenuItem { - id: copyImage + id: copyMedia icon.name: "copy-link" - text: qsTr("Copy image address") - visible: Boolean(contextMenu.image) - onTriggered: Utils.copyToClipboard(contextMenu.image) + text: + contextMenu.media.length < 1 ? "" : + + contextMenu.media[0] === EventDelegate.Media.Page ? + qsTr("Copy page address") : + + contextMenu.media[0] === EventDelegate.Media.File ? + qsTr("Copy file address") : + + contextMenu.media[0] === EventDelegate.Media.Image ? + qsTr("Copy image address") : + + contextMenu.media[0] === EventDelegate.Media.Video ? + qsTr("Copy video address") : + + contextMenu.media[0] === EventDelegate.Media.Audio ? + qsTr("Copy audio address") : + + qsTr("Copy media address") + + visible: Boolean(text) + onTriggered: Utils.copyToClipboard(contextMenu.media[1]) } HMenuItem { @@ -117,7 +151,7 @@ Column { HMenuItem { icon.name: "copy-text" text: qsTr("Copy text") - visible: enabled || (! copyLink.visible && ! copyImage.visible) + visible: enabled || (! copyLink.visible && ! copyMedia.visible) enabled: Boolean(selectableLabelContainer.joinedSelection) onTriggered: Utils.copyToClipboard(selectableLabelContainer.joinedSelection) diff --git a/src/qml/Chat/Timeline/EventFile.qml b/src/qml/Chat/Timeline/EventFile.qml index 74e77715..bc3a8dc5 100644 --- a/src/qml/Chat/Timeline/EventFile.qml +++ b/src/qml/Chat/Timeline/EventFile.qml @@ -8,6 +8,12 @@ HTile { theme.chat.message.thumbnailWidth, ) + onClicked: Qt.openUrlExternally(fileUrl) + + onHoveredChanged: + eventDelegate.hoveredMediaTypeUrl = + hovered ? [EventDelegate.Media.File, fileUrl] : [] + property url thumbnailUrl property url fileUrl @@ -23,16 +29,4 @@ HTile { image: HIcon { svgName: "download" } - - - TapHandler { - acceptedButtons: Qt.LeftButton - onTapped: Qt.openUrlExternally(file.fileUrl) - } - - HoverHandler { - id: hover - onHoveredChanged: - eventContent.hoveredImage = hovered ? file.fileUrl : "" - } } diff --git a/src/qml/Chat/Timeline/EventImage.qml b/src/qml/Chat/Timeline/EventImage.qml index c8f45243..c4be375b 100644 --- a/src/qml/Chat/Timeline/EventImage.qml +++ b/src/qml/Chat/Timeline/EventImage.qml @@ -17,19 +17,14 @@ HImage { TapHandler { - onTapped: if (! image.animated) Qt.openUrlExternally(image.fullSource) - onDoubleTapped: Qt.openUrlExternally(image.fullSource) + onTapped: if (! image.animated) Qt.openUrlExternally(fullSource) + onDoubleTapped: Qt.openUrlExternally(fullSource) } HoverHandler { id: hover onHoveredChanged: - eventContent.hoveredImage = hovered ? image.fullSource : "" - } - - MouseArea { - anchors.fill: image - acceptedButtons: Qt.NoButton - cursorShape: Qt.PointingHandCursor + eventDelegate.hoveredMediaTypeUrl = + hovered ? [EventDelegate.Media.Image, fullSource] : [] } } diff --git a/src/qml/Chat/Timeline/EventMediaLoader.qml b/src/qml/Chat/Timeline/EventMediaLoader.qml index 536a6a64..3870e6b3 100644 --- a/src/qml/Chat/Timeline/EventMediaLoader.qml +++ b/src/qml/Chat/Timeline/EventMediaLoader.qml @@ -7,8 +7,6 @@ HLoader { x: eventContent.spacing - enum Type { Page, File, Image, Video, Audio } - property QtObject info property url mediaUrl @@ -30,35 +28,35 @@ HLoader { readonly property int type: { let main_type = info.media_mime.split("/")[0].toLowerCase() - if (main_type === "image") return EventMediaLoader.Type.Image - if (main_type === "video") return EventMediaLoader.Type.Video - if (main_type === "audio") return EventMediaLoader.Type.Audio + if (main_type === "image") return EventDelegate.Media.Image + if (main_type === "video") return EventDelegate.Media.Video + if (main_type === "audio") return EventDelegate.Media.Audio if (info.event_type === "RoomMessageFile") - return EventMediaLoader.Type.File + return EventDelegate.Media.File let ext = Utils.urlExtension(mediaUrl) - if (imageExtensions.includes(ext)) return EventMediaLoader.Type.Image - if (videoExtensions.includes(ext)) return EventMediaLoader.Type.Video - if (audioExtensions.includes(ext)) return EventMediaLoader.Type.Audio + if (imageExtensions.includes(ext)) return EventDelegate.Media.Image + if (videoExtensions.includes(ext)) return EventDelegate.Media.Video + if (audioExtensions.includes(ext)) return EventDelegate.Media.Audio - return EventMediaLoader.Type.Page + return EventDelegate.Media.Page } readonly property url previewUrl: ( - type === EventMediaLoader.Type.File || - type === EventMediaLoader.Type.Image ? + type === EventDelegate.Media.File || + type === EventDelegate.Media.Image ? info.thumbnail_url : "" ) || mediaUrl onPreviewUrlChanged: { - if (type === EventMediaLoader.Type.Image) { + if (type === EventDelegate.Media.Image) { var file = "EventImage.qml" var props = { source: previewUrl, fullSource: mediaUrl } - } else if (type === EventMediaLoader.Type.File) { + } else if (type === EventDelegate.Media.File) { var file = "EventFile.qml" var props = { thumbnailUrl: previewUrl,