diff --git a/src/qml/Component/Timeline/LinkPreviewDelegate.qml b/src/qml/Component/Timeline/LinkPreviewDelegate.qml index d6699c7e7..d41ee42e6 100644 --- a/src/qml/Component/Timeline/LinkPreviewDelegate.qml +++ b/src/qml/Component/Timeline/LinkPreviewDelegate.qml @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: 2022 Bharadwaj Raju +// SPDX-FileCopyrightText: 2023 James Graham // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-or-later OR LicenseRef-KDE-Accepted-GPL import QtQuick 2.15 @@ -9,58 +10,140 @@ import org.kde.kirigami 2.15 as Kirigami import org.kde.neochat 1.0 -RowLayout { - id: row +Loader { + id: root - property var links: model.display.match(/\bhttps?:\/\/[^\s\<\>\"\']+/g) - // don't show previews for room links or user mentions or custom emojis - .filter(link => !( - link.includes("https://matrix.to") || link.includes("/_matrix/media/r0/download/") - )) - // remove ending fullstops and commas - .map(link => (link.length && [".", ","].includes(link[link.length-1])) ? link.substring(0, link.length-1) : link) + /** + * @brief Get a list of hyperlinks in the text. + * + * User links i.e. anything starting with https://matrix.to are ignored. + */ + property var links: { + let matches = model.display.match(/\bhttps?:\/\/[^\s\<\>\"\']+/g) + if (matches && matches.length > 0) { + // don't show previews for room links or user mentions or custom emojis + return matches.filter(link => !( + link.includes("https://matrix.to") || link.includes("/_matrix/media/r0/download/") + )) + // remove ending fullstops and commas + .map(link => (link.length && [".", ","].includes(link[link.length-1])) ? link.substring(0, link.length-1) : link) + } + return [] + + } LinkPreviewer { - id: lp - url: links.length > 0 ? links[0] : "" + id: linkPreviewer + url: root.links && root.links.length > 0 ? root.links[0] : "" } - visible: lp.loaded && lp.title - Rectangle { - Layout.fillHeight: true - width: Kirigami.Units.smallSpacing - visible: lp.loaded && lp.title - color: Kirigami.Theme.highlightColor + + /** + * @brief Standard height for the link preview. + * + * When the content of the link preview is larger than this it will be + * elided/hidden until maximized. + */ + property var defaultHeight : Kirigami.Units.gridUnit * 3 + Kirigami.Units.smallSpacing * 2 + + active: !currentRoom.usesEncryption && model.display && links && links.length > 0 + visible: Config.showLinkPreview && active + sourceComponent: linkPreviewer.loaded ? linkPreviewComponent : loadingComponent + + Component { + id: linkPreviewComponent + QQC2.Control { + id: componentRoot + property bool truncated: linkPreviewDescription.truncated || !linkPreviewDescription.visible + + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + + contentItem: RowLayout { + spacing: Kirigami.Units.smallSpacing + + Rectangle { + Layout.fillHeight: true + width: Kirigami.Units.smallSpacing + color: Kirigami.Theme.highlightColor + } + Image { + visible: linkPreviewer.imageSource + Layout.maximumHeight: root.defaultHeight + Layout.maximumWidth: root.defaultHeight + source: linkPreviewer.imageSource.replace("mxc://", "image://mxc/") + fillMode: Image.PreserveAspectFit + } + ColumnLayout { + id: column + spacing: Kirigami.Units.smallSpacing + Kirigami.Heading { + id: linkPreviewTitle + Layout.fillWidth: true + level: 3 + wrapMode: Text.Wrap + textFormat: Text.RichText + text: " - " + lp.title.replace("–", "—") + "" - visible: lp.loaded - onLinkActivated: RoomManager.openResource(link) + + " + (maximizeButton.checked ? linkPreviewer.title : titleTextMetrics.elidedText).replace("–", "—") + "" + onLinkActivated: RoomManager.openResource(link) + + TextMetrics { + id: titleTextMetrics + text: linkPreviewer.title + font: linkPreviewTitle.font + elide: Text.ElideRight + elideWidth: (linkPreviewTitle.width - Kirigami.Units.largeSpacing * 2.5) * 3 + } + } + QQC2.Label { + id: linkPreviewDescription + Layout.fillWidth: true + Layout.maximumHeight: maximizeButton.checked ? -1 : root.defaultHeight - linkPreviewTitle.height - column.spacing + visible: linkPreviewTitle.height + column.spacing <= root.defaultHeight || maximizeButton.checked + text: linkPreviewer.description + wrapMode: Text.Wrap + elide: Text.ElideRight + } + } + } + + QQC2.Button { + id: maximizeButton + anchors.right: parent.right + anchors.bottom: parent.bottom + visible: componentRoot.hovered && (componentRoot.truncated || checked) + checkable: true + icon.name: checked ? "go-up" : "go-down" + + QQC2.ToolTip.text: checked ? i18n("Shrink preview") : i18n("Expand preview") + QQC2.ToolTip.visible: hovered + QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay + } } - QQC2.Label { - text: lp.description - Layout.maximumWidth: messageDelegate.bubbleMaxWidth - Layout.fillWidth: true - wrapMode: Text.Wrap - visible: lp.loaded && lp.description + } + + Component { + id: loadingComponent + RowLayout { + property bool hovered: false + property bool truncated: false + + Rectangle { + Layout.fillHeight: true + width: Kirigami.Units.smallSpacing + color: Kirigami.Theme.highlightColor + } + QQC2.BusyIndicator { } + Kirigami.Heading { + Layout.fillWidth: true + Layout.minimumHeight: root.defaultHeight + level: 2 + text: i18n("Loading URL preview") + } } } } diff --git a/src/qml/Component/Timeline/MessageDelegate.qml b/src/qml/Component/Timeline/MessageDelegate.qml index cec3d8622..44db5ec30 100644 --- a/src/qml/Component/Timeline/MessageDelegate.qml +++ b/src/qml/Component/Timeline/MessageDelegate.qml @@ -29,14 +29,8 @@ TimelineContainer { messageId: model.eventId visible: currentRoom.chatBoxEditId === model.eventId } - Loader { - id: linkPreviewLoader + LinkPreviewDelegate { Layout.fillWidth: true - active: !currentRoom.usesEncryption && model.display && model.display.includes("http") - visible: Config.showLinkPreview && active - sourceComponent: LinkPreviewDelegate { - anchors.verticalCenter: parent.verticalCenter - } } } }