From 34f5400e99eb0ecbf402fd5e7961dfed7b076ed2 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Mon, 2 Sep 2019 23:28:05 +0200 Subject: Implement TextMessage delegate Text selection over multiple items doesn't work yet --- resources/qml/delegates/TextMessage.qml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 resources/qml/delegates/TextMessage.qml (limited to 'resources/qml/delegates/TextMessage.qml') diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml new file mode 100644 index 00000000..5f4b33fa --- /dev/null +++ b/resources/qml/delegates/TextMessage.qml @@ -0,0 +1,10 @@ +import QtQuick 2.5 + +TextEdit { + text: eventData.formattedBody + textFormat: TextEdit.RichText + readOnly: true + wrapMode: Text.Wrap + width: parent.width + selectByMouse: true +} -- cgit 1.5.1 From bbbd5df75f97271506e366325a378f1623881f3d Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 7 Sep 2019 01:33:46 +0200 Subject: Use system colors for now --- resources/qml/TimelineView.qml | 27 +++++++++++++++++++++++---- resources/qml/delegates/NoticeMessage.qml | 12 ++++++++++++ resources/qml/delegates/TextMessage.qml | 1 + resources/res.qrc | 1 + src/AvatarProvider.cpp | 4 ---- 5 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 resources/qml/delegates/NoticeMessage.qml (limited to 'resources/qml/delegates/TextMessage.qml') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index f0f73ec9..e97b560a 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -1,17 +1,23 @@ import QtQuick 2.6 import QtQuick.Controls 2.5 import QtQuick.Layouts 1.5 +import QtGraphicalEffects 1.0 import com.github.nheko 1.0 Rectangle { anchors.fill: parent + SystemPalette { id: colors; colorGroup: SystemPalette.Active } + SystemPalette { id: inactiveColors; colorGroup: SystemPalette.Disabled } + color: colors.window + Text { visible: !timelineManager.timeline anchors.centerIn: parent text: qsTr("No room open") font.pointSize: 24 + color: colors.windowText } ListView { @@ -67,16 +73,22 @@ Rectangle { Layout.alignment: Qt.AlignRight | Qt.AlignTop id: replyButton flat: true - height: replyButtonImg.contentHeight - width: replyButtonImg.contentWidth + height: 32 + width: 32 ToolTip.visible: hovered ToolTip.text: qsTr("Reply") + Image { id: replyButtonImg // Workaround, can't get icon.source working for now... anchors.fill: parent source: "qrc:/icons/icons/ui/mail-reply.png" } + ColorOverlay { + anchors.fill: replyButtonImg + source: replyButtonImg + color: colors.buttonText + } } Button { Layout.alignment: Qt.AlignRight | Qt.AlignTop @@ -92,6 +104,11 @@ Rectangle { anchors.fill: parent source: "qrc:/icons/icons/ui/vertical-ellipsis.png" } + ColorOverlay { + anchors.fill: optionsButtonImg + source: optionsButtonImg + color: colors.buttonText + } onClicked: contextMenu.open() @@ -117,6 +134,7 @@ Rectangle { Text { Layout.alignment: Qt.AlignRight | Qt.AlignTop text: model.timestamp.toLocaleTimeString("HH:mm") + color: inactiveColors.text } } @@ -134,13 +152,14 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter visible: section.includes(" ") text: chat.model.formatDateSeparator(new Date(Number(section.split(" ")[1]))) + color: colors.windowText height: contentHeight * 1.2 width: contentWidth * 1.2 horizontalAlignment: Text.AlignHCenter background: Rectangle { radius: parent.height / 2 - color: "black" + color: colors.dark } } Row { @@ -155,7 +174,7 @@ Rectangle { Text { id: userName text: chat.model.displayName(section.split(" ")[0]) - color: chat.model.userColor(section.split(" ")[0], "#ffffff") + color: chat.model.userColor(section.split(" ")[0], colors.window) } } } diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml new file mode 100644 index 00000000..5f04d235 --- /dev/null +++ b/resources/qml/delegates/NoticeMessage.qml @@ -0,0 +1,12 @@ +import QtQuick 2.5 + +TextEdit { + text: eventData.formattedBody + textFormat: TextEdit.RichText + readOnly: true + wrapMode: Text.Wrap + width: parent.width + selectByMouse: true + font.italic: true + color: inactiveColors.text +} diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index 5f4b33fa..f7dba618 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -7,4 +7,5 @@ TextEdit { wrapMode: Text.Wrap width: parent.width selectByMouse: true + color: colors.text } diff --git a/resources/res.qrc b/resources/res.qrc index b2f27814..b18835fb 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -117,5 +117,6 @@ qml/TimelineView.qml qml/delegates/TextMessage.qml + qml/delegates/NoticeMessage.qml diff --git a/src/AvatarProvider.cpp b/src/AvatarProvider.cpp index ec745c04..c83ffe0f 100644 --- a/src/AvatarProvider.cpp +++ b/src/AvatarProvider.cpp @@ -43,7 +43,6 @@ resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback ca QPixmap pixmap; if (avatar_cache.find(cacheKey, &pixmap)) { - nhlog::net()->info("cached pixmap {}", avatarUrl.toStdString()); callback(pixmap); return; } @@ -52,7 +51,6 @@ resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback ca if (!data.isNull()) { pixmap.loadFromData(data); avatar_cache.insert(cacheKey, pixmap); - nhlog::net()->info("loaded pixmap from disk cache {}", avatarUrl.toStdString()); callback(pixmap); return; } @@ -86,8 +84,6 @@ resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback ca cache::client()->saveImage(opts.mxc_url, res); - nhlog::net()->info("downloaded pixmap {}", opts.mxc_url); - emit proxy->avatarDownloaded(QByteArray(res.data(), res.size())); }); } -- cgit 1.5.1 From b9076c5c4d1beb7ff4cb4a2db8e6eb4e7f5b0dcd Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 8 Oct 2019 20:55:09 +0200 Subject: Try out DelegateChooser requires Qt5.12+ --- resources/qml/TimelineView.qml | 176 +++++------------------ resources/qml/delegates/FileMessage.qml | 6 +- resources/qml/delegates/ImageMessage.qml | 8 +- resources/qml/delegates/NoticeMessage.qml | 2 +- resources/qml/delegates/PlayableMediaMessage.qml | 10 +- resources/qml/delegates/TextMessage.qml | 2 +- resources/qml/delegates/TimelineRow.qml | 139 ++++++++++++++++++ resources/qml/delegates/placeholder.qml | 2 +- resources/res.qrc | 1 + 9 files changed, 189 insertions(+), 157 deletions(-) create mode 100644 resources/qml/delegates/TimelineRow.qml (limited to 'resources/qml/delegates/TextMessage.qml') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 4782c1f1..0642b13a 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -3,9 +3,12 @@ import QtQuick.Controls 2.1 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import QtQuick.Window 2.2 +import Qt.labs.qmlmodels 1.0 import com.github.nheko 1.0 +import "./delegates" + Rectangle { anchors.fill: parent @@ -77,158 +80,47 @@ Rectangle { onMovementEnded: updatePosition() spacing: 4 - delegate: RowLayout { - anchors.leftMargin: avatarSize + 4 - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: scrollbar.width - - function isFullyVisible() { - return (y - chat.contentY - 1) + height < chat.height + delegate: DelegateChooser { + role: "type" + DelegateChoice { + roleValue: MtxEvent.TextMessage + TimelineRow { view: chat; TextMessage { id: kid } } } - function getIndex() { - return index; + DelegateChoice { + roleValue: MtxEvent.NoticeMessage + TimelineRow { view: chat; NoticeMessage { id: kid } } } - - Loader { - id: loader - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - height: item.height - - source: switch(model.type) { - //case MtxEvent.Aliases: return "delegates/Aliases.qml" - //case MtxEvent.Avatar: return "delegates/Avatar.qml" - //case MtxEvent.CanonicalAlias: return "delegates/CanonicalAlias.qml" - //case MtxEvent.Create: return "delegates/Create.qml" - //case MtxEvent.GuestAccess: return "delegates/GuestAccess.qml" - //case MtxEvent.HistoryVisibility: return "delegates/HistoryVisibility.qml" - //case MtxEvent.JoinRules: return "delegates/JoinRules.qml" - //case MtxEvent.Member: return "delegates/Member.qml" - //case MtxEvent.Name: return "delegates/Name.qml" - //case MtxEvent.PowerLevels: return "delegates/PowerLevels.qml" - //case MtxEvent.Topic: return "delegates/Topic.qml" - case MtxEvent.NoticeMessage: return "delegates/NoticeMessage.qml" - case MtxEvent.TextMessage: return "delegates/TextMessage.qml" - case MtxEvent.EmoteMessage: return "delegates/TextMessage.qml" - case MtxEvent.ImageMessage: return "delegates/ImageMessage.qml" - case MtxEvent.Sticker: return "delegates/ImageMessage.qml" - case MtxEvent.FileMessage: return "delegates/FileMessage.qml" - case MtxEvent.VideoMessage: return "delegates/PlayableMediaMessage.qml" - case MtxEvent.AudioMessage: return "delegates/PlayableMediaMessage.qml" - case MtxEvent.Redacted: return "delegates/Redacted.qml" - default: return "delegates/placeholder.qml" - } - property variant eventData: model + DelegateChoice { + roleValue: MtxEvent.EmoteMessage + TimelineRow { view: chat; TextMessage { id: kid } } } - - StatusIndicator { - state: model.state - Layout.alignment: Qt.AlignRight | Qt.AlignTop - Layout.preferredHeight: 16 + DelegateChoice { + roleValue: MtxEvent.ImageMessage + TimelineRow { view: chat; ImageMessage { id: kid } } } - - EncryptionIndicator { - visible: model.isEncrypted - Layout.alignment: Qt.AlignRight | Qt.AlignTop - Layout.preferredHeight: 16 + DelegateChoice { + roleValue: MtxEvent.Sticker + TimelineRow { view: chat; ImageMessage { id: kid } } } - - Button { - Layout.alignment: Qt.AlignRight | Qt.AlignTop - id: replyButton - flat: true - Layout.preferredHeight: 16 - ToolTip.visible: hovered - ToolTip.text: qsTr("Reply") - - // disable background, because we don't want a border on hover - background: Item { - } - - Image { - id: replyButtonImg - // Workaround, can't get icon.source working for now... - anchors.fill: parent - source: "qrc:/icons/icons/ui/mail-reply.png" - } - ColorOverlay { - anchors.fill: replyButtonImg - source: replyButtonImg - color: replyButton.hovered ? colors.highlight : colors.buttonText - } - - onClicked: chat.model.replyAction(model.id) + DelegateChoice { + roleValue: MtxEvent.FileMessage + TimelineRow { view: chat; FileMessage { id: kid } } } - Button { - Layout.alignment: Qt.AlignRight | Qt.AlignTop - id: optionsButton - flat: true - Layout.preferredHeight: 16 - ToolTip.visible: hovered - ToolTip.text: qsTr("Options") - - // disable background, because we don't want a border on hover - background: Item { - } - - Image { - id: optionsButtonImg - // Workaround, can't get icon.source working for now... - anchors.fill: parent - source: "qrc:/icons/icons/ui/vertical-ellipsis.png" - } - ColorOverlay { - anchors.fill: optionsButtonImg - source: optionsButtonImg - color: optionsButton.hovered ? colors.highlight : colors.buttonText - } - - onClicked: contextMenu.open() - - Menu { - y: optionsButton.height - id: contextMenu - - MenuItem { - text: qsTr("Read receipts") - onTriggered: chat.model.readReceiptsAction(model.id) - } - MenuItem { - text: qsTr("Mark as read") - } - MenuItem { - text: qsTr("View raw message") - onTriggered: chat.model.viewRawMessage(model.id) - } - MenuItem { - text: qsTr("Redact message") - onTriggered: chat.model.redactEvent(model.id) - } - MenuItem { - visible: model.type == MtxEvent.ImageMessage || model.type == MtxEvent.VideoMessage || model.type == MtxEvent.AudioMessage || model.type == MtxEvent.FileMessage || model.type == MtxEvent.Sticker - text: qsTr("Save as") - onTriggered: timelineManager.saveMedia(model.url, model.filename, model.mimetype, model.type) - } - } + DelegateChoice { + roleValue: MtxEvent.VideoMessage + TimelineRow { view: chat; PlayableMediaMessage { id: kid } } } - - Text { - Layout.alignment: Qt.AlignRight | Qt.AlignTop - text: model.timestamp.toLocaleTimeString("HH:mm") - color: inactiveColors.text - - ToolTip.visible: ma.containsMouse - ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) - - MouseArea{ - id: ma - anchors.fill: parent - hoverEnabled: true - } + DelegateChoice { + roleValue: MtxEvent.AudioMessage + TimelineRow { view: chat; PlayableMediaMessage { id: kid } } + } + DelegateChoice { + roleValue: MtxEvent.Redacted + TimelineRow { view: chat; Redacted { id: kid } } } } + section { property: "section" delegate: Column { diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index 6dd552ab..ad2c695d 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -31,7 +31,7 @@ Rectangle { } MouseArea { anchors.fill: parent - onClicked: timelineManager.saveMedia(eventData.url, eventData.filename, eventData.mimetype, eventData.type) + onClicked: timelineManager.saveMedia(model.url, model.filename, model.mimetype, model.type) cursorShape: Qt.PointingHandCursor } } @@ -40,14 +40,14 @@ Rectangle { Text { Layout.fillWidth: true - text: eventData.body + text: model.body textFormat: Text.PlainText elide: Text.ElideRight color: colors.text } Text { Layout.fillWidth: true - text: eventData.filesize + text: model.filesize textFormat: Text.PlainText elide: Text.ElideRight color: colors.text diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml index 2ed41a17..70d2debe 100644 --- a/resources/qml/delegates/ImageMessage.qml +++ b/resources/qml/delegates/ImageMessage.qml @@ -4,20 +4,20 @@ import com.github.nheko 1.0 Item { width: 300 - height: 300 * eventData.proportionalHeight + height: 300 * model.proportionalHeight Image { id: img anchors.fill: parent - source: eventData.url.replace("mxc://", "image://MxcImage/") + source: model.url.replace("mxc://", "image://MxcImage/") asynchronous: true fillMode: Image.PreserveAspectFit MouseArea { - enabled: eventData.type == MtxEvent.ImageMessage + enabled: model.type == MtxEvent.ImageMessage anchors.fill: parent - onClicked: timelineManager.openImageOverlay(eventData.url, eventData.filename, eventData.mimetype, eventData.type) + onClicked: timelineManager.openImageOverlay(model.url, model.filename, model.mimetype, model.type) } } } diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml index 5f04d235..b916d65a 100644 --- a/resources/qml/delegates/NoticeMessage.qml +++ b/resources/qml/delegates/NoticeMessage.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 TextEdit { - text: eventData.formattedBody + text: model.formattedBody textFormat: TextEdit.RichText readOnly: true wrapMode: Text.Wrap diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 2385c750..c716d21d 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -17,7 +17,7 @@ Rectangle { anchors.centerIn: parent VideoOutput { - visible: eventData.type == MtxEvent.VideoMessage + visible: model.type == MtxEvent.VideoMessage Layout.maximumHeight: 300 Layout.minimumHeight: 300 Layout.maximumWidth: 500 @@ -85,7 +85,7 @@ Rectangle { anchors.fill: parent onClicked: { switch (button.state) { - case "": timelineManager.cacheMedia(eventData.url, eventData.mimetype); break; + case "": timelineManager.cacheMedia(model.url, model.mimetype); break; case "stopped": media.play(); console.log("play"); button.state = "playing" @@ -107,7 +107,7 @@ Rectangle { Connections { target: timelineManager onMediaCached: { - if (mxcUrl == eventData.url) { + if (mxcUrl == model.url) { media.source = "file://" + cacheUrl button.state = "stopped" console.log("media loaded: " + mxcUrl + " at " + cacheUrl) @@ -132,14 +132,14 @@ Rectangle { Text { Layout.fillWidth: true - text: eventData.body + text: model.body textFormat: Text.PlainText elide: Text.ElideRight color: colors.text } Text { Layout.fillWidth: true - text: eventData.filesize + text: model.filesize textFormat: Text.PlainText elide: Text.ElideRight color: colors.text diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index f7dba618..3a3492ed 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 TextEdit { - text: eventData.formattedBody + text: model.formattedBody textFormat: TextEdit.RichText readOnly: true wrapMode: Text.Wrap diff --git a/resources/qml/delegates/TimelineRow.qml b/resources/qml/delegates/TimelineRow.qml new file mode 100644 index 00000000..28a2ec8c --- /dev/null +++ b/resources/qml/delegates/TimelineRow.qml @@ -0,0 +1,139 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import QtQuick.Window 2.2 + +import com.github.nheko 1.0 + +import ".." + +RowLayout { + property var view: undefined + default property alias data: contentItem.data + + height: kid.height // TODO: fix this, we shouldn't need to give the child of contentItem this id! + anchors.leftMargin: avatarSize + 4 + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: scrollbar.width + + function isFullyVisible() { + return (y - view.contentY - 1) + height < view.height + } + function getIndex() { + return index; + } + + Item { + id: contentItem + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + } + + StatusIndicator { + state: model.state + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.preferredHeight: 16 + } + + EncryptionIndicator { + visible: model.isEncrypted + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.preferredHeight: 16 + } + + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignTop + id: replyButton + flat: true + Layout.preferredHeight: 16 + ToolTip.visible: hovered + ToolTip.text: qsTr("Reply") + + // disable background, because we don't want a border on hover + background: Item { + } + + Image { + id: replyButtonImg + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: "qrc:/icons/icons/ui/mail-reply.png" + } + ColorOverlay { + anchors.fill: replyButtonImg + source: replyButtonImg + color: replyButton.hovered ? colors.highlight : colors.buttonText + } + + onClicked: view.model.replyAction(model.id) + } + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignTop + id: optionsButton + flat: true + Layout.preferredHeight: 16 + ToolTip.visible: hovered + ToolTip.text: qsTr("Options") + + // disable background, because we don't want a border on hover + background: Item { + } + + Image { + id: optionsButtonImg + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: "qrc:/icons/icons/ui/vertical-ellipsis.png" + } + ColorOverlay { + anchors.fill: optionsButtonImg + source: optionsButtonImg + color: optionsButton.hovered ? colors.highlight : colors.buttonText + } + + onClicked: contextMenu.open() + + Menu { + y: optionsButton.height + id: contextMenu + + MenuItem { + text: qsTr("Read receipts") + onTriggered: view.model.readReceiptsAction(model.id) + } + MenuItem { + text: qsTr("Mark as read") + } + MenuItem { + text: qsTr("View raw message") + onTriggered: view.model.viewRawMessage(model.id) + } + MenuItem { + text: qsTr("Redact message") + onTriggered: view.model.redactEvent(model.id) + } + MenuItem { + visible: model.type == MtxEvent.ImageMessage || model.type == MtxEvent.VideoMessage || model.type == MtxEvent.AudioMessage || model.type == MtxEvent.FileMessage || model.type == MtxEvent.Sticker + text: qsTr("Save as") + onTriggered: timelineManager.saveMedia(model.url, model.filename, model.mimetype, model.type) + } + } + } + + Text { + Layout.alignment: Qt.AlignRight | Qt.AlignTop + text: model.timestamp.toLocaleTimeString("HH:mm") + color: inactiveColors.text + + ToolTip.visible: ma.containsMouse + ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) + + MouseArea{ + id: ma + anchors.fill: parent + hoverEnabled: true + } + } +} diff --git a/resources/qml/delegates/placeholder.qml b/resources/qml/delegates/placeholder.qml index e64bc368..462af2db 100644 --- a/resources/qml/delegates/placeholder.qml +++ b/resources/qml/delegates/placeholder.qml @@ -2,7 +2,7 @@ import QtQuick 2.5 import QtQuick.Controls 2.1 Label { - text: qsTr("unimplemented event: ") + eventData.type + text: qsTr("unimplemented event: ") + model.type textFormat: Text.PlainText wrapMode: Text.Wrap width: parent.width diff --git a/resources/res.qrc b/resources/res.qrc index 16bab4e4..2e0f89ce 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -119,6 +119,7 @@ qml/Avatar.qml qml/StatusIndicator.qml qml/EncryptionIndicator.qml + qml/delegates/TimelineRow.qml qml/delegates/TextMessage.qml qml/delegates/NoticeMessage.qml qml/delegates/ImageMessage.qml -- cgit 1.5.1 From 2055c75f8ba710e8950a55aa3c41a9cec9f26ad7 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 27 Oct 2019 22:01:40 +0100 Subject: Organize qml files a bit --- CMakeLists.txt | 1 + cmake/Translations.cmake | 7 +- resources/qml/Avatar.qml | 1 + resources/qml/RowDelegateChooser.qml | 51 -------- resources/qml/TimelineRow.qml | 144 +++++++++++++++++++++ resources/qml/TimelineView.qml | 3 +- resources/qml/delegates/FileMessage.qml | 2 +- resources/qml/delegates/ImageMessage.qml | 2 +- resources/qml/delegates/MessageDelegate.qml | 50 ++++++++ resources/qml/delegates/NoticeMessage.qml | 2 +- resources/qml/delegates/Placeholder.qml | 2 +- resources/qml/delegates/PlayableMediaMessage.qml | 2 +- resources/qml/delegates/TextMessage.qml | 2 +- resources/qml/delegates/TimelineRow.qml | 151 ----------------------- resources/res.qrc | 4 +- 15 files changed, 211 insertions(+), 213 deletions(-) delete mode 100644 resources/qml/RowDelegateChooser.qml create mode 100644 resources/qml/TimelineRow.qml create mode 100644 resources/qml/delegates/MessageDelegate.qml delete mode 100644 resources/qml/delegates/TimelineRow.qml (limited to 'resources/qml/delegates/TextMessage.qml') diff --git a/CMakeLists.txt b/CMakeLists.txt index 368b754a..ae9a5e46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ include(LMDB) # Discover Qt dependencies. # find_package(Qt5 COMPONENTS Core Widgets LinguistTools Concurrent Svg Multimedia Qml QuickControls2 REQUIRED) +find_package(Qt5QuickCompiler) find_package(Qt5DBus) if (APPLE) diff --git a/cmake/Translations.cmake b/cmake/Translations.cmake index 8ca91883..bdd8ecbc 100644 --- a/cmake/Translations.cmake +++ b/cmake/Translations.cmake @@ -21,4 +21,9 @@ if(NOT EXISTS ${_qrc}) endif() qt5_add_resources(LANG_QRC ${_qrc}) -qt5_add_resources(QRC resources/res.qrc) +#qt5_add_resources(QRC resources/res.qrc) +if(Qt5QuickCompiler_FOUND) + qtquick_compiler_add_resources(QRC resources/res.qrc) +else() + qt5_add_resources(QRC resources/res.qrc) +endif() diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml index 9d7b54fe..131e6b46 100644 --- a/resources/qml/Avatar.qml +++ b/resources/qml/Avatar.qml @@ -30,6 +30,7 @@ Rectangle { id: img anchors.fill: parent asynchronous: true + fillMode: Image.PreserveAspectCrop layer.enabled: true layer.effect: OpacityMask { diff --git a/resources/qml/RowDelegateChooser.qml b/resources/qml/RowDelegateChooser.qml deleted file mode 100644 index bacd970a..00000000 --- a/resources/qml/RowDelegateChooser.qml +++ /dev/null @@ -1,51 +0,0 @@ -import QtQuick 2.6 -import Qt.labs.qmlmodels 1.0 -import com.github.nheko 1.0 - -import "./delegates" - -DelegateChooser { - //role: "type" //< not supported in our custom implementation, have to use roleValue - width: chat.width - roleValue: model.type - - DelegateChoice { - roleValue: MtxEvent.TextMessage - TimelineRow { view: chat; TextMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.NoticeMessage - TimelineRow { view: chat; NoticeMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.EmoteMessage - TimelineRow { view: chat; TextMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.ImageMessage - TimelineRow { view: chat; ImageMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.Sticker - TimelineRow { view: chat; ImageMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.FileMessage - TimelineRow { view: chat; FileMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.VideoMessage - TimelineRow { view: chat; PlayableMediaMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.AudioMessage - TimelineRow { view: chat; PlayableMediaMessage { id: kid } } - } - DelegateChoice { - roleValue: MtxEvent.Redacted - TimelineRow { view: chat; Redacted { id: kid } } - } - DelegateChoice { - TimelineRow { view: chat; Placeholder { id: kid } } - } -} diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml new file mode 100644 index 00000000..fdc2ec95 --- /dev/null +++ b/resources/qml/TimelineRow.qml @@ -0,0 +1,144 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import QtQuick.Window 2.2 + +import com.github.nheko 1.0 + +import "./delegates" + +RowLayout { + property var view: chat + + anchors.leftMargin: avatarSize + 4 + anchors.rightMargin: scrollbar.width + anchors.left: parent.left + anchors.right: parent.right + + height: contentItem.height + + MessageDelegate { + Layout.fillWidth: true + Layout.alignment: Qt.AlignTop + id: contentItem + } + + StatusIndicator { + state: model.state + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.preferredHeight: 16 + } + + EncryptionIndicator { + visible: model.isEncrypted + Layout.alignment: Qt.AlignRight | Qt.AlignTop + Layout.preferredHeight: 16 + } + + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignTop + id: replyButton + flat: true + Layout.preferredHeight: 16 + + ToolTip { + visible: replyButton.hovered + text: qsTr("Reply") + palette: colors + } + + // disable background, because we don't want a border on hover + background: Item { + } + + Image { + id: replyButtonImg + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: "qrc:/icons/icons/ui/mail-reply.png" + } + ColorOverlay { + anchors.fill: replyButtonImg + source: replyButtonImg + color: replyButton.hovered ? colors.highlight : colors.buttonText + } + + onClicked: view.model.replyAction(model.id) + } + Button { + Layout.alignment: Qt.AlignRight | Qt.AlignTop + id: optionsButton + flat: true + Layout.preferredHeight: 16 + + ToolTip { + visible: optionsButton.hovered + text: qsTr("Options") + palette: colors + } + + // disable background, because we don't want a border on hover + background: Item { + } + + Image { + id: optionsButtonImg + // Workaround, can't get icon.source working for now... + anchors.fill: parent + source: "qrc:/icons/icons/ui/vertical-ellipsis.png" + } + ColorOverlay { + anchors.fill: optionsButtonImg + source: optionsButtonImg + color: optionsButton.hovered ? colors.highlight : colors.buttonText + } + + onClicked: contextMenu.open() + + Menu { + y: optionsButton.height + id: contextMenu + palette: colors + + MenuItem { + text: qsTr("Read receipts") + onTriggered: view.model.readReceiptsAction(model.id) + } + MenuItem { + text: qsTr("Mark as read") + } + MenuItem { + text: qsTr("View raw message") + onTriggered: view.model.viewRawMessage(model.id) + } + MenuItem { + text: qsTr("Redact message") + onTriggered: view.model.redactEvent(model.id) + } + MenuItem { + visible: model.type == MtxEvent.ImageMessage || model.type == MtxEvent.VideoMessage || model.type == MtxEvent.AudioMessage || model.type == MtxEvent.FileMessage || model.type == MtxEvent.Sticker + text: qsTr("Save as") + onTriggered: timelineManager.saveMedia(model.url, model.filename, model.mimetype, model.type) + } + } + } + + Text { + Layout.alignment: Qt.AlignRight | Qt.AlignTop + text: model.timestamp.toLocaleTimeString("HH:mm") + color: inactiveColors.text + + MouseArea{ + id: ma + anchors.fill: parent + hoverEnabled: true + } + + ToolTip { + visible: ma.containsMouse + text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) + palette: colors + } + } +} diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 046f7800..e5c1bda6 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -90,14 +90,13 @@ Rectangle { onMovementEnded: updatePosition() spacing: 4 - delegate: RowDelegateChooser { + delegate: TimelineRow { function isFullyVisible() { return height > 1 && (y - chat.contentY - 1) + height < chat.height } function getIndex() { return index; } - } section { diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index ad2c695d..f4cf3f15 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -5,7 +5,7 @@ Rectangle { radius: 10 color: colors.dark height: row.height + 24 - width: parent.width + width: parent ? parent.width : undefined RowLayout { id: row diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml index f1e95e3d..802ef721 100644 --- a/resources/qml/delegates/ImageMessage.qml +++ b/resources/qml/delegates/ImageMessage.qml @@ -3,7 +3,7 @@ import QtQuick 2.6 import com.github.nheko 1.0 Item { - width: Math.min(parent.width, model.width) + width: Math.min(parent ? parent.width : undefined, model.width) height: width * model.proportionalHeight Image { diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml new file mode 100644 index 00000000..3d342a02 --- /dev/null +++ b/resources/qml/delegates/MessageDelegate.qml @@ -0,0 +1,50 @@ +import QtQuick 2.6 +import Qt.labs.qmlmodels 1.0 +import com.github.nheko 1.0 + +DelegateChooser { + //role: "type" //< not supported in our custom implementation, have to use roleValue + roleValue: model.type + + width: parent.width + + DelegateChoice { + roleValue: MtxEvent.TextMessage + TextMessage {} + } + DelegateChoice { + roleValue: MtxEvent.NoticeMessage + NoticeMessage {} + } + DelegateChoice { + roleValue: MtxEvent.EmoteMessage + TextMessage {} + } + DelegateChoice { + roleValue: MtxEvent.ImageMessage + ImageMessage {} + } + DelegateChoice { + roleValue: MtxEvent.Sticker + ImageMessage {} + } + DelegateChoice { + roleValue: MtxEvent.FileMessage + FileMessage {} + } + DelegateChoice { + roleValue: MtxEvent.VideoMessage + PlayableMediaMessage {} + } + DelegateChoice { + roleValue: MtxEvent.AudioMessage + PlayableMediaMessage {} + } + DelegateChoice { + roleValue: MtxEvent.Redacted + Redacted {} + } + DelegateChoice { + Placeholder {} + } +} diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml index b916d65a..59e051be 100644 --- a/resources/qml/delegates/NoticeMessage.qml +++ b/resources/qml/delegates/NoticeMessage.qml @@ -5,7 +5,7 @@ TextEdit { textFormat: TextEdit.RichText readOnly: true wrapMode: Text.Wrap - width: parent.width + width: parent ? parent.width : undefined selectByMouse: true font.italic: true color: inactiveColors.text diff --git a/resources/qml/delegates/Placeholder.qml b/resources/qml/delegates/Placeholder.qml index 462af2db..171bf18d 100644 --- a/resources/qml/delegates/Placeholder.qml +++ b/resources/qml/delegates/Placeholder.qml @@ -5,6 +5,6 @@ Label { text: qsTr("unimplemented event: ") + model.type textFormat: Text.PlainText wrapMode: Text.Wrap - width: parent.width + width: parent ? parent.width : undefined color: inactiveColors.text } diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index 3a518617..68b09f7b 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -10,7 +10,7 @@ Rectangle { radius: 10 color: colors.dark height: content.height + 24 - width: parent.width + width: parent ? parent.width : undefined Column { id: content diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index 3a3492ed..713be868 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -5,7 +5,7 @@ TextEdit { textFormat: TextEdit.RichText readOnly: true wrapMode: Text.Wrap - width: parent.width + width: parent ? parent.width : undefined selectByMouse: true color: colors.text } diff --git a/resources/qml/delegates/TimelineRow.qml b/resources/qml/delegates/TimelineRow.qml deleted file mode 100644 index 3019deb1..00000000 --- a/resources/qml/delegates/TimelineRow.qml +++ /dev/null @@ -1,151 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Controls 2.3 -import QtQuick.Layouts 1.2 -import QtGraphicalEffects 1.0 -import QtQuick.Window 2.2 - -import com.github.nheko 1.0 - -import ".." - -RowLayout { - property var view: undefined - default property alias data: contentItem.data - - height: kid.height // TODO: fix this, we shouldn't need to give the child of contentItem this id! - anchors.leftMargin: avatarSize + 4 - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: scrollbar.width - - function isFullyVisible() { - return (y - view.contentY - 1) + height < view.height - } - function getIndex() { - return index; - } - - Item { - id: contentItem - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop - } - - StatusIndicator { - state: model.state - Layout.alignment: Qt.AlignRight | Qt.AlignTop - Layout.preferredHeight: 16 - } - - EncryptionIndicator { - visible: model.isEncrypted - Layout.alignment: Qt.AlignRight | Qt.AlignTop - Layout.preferredHeight: 16 - } - - Button { - Layout.alignment: Qt.AlignRight | Qt.AlignTop - id: replyButton - flat: true - Layout.preferredHeight: 16 - - ToolTip { - visible: replyButton.hovered - text: qsTr("Reply") - palette: colors - } - - // disable background, because we don't want a border on hover - background: Item { - } - - Image { - id: replyButtonImg - // Workaround, can't get icon.source working for now... - anchors.fill: parent - source: "qrc:/icons/icons/ui/mail-reply.png" - } - ColorOverlay { - anchors.fill: replyButtonImg - source: replyButtonImg - color: replyButton.hovered ? colors.highlight : colors.buttonText - } - - onClicked: view.model.replyAction(model.id) - } - Button { - Layout.alignment: Qt.AlignRight | Qt.AlignTop - id: optionsButton - flat: true - Layout.preferredHeight: 16 - - ToolTip { - visible: optionsButton.hovered - text: qsTr("Options") - palette: colors - } - - // disable background, because we don't want a border on hover - background: Item { - } - - Image { - id: optionsButtonImg - // Workaround, can't get icon.source working for now... - anchors.fill: parent - source: "qrc:/icons/icons/ui/vertical-ellipsis.png" - } - ColorOverlay { - anchors.fill: optionsButtonImg - source: optionsButtonImg - color: optionsButton.hovered ? colors.highlight : colors.buttonText - } - - onClicked: contextMenu.open() - - Menu { - y: optionsButton.height - id: contextMenu - palette: colors - - MenuItem { - text: qsTr("Read receipts") - onTriggered: view.model.readReceiptsAction(model.id) - } - MenuItem { - text: qsTr("Mark as read") - } - MenuItem { - text: qsTr("View raw message") - onTriggered: view.model.viewRawMessage(model.id) - } - MenuItem { - text: qsTr("Redact message") - onTriggered: view.model.redactEvent(model.id) - } - MenuItem { - visible: model.type == MtxEvent.ImageMessage || model.type == MtxEvent.VideoMessage || model.type == MtxEvent.AudioMessage || model.type == MtxEvent.FileMessage || model.type == MtxEvent.Sticker - text: qsTr("Save as") - onTriggered: timelineManager.saveMedia(model.url, model.filename, model.mimetype, model.type) - } - } - } - - Text { - Layout.alignment: Qt.AlignRight | Qt.AlignTop - text: model.timestamp.toLocaleTimeString("HH:mm") - color: inactiveColors.text - - MouseArea{ - id: ma - anchors.fill: parent - hoverEnabled: true - } - - ToolTip { - visible: ma.containsMouse - text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) - palette: colors - } - } -} diff --git a/resources/res.qrc b/resources/res.qrc index 4816ffad..86b1364c 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -116,11 +116,11 @@ qml/TimelineView.qml - qml/RowDelegateChooser.qml qml/Avatar.qml qml/StatusIndicator.qml qml/EncryptionIndicator.qml - qml/delegates/TimelineRow.qml + qml/TimelineRow.qml + qml/delegates/MessageDelegate.qml qml/delegates/TextMessage.qml qml/delegates/NoticeMessage.qml qml/delegates/ImageMessage.qml -- cgit 1.5.1 From 88dc72df4f7cd6cabdb48866e6030f5e506eb24f Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 3 Nov 2019 03:28:16 +0100 Subject: Enable link handling --- resources/qml/MatrixText.qml | 33 +++++++++++++++++++++++++++++++ resources/qml/delegates/NoticeMessage.qml | 8 ++------ resources/qml/delegates/Placeholder.qml | 7 ++----- resources/qml/delegates/TextMessage.qml | 9 ++------- resources/res.qrc | 1 + src/timeline2/TimelineModel.cpp | 1 + 6 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 resources/qml/MatrixText.qml (limited to 'resources/qml/delegates/TextMessage.qml') diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml new file mode 100644 index 00000000..5d20095c --- /dev/null +++ b/resources/qml/MatrixText.qml @@ -0,0 +1,33 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.3 + +TextEdit { + textFormat: TextEdit.RichText + readOnly: true + wrapMode: Text.Wrap + selectByMouse: true + color: colors.text + + onLinkActivated: { + if (/^https:\/\/matrix.to\/#\/(@.*)$/.test(link)) chat.model.openUserProfile(/^https:\/\/matrix.to\/#\/(@.*)$/.exec(link)[1]) + if (/^https:\/\/matrix.to\/#\/(![^\/]*)$/.test(link)) timelineManager.setHistoryView(/^https:\/\/matrix.to\/#\/(!.*)$/.exec(link)[1]) + if (/^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.test(link)) { + var match = /^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.exec(link) + timelineManager.setHistoryView(match[1]) + chat.positionViewAtIndex(chat.model.idToIndex(match[2]), ListView.Contain) + } + else Qt.openUrlExternally(link) + } + MouseArea + { + anchors.fill: parent + onPressed: mouse.accepted = false + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + + ToolTip { + visible: parent.hoveredLink + text: parent.hoveredLink + palette: colors + } +} diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml index 59e051be..a392eb5b 100644 --- a/resources/qml/delegates/NoticeMessage.qml +++ b/resources/qml/delegates/NoticeMessage.qml @@ -1,12 +1,8 @@ -import QtQuick 2.5 +import ".." -TextEdit { +MatrixText { text: model.formattedBody - textFormat: TextEdit.RichText - readOnly: true - wrapMode: Text.Wrap width: parent ? parent.width : undefined - selectByMouse: true font.italic: true color: inactiveColors.text } diff --git a/resources/qml/delegates/Placeholder.qml b/resources/qml/delegates/Placeholder.qml index 171bf18d..4c0e68c3 100644 --- a/resources/qml/delegates/Placeholder.qml +++ b/resources/qml/delegates/Placeholder.qml @@ -1,10 +1,7 @@ -import QtQuick 2.5 -import QtQuick.Controls 2.1 +import ".." -Label { +MatrixText { text: qsTr("unimplemented event: ") + model.type - textFormat: Text.PlainText - wrapMode: Text.Wrap width: parent ? parent.width : undefined color: inactiveColors.text } diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index 713be868..990a3f5b 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -1,11 +1,6 @@ -import QtQuick 2.5 +import ".." -TextEdit { +MatrixText { text: model.formattedBody - textFormat: TextEdit.RichText - readOnly: true - wrapMode: Text.Wrap width: parent ? parent.width : undefined - selectByMouse: true - color: colors.text } diff --git a/resources/res.qrc b/resources/res.qrc index 264ed82d..c9938d57 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -118,6 +118,7 @@ qml/TimelineView.qml qml/Avatar.qml qml/ImageButton.qml + qml/MatrixText.qml qml/StatusIndicator.qml qml/EncryptionIndicator.qml qml/TimelineRow.qml diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp index fa87ec26..bdb3ea6f 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp @@ -827,6 +827,7 @@ TimelineModel::replyAction(QString id) [](const auto &e) -> std::string { return eventMsgType(e); }, event)); related.quoted_body = boost::apply_visitor([](const auto &e) -> QString { return eventBody(e); }, event); + related.room = room_id_; if (related.quoted_body.isEmpty()) return; -- cgit 1.5.1 From 85aae9408b2bb8ebd64c91fdcb4eddc9aec49746 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 22 Nov 2019 16:37:43 +0100 Subject: Wrap text in pre tags --- resources/qml/delegates/TextMessage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'resources/qml/delegates/TextMessage.qml') diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index 990a3f5b..f984b32f 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -1,6 +1,6 @@ import ".." MatrixText { - text: model.formattedBody + text: model.formattedBody.replace("
", "
")
 	width: parent ? parent.width : undefined
 }
-- 
cgit 1.5.1