Rewrite MessageDelegate.

square-messages
Black Hat 2018-09-04 14:58:41 +08:00
parent 0301590b44
commit 2f080f21ce
18 changed files with 272 additions and 323 deletions

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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) : {}
}
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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: "<b>File: </b>" + content.body
}
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}
}
}

View File

@ -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
}
}

View File

@ -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: "<b>File: </b>" + 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 ""
}
}
}

View File

@ -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: "<b>" + author.displayName + "</b> " + display
}

View File

@ -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: "<b>" + author.displayName + "</b> " + 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"
}
}

View File

@ -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
}
}
}

View File

@ -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

View File

@ -65,7 +65,7 @@ ApplicationWindow {
parent: null
connection: matriqueController.isLogin ? window.connection : null
connection: window.connection
}
Setting {

View File

@ -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

10
res.qrc
View File

@ -14,16 +14,9 @@
<file>asset/img/icon.png</file>
<file>js/md.js</file>
<file>qml/component/MessageDelegate.qml</file>
<file>qml/component/MessageBubble.qml</file>
<file>qml/component/ImageBubble.qml</file>
<file>qml/component/StateBubble.qml</file>
<file>qml/component/DownloadableContent.qml</file>
<file>qml/component/FileBubble.qml</file>
<file>qml/component/AvatarContainer.qml</file>
<file>qml/form/RoomListForm.qml</file>
<file>qml/component/AudioBubble.qml</file>
<file>qml/Setting.qml</file>
<file>qml/component/TextDelegate.qml</file>
<file>qml/component/EmojiPicker.qml</file>
<file>qml/component/EmojiButton.qml</file>
<file>qml/component/AutoImage.qml</file>
@ -33,5 +26,8 @@
<file>qml/MatriqueSettings.qml</file>
<file>qml/menu/MessageContextMenu.qml</file>
<file>qml/menu/RoomContextMenu.qml</file>
<file>qml/component/GenericBubble.qml</file>
<file>qml/component/StateDelegate.qml</file>
<file>qml/component/AutoLabel.qml</file>
</qresource>
</RCC>