From 2f080f21ced81fc88162c14e32020132d5d06243 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Tue, 4 Sep 2018 14:58:41 +0800 Subject: [PATCH] Rewrite MessageDelegate. --- matrique.pro | 7 +- qml/MatriqueSettings.qml | 1 - qml/Setting.qml | 6 - qml/component/AudioBubble.qml | 50 -------- qml/component/AutoLabel.qml | 15 +++ qml/component/AvatarContainer.qml | 26 ---- qml/component/FileBubble.qml | 28 ----- qml/component/GenericBubble.qml | 24 ++++ qml/component/ImageBubble.qml | 34 ------ qml/component/MessageBubble.qml | 20 --- qml/component/MessageDelegate.qml | 195 +++++++++++++++++++++++++----- qml/component/StateBubble.qml | 12 -- qml/component/StateDelegate.qml | 23 ++++ qml/component/TextDelegate.qml | 61 ---------- qml/form/RoomForm.qml | 77 ++++++------ qml/main.qml | 2 +- qml/menu/MessageContextMenu.qml | 4 +- res.qrc | 10 +- 18 files changed, 272 insertions(+), 323 deletions(-) delete mode 100644 qml/component/AudioBubble.qml create mode 100644 qml/component/AutoLabel.qml delete mode 100644 qml/component/AvatarContainer.qml delete mode 100644 qml/component/FileBubble.qml create mode 100644 qml/component/GenericBubble.qml delete mode 100644 qml/component/ImageBubble.qml delete mode 100644 qml/component/MessageBubble.qml delete mode 100644 qml/component/StateBubble.qml create mode 100644 qml/component/StateDelegate.qml delete mode 100644 qml/component/TextDelegate.qml diff --git a/matrique.pro b/matrique.pro index 5a6d65a..f27d296 100644 --- a/matrique.pro +++ b/matrique.pro @@ -1,7 +1,9 @@ QT += quick widgets multimedia CONFIG += c++14 CONFIG += object_parallel_to_source -CONFIG += qtquickcompiler + +# Enable this to use QtQuick Compiler. +#CONFIG += qtquickcompiler TARGET = matrique @@ -75,10 +77,9 @@ DISTFILES += \ ButtonDelegate.qml \ SideNav.qml \ RoomListForm.qml \ - RoomDetailForm.qml \ Room.qml \ Setting.qml \ - qml/js/md.js + qml/js/md.js \ HEADERS += \ src/controller.h \ diff --git a/qml/MatriqueSettings.qml b/qml/MatriqueSettings.qml index 6bcdbb5..1c8ead1 100644 --- a/qml/MatriqueSettings.qml +++ b/qml/MatriqueSettings.qml @@ -4,7 +4,6 @@ import Qt.labs.settings 1.0 Settings { property bool lazyLoad: true - property bool asyncMessageDelegate property bool richText property bool pressAndHold property bool rearrangeByActivity diff --git a/qml/Setting.qml b/qml/Setting.qml index 968ee5b..d268159 100644 --- a/qml/Setting.qml +++ b/qml/Setting.qml @@ -66,12 +66,6 @@ Page { onCheckedChanged: MSettings.lazyLoad = checked } - Switch { - text: "Force loading message delegates asynchronously" - checked: MSettings.asyncMessageDelegate - onCheckedChanged: MSettings.asyncMessageDelegate = checked - } - Switch { text: "Use RichText instead of StyledText" checked: MSettings.richText diff --git a/qml/component/AudioBubble.qml b/qml/component/AudioBubble.qml deleted file mode 100644 index e01f5ae..0000000 --- a/qml/component/AudioBubble.qml +++ /dev/null @@ -1,50 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 -import QtMultimedia 5.9 -import Qt.labs.platform 1.0 - -AvatarContainer { - readonly property var downloadAndOpen: downloadable.downloadAndOpen - readonly property var saveFileAs: downloadable.saveFileAs - - property bool playOnFinished: false - - id: messageRow - - DownloadableContent { - id: downloadable - - width: downloadDelegate.width - height: downloadDelegate.height - - TextDelegate { - id: downloadDelegate - - maximumWidth: messageListView.width - highlighted: !sentByMe - timeLabelVisible: false - authorLabelVisible: false - - displayText: content.info.duration / 1000 + '"' - - MouseArea { - anchors.fill: parent - - propagateComposedEvents: true - - onClicked: { - if (downloadable.downloaded) - matriqueController.playAudio(progressInfo.localPath) - else - { - playOnFinished = true - currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + ".tmp") - } - } - } - } - onDownloadedChanged: downloaded && playOnFinished ? matriqueController.playAudio(progressInfo.localPath) : {} - } - -} diff --git a/qml/component/AutoLabel.qml b/qml/component/AutoLabel.qml new file mode 100644 index 0000000..238c831 --- /dev/null +++ b/qml/component/AutoLabel.qml @@ -0,0 +1,15 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Controls.Material 2.2 +import Matrique.Settings 0.1 + +Label { + property bool coloredBackground + + color: coloredBackground ? "white": Material.foreground + + wrapMode: Label.Wrap + linkColor: coloredBackground ? "white" : Material.accent + textFormat: MSettings.richText ? Text.RichText : Text.StyledText + onLinkActivated: Qt.openUrlExternally(link) +} diff --git a/qml/component/AvatarContainer.qml b/qml/component/AvatarContainer.qml deleted file mode 100644 index 64c4599..0000000 --- a/qml/component/AvatarContainer.qml +++ /dev/null @@ -1,26 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 - -Row { - readonly property bool avatarVisible: !(sentByMe || (aboveAuthor === author && section === aboveSection)) - - spacing: 6 - - ImageStatus { - id: avatar - - width: height - height: 40 - round: false - visible: avatarVisible - source: author.avatarUrl != "" ? "image://mxc/" + author.avatarUrl : null - displayText: author.displayName - } - - Rectangle { - width: height - height: 40 - color: "transparent" - visible: !avatarVisible - } -} diff --git a/qml/component/FileBubble.qml b/qml/component/FileBubble.qml deleted file mode 100644 index 4ff77bd..0000000 --- a/qml/component/FileBubble.qml +++ /dev/null @@ -1,28 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 - -AvatarContainer { - readonly property var downloadAndOpen: downloadable.downloadAndOpen - readonly property var saveFileAs: downloadable.saveFileAs - - id: messageRow - - DownloadableContent { - id: downloadable - - width: downloadDelegate.width - height: downloadDelegate.height - - TextDelegate { - id: downloadDelegate - - maximumWidth: messageListView.width - highlighted: !sentByMe - timeLabelVisible: false - authorLabelVisible: false - - displayText: "File: " + content.body - } - } -} diff --git a/qml/component/GenericBubble.qml b/qml/component/GenericBubble.qml new file mode 100644 index 0000000..369423e --- /dev/null +++ b/qml/component/GenericBubble.qml @@ -0,0 +1,24 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Controls.Material 2.2 +import Matrique.Settings 0.1 + +Control { + property bool highlighted: false + property bool colored: false + + readonly property bool darkBackground: highlighted ? true : MSettings.darkTheme + readonly property color backgroundColor: MSettings.darkTheme ? "#242424" : "lightgrey" + + padding: 12 + + background: Rectangle { + color: colored ? Material.accent : highlighted ? Material.primary : backgroundColor + } + + AutoMouseArea { + anchors.fill: parent + + onSecondaryClicked: Qt.createComponent("qrc:/qml/menu/MessageContextMenu.qml").createObject(this) + } +} diff --git a/qml/component/ImageBubble.qml b/qml/component/ImageBubble.qml deleted file mode 100644 index 979c670..0000000 --- a/qml/component/ImageBubble.qml +++ /dev/null @@ -1,34 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 - -AvatarContainer { - readonly property var downloadAndOpen: downloadable.downloadAndOpen - readonly property var saveFileAs: downloadable.saveFileAs - - Rectangle { - id: messageRect - - width: messageImage.width + 24 - height: messageImage.height + 24 - - color: sentByMe ? background : Material.primary - - DownloadableContent { - id: downloadable - - width: messageImage.width - height: messageImage.height - anchors.centerIn: parent - - AutoImage { - id: messageImage - z: -4 - sourceSize: 128 - source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url) - - onClicked: downloadAndOpen() - } - } - } -} diff --git a/qml/component/MessageBubble.qml b/qml/component/MessageBubble.qml deleted file mode 100644 index 7e87cae..0000000 --- a/qml/component/MessageBubble.qml +++ /dev/null @@ -1,20 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 - -AvatarContainer { - readonly property bool isNotice: eventType === "notice" - - id: messageRow - - TextDelegate { - maximumWidth: messageListView.width - (!sentByMe ? 40 + messageRow.spacing : 0) - flat: isNotice - highlighted: !sentByMe - timeLabelVisible: Math.abs(time - aboveTime) > 600000 || index == 0 - authorLabelVisible: messageRow.avatarVisible - - displayText: display - } -} diff --git a/qml/component/MessageDelegate.qml b/qml/component/MessageDelegate.qml index e007cbf..a78ab35 100644 --- a/qml/component/MessageDelegate.qml +++ b/qml/component/MessageDelegate.qml @@ -1,53 +1,184 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.2 import Matrique 0.1 import Matrique.Settings 0.1 -Item { - readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden - readonly property color background: MSettings.darkTheme ? "#242424" : "lightgrey" +RowLayout { + readonly property bool avatarVisible: !(sentByMe || (aboveAuthor === author && section === aboveSection)) + readonly property bool highlighted: !sentByMe readonly property bool sentByMe: author === currentRoom.localUser - readonly property bool isState: eventType === "state" || eventType === "emote" + readonly property bool isText: eventType === "notice" || eventType === "message" - id: messageDelegate + signal saveFileAs() + signal openExternally() + + id: messageRow z: -5 - width: delegateLoader.width - height: delegateLoader.height - anchors.right: !isState && sentByMe ? parent.right : undefined - anchors.horizontalCenter: isState ? parent.horizontalCenter : undefined + Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft - AutoMouseArea { - anchors.fill: parent + spacing: 6 - onSecondaryClicked: Qt.createComponent("qrc:/qml/menu/MessageContextMenu.qml").createObject(this) + ImageStatus { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignTop + + round: false + visible: avatarVisible + source: author.avatarUrl != "" ? "image://mxc/" + author.avatarUrl : null + displayText: author.displayName } - Loader { - id: delegateLoader + Rectangle { + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + Layout.alignment: Qt.AlignTop - asynchronous: MSettings.asyncMessageDelegate + color: "transparent" + visible: !(sentByMe || avatarVisible) + } - source: { - if (eventType == "redaction" || hidden) return "" - switch (eventType) { - case "state": - case "emote": - return "StateBubble.qml" - case "message": - case "notice": - return "MessageBubble.qml" - case "image": - return "ImageBubble.qml" - case "audio": - return "AudioBubble.qml" - case "video": - case "file": - return "FileBubble.qml" + GenericBubble { + Layout.maximumWidth: messageListView.width - (!sentByMe ? 40 + messageRow.spacing : 0) + + id: genericBubble + + highlighted: !sentByMe + colored: highlighted && eventType === "notice" + + contentItem: ColumnLayout { + id: messageColumn + + spacing: 0 + + AutoLabel { + visible: messageRow.avatarVisible + text: author.displayName + Material.foreground: Material.accent + coloredBackground: highlighted + font.bold: true + } + + AutoLabel { + Layout.fillWidth: true + + text: display + visible: isText + coloredBackground: highlighted + } + + Loader { + sourceComponent: { + switch (eventType) { + case "image": + return imageComponent + case "file": + return fileComponent + case "audio": + return audioComponent + } + } + + active: eventType === "image" || eventType === "file" || eventType === "audio" + } + + AutoLabel { + Layout.alignment: Qt.AlignRight + visible: Math.abs(time - aboveTime) > 600000 || index == 0 + text: Qt.formatTime(time, "hh:mm") + coloredBackground: highlighted + Material.foreground: "grey" + font.pointSize: 8 + } + } + + Component { + id: imageComponent + + DownloadableContent { + id: downloadable + + width: messageImage.width + height: messageImage.height + + AutoImage { + id: messageImage + z: -4 + sourceSize: 128 + source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url) + + onClicked: downloadAndOpen() + } + + Component.onCompleted: { + messageRow.saveFileAs.connect(saveFileAs) + messageRow.openExternally.connect(downloadAndOpen) + } + } + } + + Component { + id: fileComponent + + AutoLabel { + Layout.fillWidth: true + + id: downloadDelegate + + text: "File: " + content.body + coloredBackground: highlighted + + background: DownloadableContent { + id: downloadable + + Component.onCompleted: { + messageRow.saveFileAs.connect(saveFileAs) + messageRow.openExternally.connect(downloadAndOpen) + } + } + } + } + + Component { + id: audioComponent + + AutoLabel { + id: downloadDelegate + + text: content.info.duration / 1000 + '"' + coloredBackground: highlighted + + MouseArea { + anchors.fill: parent + + propagateComposedEvents: true + + onClicked: { + if (downloadable.downloaded) + matriqueController.playAudio(progressInfo.localPath) + else + { + playOnFinished = true + currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + ".tmp") + } + } + } + + background: DownloadableContent { + id: downloadable + + onDownloadedChanged: downloaded && playOnFinished ? matriqueController.playAudio(progressInfo.localPath) : {} + + Component.onCompleted: { + messageRow.saveFileAs.connect(saveFileAs) + messageRow.openExternally.connect(downloadAndOpen) + } + } } - return "" } } } diff --git a/qml/component/StateBubble.qml b/qml/component/StateBubble.qml deleted file mode 100644 index 693c677..0000000 --- a/qml/component/StateBubble.qml +++ /dev/null @@ -1,12 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 - -TextDelegate { - maximumWidth: messageListView.width - highlighted: eventType === "emote" - timeLabelVisible: false - authorLabelVisible: false - - displayText: "" + author.displayName + " " + display -} diff --git a/qml/component/StateDelegate.qml b/qml/component/StateDelegate.qml new file mode 100644 index 0000000..376763f --- /dev/null +++ b/qml/component/StateDelegate.qml @@ -0,0 +1,23 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import Matrique.Settings 0.1 + +Label { + Layout.alignment: Qt.AlignHCenter + + text: "" + author.displayName + " " + display + color: "white" + + padding: 8 + + wrapMode: Label.Wrap + linkColor: "white" + textFormat: MSettings.richText ? Text.RichText : Text.StyledText + onLinkActivated: Qt.openUrlExternally(link) + + background: Rectangle { + color: MSettings.darkTheme ? "#484848" : "grey" + } +} diff --git a/qml/component/TextDelegate.qml b/qml/component/TextDelegate.qml deleted file mode 100644 index 9470178..0000000 --- a/qml/component/TextDelegate.qml +++ /dev/null @@ -1,61 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 -import QtQuick.Layouts 1.3 -import Matrique.Settings 0.1 - -Rectangle { - property bool flat: false - property bool highlighted: false - property string displayText: "" - property alias timeLabelVisible: timeText.visible - property alias authorLabelVisible: authorText.visible - - property int maximumWidth - - readonly property bool darkBackground: highlighted && !flat - - id: messageRect - - width: Math.min(Math.max(messageText.implicitWidth, (timeText.visible ? timeText.implicitWidth : 0), (authorLabelVisible ? authorText.implicitWidth : 0)) + 24, maximumWidth) - height: (authorText.visible ? authorText.implicitHeight : 0) + messageText.implicitHeight + (timeText.visible ? timeText.implicitHeight : 0) + 24 - - color: flat ? "transparent" : highlighted ? Material.primary : background - border.color: Material.primary - border.width: flat ? 2 : 0 - - ColumnLayout { - id: messageColumn - - anchors.fill: parent - anchors.margins: 12 - spacing: 0 - - Label { - id: authorText - text: author.displayName - color: darkBackground ? "white" : Material.accent - font.bold: true - } - - Label { - id: messageText - Layout.maximumWidth: parent.width - text: displayText - color: darkBackground ? "white": Material.foreground - - wrapMode: Label.Wrap - linkColor: darkBackground ? "white" : Material.accent - textFormat: MSettings.richText ? Text.RichText : Text.StyledText - onLinkActivated: Qt.openUrlExternally(link) - } - - Label { - id: timeText - Layout.alignment: Qt.AlignRight - text: Qt.formatTime(time, "hh:mm") - color: darkBackground ? "white" : "grey" - font.pointSize: 8 - } - } -} diff --git a/qml/form/RoomForm.qml b/qml/form/RoomForm.qml index c94ec12..c8faaec 100644 --- a/qml/form/RoomForm.qml +++ b/qml/form/RoomForm.qml @@ -233,70 +233,67 @@ Item { spacing: 8 boundsBehavior: Flickable.DragOverBounds + maximumFlickVelocity: 2048 model: MessageEventModel { id: messageEventModel room: currentRoom } - delegate: Column { + delegate: ColumnLayout { readonly property bool hidden: marks === EventStatus.Redacted || marks === EventStatus.Hidden + id: delegateColumn + width: parent.width height: hidden ? -8 : undefined + spacing: 8 - RowLayout { - width: parent.width * 0.8 + Label { + Layout.alignment: Qt.AlignHCenter + visible: section !== aboveSection && !hidden - anchors.horizontalCenter: parent.horizontalCenter - spacing: 8 - Rectangle { - Layout.fillWidth: true - height:2 - color: Material.accent - } + text: section + color: "white" + verticalAlignment: Text.AlignVCenter + leftPadding: 8 + rightPadding: 8 + topPadding: 4 + bottomPadding: 4 - Label { - text: section - color: Material.accent - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - Layout.fillWidth: true - height:2 - color: Material.accent + background: Rectangle { + color: MSettings.darkTheme ? "#484848" : "grey" } } - RowLayout { - width: parent.width * 0.8 + Label { + Layout.alignment: Qt.AlignHCenter + visible: readMarker === true && index !== 0 - anchors.horizontalCenter: parent.horizontalCenter - spacing: 8 - Rectangle { - Layout.fillWidth: true - height:2 - color: Material.accent - } + text: "And Now" + color: "white" + verticalAlignment: Text.AlignVCenter + leftPadding: 8 + rightPadding: 8 + topPadding: 4 + bottomPadding: 4 - Label { - text: "And Now" - color: Material.accent - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - Layout.fillWidth: true - height:2 - color: Material.accent + background: Rectangle { + color: MSettings.darkTheme ? "#484848" : "grey" } } - MessageDelegate {} + MessageDelegate { + visible: eventType === "notice" || eventType === "message" || eventType === "image" || eventType === "video" || eventType === "audio" || eventType === "file" + } + + StateDelegate { + Layout.maximumWidth: messageListView.width * 0.8 + visible: eventType === "emote" || eventType === "state" + } } ScrollBar.vertical: messageListViewScrollBar diff --git a/qml/main.qml b/qml/main.qml index 1f06ca1..a2d4186 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -65,7 +65,7 @@ ApplicationWindow { parent: null - connection: matriqueController.isLogin ? window.connection : null + connection: window.connection } Setting { diff --git a/qml/menu/MessageContextMenu.qml b/qml/menu/MessageContextMenu.qml index dd2b92d..91c8e03 100644 --- a/qml/menu/MessageContextMenu.qml +++ b/qml/menu/MessageContextMenu.qml @@ -18,13 +18,13 @@ Menu { visible: isFile height: visible ? undefined : 0 text: "Open Externally" - onTriggered: delegateLoader.item.downloadAndOpen() + onTriggered: messageRow.openExternally() } MenuItem { visible: isFile height: visible ? undefined : 0 text: "Save As" - onTriggered: delegateLoader.item.saveFileAs() + onTriggered: messageRow.saveFileAs() } MenuItem { visible: sentByMe diff --git a/res.qrc b/res.qrc index e2c99a1..71c1cf5 100644 --- a/res.qrc +++ b/res.qrc @@ -14,16 +14,9 @@ asset/img/icon.png js/md.js qml/component/MessageDelegate.qml - qml/component/MessageBubble.qml - qml/component/ImageBubble.qml - qml/component/StateBubble.qml qml/component/DownloadableContent.qml - qml/component/FileBubble.qml - qml/component/AvatarContainer.qml qml/form/RoomListForm.qml - qml/component/AudioBubble.qml qml/Setting.qml - qml/component/TextDelegate.qml qml/component/EmojiPicker.qml qml/component/EmojiButton.qml qml/component/AutoImage.qml @@ -33,5 +26,8 @@ qml/MatriqueSettings.qml qml/menu/MessageContextMenu.qml qml/menu/RoomContextMenu.qml + qml/component/GenericBubble.qml + qml/component/StateDelegate.qml + qml/component/AutoLabel.qml