Fix the timeline Part 2: Bubble Rework
This reworks the bubble as a separate component and makes some fixes to prevent the console being spammed with polish loop warnings.
This commit is contained in:
@@ -38,10 +38,7 @@ MessageDelegate {
|
|||||||
|
|
||||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||||
|
|
||||||
innerObject: ColumnLayout {
|
bubbleContent: ColumnLayout {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.maximumWidth: root.contentMaxWidth
|
|
||||||
|
|
||||||
MediaPlayer {
|
MediaPlayer {
|
||||||
id: audio
|
id: audio
|
||||||
source: root.progressInfo.localPath
|
source: root.progressInfo.localPath
|
||||||
|
|||||||
226
src/qml/Component/Timeline/Bubble.qml
Normal file
226
src/qml/Component/Timeline/Bubble.qml
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import org.kde.kirigami 2.15 as Kirigami
|
||||||
|
|
||||||
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A chat bubble for displaying the content of message events.
|
||||||
|
*
|
||||||
|
* The content of the bubble is set via the content property which is then managed
|
||||||
|
* by the bubble to apply the correct sizing (including limiting the width if a
|
||||||
|
* maxContentWidth is set).
|
||||||
|
*
|
||||||
|
* The bubble also supports a header with the author and message timestamp and a
|
||||||
|
* reply.
|
||||||
|
*/
|
||||||
|
QQC2.Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The message author.
|
||||||
|
*
|
||||||
|
* This should consist of the following:
|
||||||
|
* - id - The matrix ID of the author.
|
||||||
|
* - isLocalUser - Whether the author is the local user.
|
||||||
|
* - avatarSource - The mxc URL for the author's avatar in the current room.
|
||||||
|
* - avatarMediaId - The media ID of the author's avatar.
|
||||||
|
* - avatarUrl - The mxc URL for the author's avatar.
|
||||||
|
* - displayName - The display name of the author.
|
||||||
|
* - display - The name of the author.
|
||||||
|
* - color - The color for the author.
|
||||||
|
* - object - The Quotient::User object for the author.
|
||||||
|
*
|
||||||
|
* @sa Quotient::User
|
||||||
|
*/
|
||||||
|
property var author
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The timestamp of the message.
|
||||||
|
*/
|
||||||
|
property var time
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The timestamp of the message as a string.
|
||||||
|
*/
|
||||||
|
property string timeString
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the message should be highlighted.
|
||||||
|
*/
|
||||||
|
property bool showHighlight: false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The main delegate content item to show in the bubble.
|
||||||
|
*/
|
||||||
|
property Item content
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether this message is replying to another.
|
||||||
|
*/
|
||||||
|
property bool isReply: false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The matrix ID of the reply event.
|
||||||
|
*/
|
||||||
|
required property var replyId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The reply author.
|
||||||
|
*
|
||||||
|
* This should consist of the following:
|
||||||
|
* - id - The matrix ID of the reply author.
|
||||||
|
* - isLocalUser - Whether the reply author is the local user.
|
||||||
|
* - avatarSource - The mxc URL for the reply author's avatar in the current room.
|
||||||
|
* - avatarMediaId - The media ID of the reply author's avatar.
|
||||||
|
* - avatarUrl - The mxc URL for the reply author's avatar.
|
||||||
|
* - displayName - The display name of the reply author.
|
||||||
|
* - display - The name of the reply author.
|
||||||
|
* - color - The color for the reply author.
|
||||||
|
* - object - The Quotient::User object for the reply author.
|
||||||
|
*
|
||||||
|
* @sa Quotient::User
|
||||||
|
*/
|
||||||
|
required property var replyAuthor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The delegate type of the message replied to.
|
||||||
|
*/
|
||||||
|
required property int replyDelegateType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The display text of the message replied to.
|
||||||
|
*/
|
||||||
|
required property string replyDisplay
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The media info for the reply event.
|
||||||
|
*
|
||||||
|
* This could be an image, audio, video or file.
|
||||||
|
*
|
||||||
|
* This should consist of the following:
|
||||||
|
* - source - The mxc URL for the media.
|
||||||
|
* - mimeType - The MIME type of the media.
|
||||||
|
* - mimeIcon - The MIME icon name.
|
||||||
|
* - size - The file size in bytes.
|
||||||
|
* - duration - The length in seconds of the audio media (audio/video only).
|
||||||
|
* - width - The width in pixels of the audio media (image/video only).
|
||||||
|
* - height - The height in pixels of the audio media (image/video only).
|
||||||
|
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads (image/video only).
|
||||||
|
*/
|
||||||
|
required property var replyMediaInfo
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether the bubble background should be shown.
|
||||||
|
*/
|
||||||
|
property alias showBackground: bubbleBackground.visible
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The maximum width that the bubble's content can be.
|
||||||
|
*/
|
||||||
|
property real maxContentWidth: -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The reply has been clicked.
|
||||||
|
*/
|
||||||
|
signal replyClicked(string eventID)
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
RowLayout {
|
||||||
|
Layout.maximumWidth: root.maxContentWidth
|
||||||
|
QQC2.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.author.displayName
|
||||||
|
color: root.author.color
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
font.weight: Font.Bold
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: RoomManager.visitUser(root.author.object, "mention")
|
||||||
|
}
|
||||||
|
HoverHandler {
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
text: root.timeString
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
color: Kirigami.Theme.disabledTextColor
|
||||||
|
QQC2.ToolTip.visible: timeHoverHandler.hovered
|
||||||
|
QQC2.ToolTip.text: root.time.toLocaleString(Qt.locale(), Locale.LongFormat)
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: timeHoverHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loader {
|
||||||
|
id: replyLoader
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumWidth: root.maxContentWidth
|
||||||
|
|
||||||
|
active: root.isReply && root.replyDelegateType !== DelegateType.Other
|
||||||
|
visible: active
|
||||||
|
|
||||||
|
sourceComponent: ReplyComponent {
|
||||||
|
author: root.replyAuthor
|
||||||
|
type: root.replyDelegateType
|
||||||
|
display: root.replyDisplay
|
||||||
|
mediaInfo: root.replyMediaInfo
|
||||||
|
contentMaxWidth: root.maxContentWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: replyLoader.item
|
||||||
|
function onReplyClicked() {
|
||||||
|
replyClicked(root.replyId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
id: contentParent
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumWidth: root.maxContentWidth
|
||||||
|
implicitWidth: root.content ? root.content.implicitWidth : 0
|
||||||
|
implicitHeight: root.content ? root.content.implicitHeight : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Kirigami.ShadowedRectangle {
|
||||||
|
id: bubbleBackground
|
||||||
|
visible: root.showBackground
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||||
|
Kirigami.Theme.inherit: false
|
||||||
|
color: if (root.author.isLocalUser) {
|
||||||
|
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
|
||||||
|
} else if (root.showHighlight) {
|
||||||
|
return Kirigami.Theme.positiveBackgroundColor
|
||||||
|
} else {
|
||||||
|
return Kirigami.Theme.backgroundColor
|
||||||
|
}
|
||||||
|
radius: Kirigami.Units.smallSpacing
|
||||||
|
shadow {
|
||||||
|
size: Kirigami.Units.smallSpacing
|
||||||
|
color: root.showHighlight ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation { duration: Kirigami.Units.shortDuration }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onContentChanged: {
|
||||||
|
if (!root.content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
root.content.parent = contentParent;
|
||||||
|
root.content.anchors.fill = contentParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ import org.kde.neochat
|
|||||||
MessageDelegate {
|
MessageDelegate {
|
||||||
id: encryptedDelegate
|
id: encryptedDelegate
|
||||||
|
|
||||||
innerObject: TextEdit {
|
bubbleContent: TextEdit {
|
||||||
text: i18n("This message is encrypted and the sender has not shared the key with this device.")
|
text: i18n("This message is encrypted and the sender has not shared the key with this device.")
|
||||||
color: Kirigami.Theme.disabledTextColor
|
color: Kirigami.Theme.disabledTextColor
|
||||||
selectedTextColor: Kirigami.Theme.highlightedTextColor
|
selectedTextColor: Kirigami.Theme.highlightedTextColor
|
||||||
@@ -25,7 +25,6 @@ MessageDelegate {
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
Layout.maximumWidth: encryptedDelegate.contentMaxWidth
|
|
||||||
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
Layout.leftMargin: Config.showAvatarInTimeline ? Kirigami.Units.largeSpacing : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ MessageDelegate {
|
|||||||
UrlHelper.openUrl(root.progressInfo.localPath);
|
UrlHelper.openUrl(root.progressInfo.localPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
innerObject: RowLayout {
|
bubbleContent: RowLayout {
|
||||||
Layout.maximumWidth: Math.min(root.contentMaxWidth, implicitWidth)
|
|
||||||
|
|
||||||
spacing: Kirigami.Units.largeSpacing
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
|
|||||||
@@ -55,15 +55,13 @@ MessageDelegate {
|
|||||||
|
|
||||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||||
|
|
||||||
innerObject: Item {
|
bubbleContent: Item {
|
||||||
id: imageContainer
|
id: imageContainer
|
||||||
Layout.preferredWidth: mediaSizeHelper.currentSize.width
|
|
||||||
Layout.preferredHeight: mediaSizeHelper.currentSize.height
|
|
||||||
|
|
||||||
property var imageItem: root.mediaInfo.animated ? animatedImageLoader.item : imageLoader.item
|
property var imageItem: root.mediaInfo.animated ? animatedImageLoader.item : imageLoader.item
|
||||||
|
|
||||||
implicitWidth: root.mediaInfo.animated ? animatedImageLoader.width : imageLoader.width
|
implicitWidth: mediaSizeHelper.currentSize.width
|
||||||
implicitHeight: root.mediaInfo.animated ? animatedImageLoader.height : imageLoader.height
|
implicitHeight: mediaSizeHelper.currentSize.height
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: imageLoader
|
id: imageLoader
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ MessageDelegate {
|
|||||||
|
|
||||||
property alias room: liveLocationModel.room
|
property alias room: liveLocationModel.room
|
||||||
|
|
||||||
ColumnLayout {
|
bubbleContent: ColumnLayout {
|
||||||
Layout.maximumWidth: root.contentMaxWidth
|
|
||||||
Layout.preferredWidth: root.contentMaxWidth
|
|
||||||
LiveLocationsModel {
|
LiveLocationsModel {
|
||||||
id: liveLocationModel
|
id: liveLocationModel
|
||||||
eventId: root.eventId
|
eventId: root.eventId
|
||||||
|
|||||||
@@ -35,9 +35,7 @@ MessageDelegate {
|
|||||||
*/
|
*/
|
||||||
required property string asset
|
required property string asset
|
||||||
|
|
||||||
ColumnLayout {
|
bubbleContent: ColumnLayout {
|
||||||
Layout.maximumWidth: root.contentMaxWidth
|
|
||||||
Layout.preferredWidth: root.contentMaxWidth
|
|
||||||
Map {
|
Map {
|
||||||
id: map
|
id: map
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@@ -29,271 +29,260 @@ TimelineDelegate {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The index of the delegate in the model.
|
* @brief The index of the delegate in the model.
|
||||||
*/
|
*/
|
||||||
required property var index
|
required property var index
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The matrix ID of the message event.
|
* @brief The matrix ID of the message event.
|
||||||
*/
|
*/
|
||||||
required property string eventId
|
required property string eventId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The timestamp of the message.
|
* @brief The timestamp of the message.
|
||||||
*/
|
*/
|
||||||
required property var time
|
required property var time
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The timestamp of the message as a string.
|
* @brief The timestamp of the message as a string.
|
||||||
*/
|
*/
|
||||||
required property string timeString
|
required property string timeString
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The message author.
|
* @brief The message author.
|
||||||
*
|
*
|
||||||
* This should consist of the following:
|
* This should consist of the following:
|
||||||
* - id - The matrix ID of the author.
|
* - id - The matrix ID of the author.
|
||||||
* - isLocalUser - Whether the author is the local user.
|
* - isLocalUser - Whether the author is the local user.
|
||||||
* - avatarSource - The mxc URL for the author's avatar in the current room.
|
* - avatarSource - The mxc URL for the author's avatar in the current room.
|
||||||
* - avatarMediaId - The media ID of the author's avatar.
|
* - avatarMediaId - The media ID of the author's avatar.
|
||||||
* - avatarUrl - The mxc URL for the author's avatar.
|
* - avatarUrl - The mxc URL for the author's avatar.
|
||||||
* - displayName - The display name of the author.
|
* - displayName - The display name of the author.
|
||||||
* - display - The name of the author.
|
* - display - The name of the author.
|
||||||
* - color - The color for the author.
|
* - color - The color for the author.
|
||||||
* - object - The Quotient::User object for the author.
|
* - object - The Quotient::User object for the author.
|
||||||
*
|
*
|
||||||
* @sa Quotient::User
|
* @sa Quotient::User
|
||||||
*/
|
*/
|
||||||
required property var author
|
required property var author
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the author should be shown.
|
* @brief Whether the author should be shown.
|
||||||
*/
|
*/
|
||||||
required property bool showAuthor
|
required property bool showAuthor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the author should always be shown.
|
* @brief Whether the author should always be shown.
|
||||||
*
|
*
|
||||||
* This is primarily used when these delegates are used in a filtered list of
|
* This is primarily used when these delegates are used in a filtered list of
|
||||||
* events rather than a sequential timeline, e.g. the media model view.
|
* events rather than a sequential timeline, e.g. the media model view.
|
||||||
*
|
*
|
||||||
* @note This setting still respects the avatar configuration settings.
|
* @note This setting still respects the avatar configuration settings.
|
||||||
*/
|
*/
|
||||||
property bool alwaysShowAuthor: false
|
property bool alwaysShowAuthor: false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The delegate type of the message.
|
* @brief The delegate type of the message.
|
||||||
*/
|
*/
|
||||||
required property int delegateType
|
required property int delegateType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The display text of the message.
|
* @brief The display text of the message.
|
||||||
*/
|
*/
|
||||||
required property string display
|
required property string display
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The display text of the message as plain text.
|
* @brief The display text of the message as plain text.
|
||||||
*/
|
*/
|
||||||
required property string plainText
|
required property string plainText
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The date of the event as a string.
|
* @brief The date of the event as a string.
|
||||||
*/
|
*/
|
||||||
required property string section
|
required property string section
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the section header should be shown.
|
* @brief Whether the section header should be shown.
|
||||||
*/
|
*/
|
||||||
required property bool showSection
|
required property bool showSection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A model with the reactions to the message in.
|
* @brief A model with the reactions to the message in.
|
||||||
*/
|
*/
|
||||||
required property var reaction
|
required property var reaction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the reaction component should be shown.
|
* @brief Whether the reaction component should be shown.
|
||||||
*/
|
*/
|
||||||
required property bool showReactions
|
required property bool showReactions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A model with the first 5 other user read markers for this message.
|
* @brief A model with the first 5 other user read markers for this message.
|
||||||
*/
|
*/
|
||||||
required property var readMarkers
|
required property var readMarkers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief String with the display name and matrix ID of the other user read markers.
|
* @brief String with the display name and matrix ID of the other user read markers.
|
||||||
*/
|
*/
|
||||||
required property string readMarkersString
|
required property string readMarkersString
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The number of other users at the event after the first 5.
|
* @brief The number of other users at the event after the first 5.
|
||||||
*/
|
*/
|
||||||
required property var excessReadMarkers
|
required property var excessReadMarkers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the other user read marker component should be shown.
|
* @brief Whether the other user read marker component should be shown.
|
||||||
*/
|
*/
|
||||||
required property bool showReadMarkers
|
required property bool showReadMarkers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The matrix ID of the reply event.
|
* @brief The matrix ID of the reply event.
|
||||||
*/
|
*/
|
||||||
required property var replyId
|
required property var replyId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The reply author.
|
* @brief The reply author.
|
||||||
*
|
*
|
||||||
* This should consist of the following:
|
* This should consist of the following:
|
||||||
* - id - The matrix ID of the reply author.
|
* - id - The matrix ID of the reply author.
|
||||||
* - isLocalUser - Whether the reply author is the local user.
|
* - isLocalUser - Whether the reply author is the local user.
|
||||||
* - avatarSource - The mxc URL for the reply author's avatar in the current room.
|
* - avatarSource - The mxc URL for the reply author's avatar in the current room.
|
||||||
* - avatarMediaId - The media ID of the reply author's avatar.
|
* - avatarMediaId - The media ID of the reply author's avatar.
|
||||||
* - avatarUrl - The mxc URL for the reply author's avatar.
|
* - avatarUrl - The mxc URL for the reply author's avatar.
|
||||||
* - displayName - The display name of the reply author.
|
* - displayName - The display name of the reply author.
|
||||||
* - display - The name of the reply author.
|
* - display - The name of the reply author.
|
||||||
* - color - The color for the reply author.
|
* - color - The color for the reply author.
|
||||||
* - object - The Quotient::User object for the reply author.
|
* - object - The Quotient::User object for the reply author.
|
||||||
*
|
*
|
||||||
* @sa Quotient::User
|
* @sa Quotient::User
|
||||||
*/
|
*/
|
||||||
required property var replyAuthor
|
required property var replyAuthor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The delegate type of the message replied to.
|
* @brief The delegate type of the message replied to.
|
||||||
*/
|
*/
|
||||||
required property int replyDelegateType
|
required property int replyDelegateType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The display text of the message replied to.
|
* @brief The display text of the message replied to.
|
||||||
*/
|
*/
|
||||||
required property string replyDisplay
|
required property string replyDisplay
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The media info for the reply event.
|
* @brief The media info for the reply event.
|
||||||
*
|
*
|
||||||
* This could be an image, audio, video or file.
|
* This could be an image, audio, video or file.
|
||||||
*
|
*
|
||||||
* This should consist of the following:
|
* This should consist of the following:
|
||||||
* - source - The mxc URL for the media.
|
* - source - The mxc URL for the media.
|
||||||
* - mimeType - The MIME type of the media.
|
* - mimeType - The MIME type of the media.
|
||||||
* - mimeIcon - The MIME icon name.
|
* - mimeIcon - The MIME icon name.
|
||||||
* - size - The file size in bytes.
|
* - size - The file size in bytes.
|
||||||
* - duration - The length in seconds of the audio media (audio/video only).
|
* - duration - The length in seconds of the audio media (audio/video only).
|
||||||
* - width - The width in pixels of the audio media (image/video only).
|
* - width - The width in pixels of the audio media (image/video only).
|
||||||
* - height - The height in pixels of the audio media (image/video only).
|
* - height - The height in pixels of the audio media (image/video only).
|
||||||
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads (image/video only).
|
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads (image/video only).
|
||||||
*/
|
*/
|
||||||
required property var replyMediaInfo
|
required property var replyMediaInfo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether this message is replying to another.
|
* @brief Whether this message is replying to another.
|
||||||
*/
|
*/
|
||||||
required property bool isReply
|
required property bool isReply
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether this message has a local user mention.
|
* @brief Whether this message has a local user mention.
|
||||||
*/
|
*/
|
||||||
required property bool isHighlighted
|
required property bool isHighlighted
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether an event is waiting to be accepted by the server.
|
* @brief Whether an event is waiting to be accepted by the server.
|
||||||
*/
|
*/
|
||||||
required property bool isPending
|
required property bool isPending
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Progress info when downloading files.
|
* @brief Progress info when downloading files.
|
||||||
*
|
*
|
||||||
* @sa Quotient::FileTransferInfo
|
* @sa Quotient::FileTransferInfo
|
||||||
*/
|
*/
|
||||||
required property var progressInfo
|
required property var progressInfo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether an encrypted message is sent in a verified session.
|
* @brief Whether an encrypted message is sent in a verified session.
|
||||||
*/
|
*/
|
||||||
required property bool verified
|
required property bool verified
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The x position of the message bubble.
|
* @brief The x position of the message bubble.
|
||||||
*
|
*
|
||||||
* @note Used for positioning the hover actions.
|
* @note Used for positioning the hover actions.
|
||||||
*/
|
*/
|
||||||
readonly property real bubbleX: bubble.x + bubble.anchors.leftMargin
|
readonly property real bubbleX: bubble.x + bubble.anchors.leftMargin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The y position of the message bubble.
|
* @brief The y position of the message bubble.
|
||||||
*
|
*
|
||||||
* @note Used for positioning the hover actions.
|
* @note Used for positioning the hover actions.
|
||||||
*/
|
*/
|
||||||
readonly property alias bubbleY: mainContainer.y
|
readonly property alias bubbleY: mainContainer.y
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The width of the message bubble.
|
* @brief The width of the message bubble.
|
||||||
*
|
*
|
||||||
* @note Used for sizing the hover actions.
|
* @note Used for sizing the hover actions.
|
||||||
*/
|
*/
|
||||||
readonly property alias bubbleWidth: bubble.width
|
readonly property alias bubbleWidth: bubble.width
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether this message is hovered.
|
* @brief Whether this message is hovered.
|
||||||
*/
|
*/
|
||||||
readonly property alias hovered: bubble.hovered
|
readonly property alias hovered: bubble.hovered
|
||||||
|
|
||||||
required property NeoChatConnection connection
|
required property NeoChatConnection connection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Open the context menu for the message.
|
* @brief Open the context menu for the message.
|
||||||
*/
|
*/
|
||||||
signal openContextMenu
|
signal openContextMenu
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Open the any message media externally.
|
* @brief Open the any message media externally.
|
||||||
*/
|
*/
|
||||||
signal openExternally()
|
signal openExternally()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The reply has been clicked.
|
* @brief The reply has been clicked.
|
||||||
*/
|
*/
|
||||||
signal replyClicked(string eventID)
|
signal replyClicked(string eventID)
|
||||||
|
|
||||||
onReplyClicked: eventID => ListView.view.goToEvent(eventID)
|
onReplyClicked: eventID => ListView.view.goToEvent(eventID)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The component to display the delegate type.
|
* @brief The main delegate content item to show in the bubble.
|
||||||
*
|
*/
|
||||||
* This is used by the inherited delegates to assign a component to visualise
|
property alias bubbleContent: bubble.content
|
||||||
* the message content for that delegate type.
|
|
||||||
*/
|
|
||||||
default property alias innerObject : column.children
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the bubble background is enabled.
|
* @brief Whether the bubble background is enabled.
|
||||||
*/
|
*/
|
||||||
property bool cardBackground: true
|
property bool cardBackground: true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the delegate should always stretch to the maximum availabel width.
|
* @brief Whether the delegate should always stretch to the maximum availabel width.
|
||||||
*/
|
*/
|
||||||
property bool alwaysMaxWidth: false
|
property bool alwaysMaxWidth: false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether local user messages should be aligned right.
|
* @brief Whether the message should be highlighted.
|
||||||
*
|
*/
|
||||||
* TODO: make private
|
|
||||||
*/
|
|
||||||
property bool showUserMessageOnRight: Config.showLocalMessagesOnRight && root.author.isLocalUser && !Config.compactLayout && !alwaysMaxWidth
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Whether the message should be highlighted.
|
|
||||||
*/
|
|
||||||
property bool showHighlight: root.isHighlighted || isTemporaryHighlighted
|
property bool showHighlight: root.isHighlighted || isTemporaryHighlighted
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the message should temporarily be highlighted.
|
* @brief Whether the message should temporarily be highlighted.
|
||||||
*
|
*
|
||||||
* Normally triggered when jumping to the event in the timeline, e.g. when a reply
|
* Normally triggered when jumping to the event in the timeline, e.g. when a reply
|
||||||
* is clicked.
|
* is clicked.
|
||||||
*/
|
*/
|
||||||
property bool isTemporaryHighlighted: false
|
property bool isTemporaryHighlighted: false
|
||||||
|
|
||||||
onIsTemporaryHighlightedChanged: if (isTemporaryHighlighted) temporaryHighlightTimer.start()
|
onIsTemporaryHighlightedChanged: if (isTemporaryHighlighted) temporaryHighlightTimer.start()
|
||||||
@@ -308,7 +297,7 @@ TimelineDelegate {
|
|||||||
/**
|
/**
|
||||||
* @brief The width available to the bubble content.
|
* @brief The width available to the bubble content.
|
||||||
*/
|
*/
|
||||||
property alias contentMaxWidth: bubbleSizeHelper.currentWidth
|
property real contentMaxWidth: bubbleSizeHelper.currentWidth - bubble.leftPadding - bubble.rightPadding
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
@@ -356,7 +345,7 @@ TimelineDelegate {
|
|||||||
|
|
||||||
visible: (root.showAuthor || root.alwaysShowAuthor) &&
|
visible: (root.showAuthor || root.alwaysShowAuthor) &&
|
||||||
Config.showAvatarInTimeline &&
|
Config.showAvatarInTimeline &&
|
||||||
(Config.compactLayout || !showUserMessageOnRight)
|
(Config.compactLayout || !_private.showUserMessageOnRight)
|
||||||
name: root.author.displayName
|
name: root.author.displayName
|
||||||
source: root.author.avatarSource
|
source: root.author.avatarSource
|
||||||
color: root.author.color
|
color: root.author.color
|
||||||
@@ -369,24 +358,19 @@ TimelineDelegate {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Bubble {
|
||||||
QQC2.Control {
|
|
||||||
id: bubble
|
id: bubble
|
||||||
|
anchors.left: avatar.right
|
||||||
|
anchors.leftMargin: Kirigami.Units.largeSpacing
|
||||||
|
anchors.rightMargin: Kirigami.Units.largeSpacing
|
||||||
|
maxContentWidth: root.contentMaxWidth
|
||||||
|
|
||||||
topPadding: Config.compactLayout ? Kirigami.Units.smallSpacing / 2 : Kirigami.Units.largeSpacing
|
topPadding: Config.compactLayout ? Kirigami.Units.smallSpacing / 2 : Kirigami.Units.largeSpacing
|
||||||
bottomPadding: Config.compactLayout ? Kirigami.Units.mediumSpacing / 2 : Kirigami.Units.largeSpacing
|
bottomPadding: Config.compactLayout ? Kirigami.Units.mediumSpacing / 2 : Kirigami.Units.largeSpacing
|
||||||
leftPadding: Config.compactLayout ? 0 : Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
leftPadding: Config.compactLayout ? 0 : Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||||
rightPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
rightPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
anchors {
|
state: _private.showUserMessageOnRight ? "userMessageOnRight" : "userMessageOnLeft"
|
||||||
left: avatar.right
|
|
||||||
leftMargin: Kirigami.Units.largeSpacing
|
|
||||||
rightMargin: Kirigami.Units.largeSpacing
|
|
||||||
}
|
|
||||||
// HACK: anchoring didn't reset anchors.right when switching from parent.right to undefined reliably
|
|
||||||
width: Config.compactLayout || root.alwaysMaxWidth ? mainContainer.width - (Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 : 0) + Kirigami.Units.largeSpacing * 2 : implicitWidth
|
|
||||||
|
|
||||||
state: showUserMessageOnRight ? "userMessageOnRight" : "userMessageOnLeft"
|
|
||||||
// states for anchor animations on window resize
|
// states for anchor animations on window resize
|
||||||
// as setting anchors to undefined did not work reliably
|
// as setting anchors to undefined did not work reliably
|
||||||
states: [
|
states: [
|
||||||
@@ -408,119 +392,22 @@ TimelineDelegate {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
transitions: [
|
author: root.author
|
||||||
Transition {
|
time: root.time
|
||||||
AnchorAnimation{duration: Kirigami.Units.longDuration; easing.type: Easing.OutCubic}
|
timeString: root.timeString
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
contentItem: RowLayout {
|
showHighlight: root.showHighlight
|
||||||
Kirigami.Icon {
|
|
||||||
source: "content-loading-symbolic"
|
|
||||||
width: height
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
|
||||||
visible: root.isPending && Config.showLocalMessagesOnRight
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
|
||||||
id: column
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
RowLayout {
|
|
||||||
id: rowLayout
|
|
||||||
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
isReply: root.isReply
|
||||||
visible: root.showAuthor || root.alwaysShowAuthor
|
replyId: root.replyId
|
||||||
|
replyAuthor: root.replyAuthor
|
||||||
|
replyDelegateType: root.replyDelegateType
|
||||||
|
replyDisplay: root.replyDisplay
|
||||||
|
replyMediaInfo: root.replyMediaInfo
|
||||||
|
|
||||||
QQC2.Label {
|
onReplyClicked: (eventId) => {root.replyClicked(eventId)}
|
||||||
id: nameLabel
|
|
||||||
|
|
||||||
Layout.maximumWidth: contentMaxWidth - timeLabel.implicitWidth - rowLayout.spacing
|
showBackground: root.cardBackground && !Config.compactLayout
|
||||||
|
|
||||||
text: visible ? root.author.displayName : ""
|
|
||||||
textFormat: Text.PlainText
|
|
||||||
font.weight: Font.Bold
|
|
||||||
color: root.author.color
|
|
||||||
elide: Text.ElideRight
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
RoomManager.visitUser(root.author.object, "mention")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QQC2.Label {
|
|
||||||
id: timeLabel
|
|
||||||
|
|
||||||
text: root.timeString
|
|
||||||
color: Kirigami.Theme.disabledTextColor
|
|
||||||
QQC2.ToolTip.visible: hoverHandler.hovered
|
|
||||||
QQC2.ToolTip.text: root.time.toLocaleString(Qt.locale(), Locale.LongFormat)
|
|
||||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
id: hoverHandler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loader {
|
|
||||||
id: replyLoader
|
|
||||||
|
|
||||||
Layout.maximumWidth: contentMaxWidth
|
|
||||||
|
|
||||||
active: root.isReply && root.replyDelegateType !== DelegateType.Other
|
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: ReplyComponent {
|
|
||||||
author: root.replyAuthor
|
|
||||||
type: root.replyDelegateType
|
|
||||||
display: root.replyDisplay
|
|
||||||
mediaInfo: root.replyMediaInfo
|
|
||||||
contentMaxWidth: bubbleSizeHelper.currentWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: replyLoader.item
|
|
||||||
function onReplyClicked() {
|
|
||||||
replyClicked(root.replyId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kirigami.Icon {
|
|
||||||
source: "content-loading-symbolic"
|
|
||||||
width: height
|
|
||||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
|
||||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
|
||||||
visible: root.isPending && !Config.showLocalMessagesOnRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Item {
|
|
||||||
Kirigami.ShadowedRectangle {
|
|
||||||
id: bubbleBackground
|
|
||||||
visible: cardBackground && !Config.compactLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
||||||
Kirigami.Theme.inherit: false
|
|
||||||
color: if (root.author.isLocalUser) {
|
|
||||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
|
|
||||||
} else if (root.showHighlight) {
|
|
||||||
return Kirigami.Theme.positiveBackgroundColor
|
|
||||||
} else {
|
|
||||||
return Kirigami.Theme.backgroundColor
|
|
||||||
}
|
|
||||||
radius: Kirigami.Units.smallSpacing
|
|
||||||
shadow {
|
|
||||||
size: Kirigami.Units.smallSpacing
|
|
||||||
color: root.isHighlighted ? Qt.rgba(0.0, 0.0, 0.0, 0.10) : Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.10)
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation { duration: Kirigami.Units.shortDuration }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
@@ -542,9 +429,9 @@ TimelineDelegate {
|
|||||||
|
|
||||||
ReactionDelegate {
|
ReactionDelegate {
|
||||||
Layout.maximumWidth: root.width - Kirigami.Units.largeSpacing * 2
|
Layout.maximumWidth: root.width - Kirigami.Units.largeSpacing * 2
|
||||||
Layout.alignment: showUserMessageOnRight ? Qt.AlignRight : Qt.AlignLeft
|
Layout.alignment: _private.showUserMessageOnRight ? Qt.AlignRight : Qt.AlignLeft
|
||||||
Layout.leftMargin: showUserMessageOnRight ? 0 : bubble.x + bubble.anchors.leftMargin
|
Layout.leftMargin: _private.showUserMessageOnRight ? 0 : bubble.x + bubble.anchors.leftMargin
|
||||||
Layout.rightMargin: showUserMessageOnRight ? Kirigami.Units.largeSpacing : 0
|
Layout.rightMargin: _private.showUserMessageOnRight ? Kirigami.Units.largeSpacing : 0
|
||||||
|
|
||||||
visible: root.showReactions
|
visible: root.showReactions
|
||||||
model: root.reaction
|
model: root.reaction
|
||||||
@@ -581,4 +468,13 @@ TimelineDelegate {
|
|||||||
ListView.view.setHoverActionsToDelegate(root)
|
ListView.view.setHoverActionsToDelegate(root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: _private
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether local user messages should be aligned right.
|
||||||
|
*/
|
||||||
|
property bool showUserMessageOnRight: Config.showLocalMessagesOnRight && root.author.isLocalUser && !Config.compactLayout && !root.alwaysMaxWidth
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ MessageDelegate {
|
|||||||
*/
|
*/
|
||||||
property var pollHandler: currentRoom.poll(root.eventId)
|
property var pollHandler: currentRoom.poll(root.eventId)
|
||||||
|
|
||||||
innerObject: ColumnLayout {
|
bubbleContent: ColumnLayout {
|
||||||
Label {
|
Label {
|
||||||
id: questionLabel
|
id: questionLabel
|
||||||
text: root.content["org.matrix.msc3381.poll.start"]["question"]["body"]
|
text: root.content["org.matrix.msc3381.poll.start"]["question"]["body"]
|
||||||
@@ -37,7 +37,6 @@ MessageDelegate {
|
|||||||
Repeater {
|
Repeater {
|
||||||
model: root.content["org.matrix.msc3381.poll.start"]["answers"]
|
model: root.content["org.matrix.msc3381.poll.start"]["answers"]
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
width: root.innerObject.width
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
checked: root.pollHandler.answers[currentRoom.localUser.id] ? root.pollHandler.answers[currentRoom.localUser.id].includes(modelData["id"]) : false
|
checked: root.pollHandler.answers[currentRoom.localUser.id] ? root.pollHandler.answers[currentRoom.localUser.id].includes(modelData["id"]) : false
|
||||||
onClicked: root.pollHandler.sendPollAnswer(root.eventId, modelData["id"])
|
onClicked: root.pollHandler.sendPollAnswer(root.eventId, modelData["id"])
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ Item {
|
|||||||
*/
|
*/
|
||||||
required property var mediaInfo
|
required property var mediaInfo
|
||||||
|
|
||||||
required property real contentMaxWidth
|
property real contentMaxWidth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The reply has been clicked.
|
* @brief The reply has been clicked.
|
||||||
@@ -79,8 +79,8 @@ Item {
|
|||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
id: mainLayout
|
id: mainLayout
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
implicitHeight: Math.max(replyAvatar.implicitHeight, replyName.implicitHeight) + loader.implicitHeight
|
||||||
|
|
||||||
rows: 2
|
rows: 2
|
||||||
columns: 3
|
columns: 3
|
||||||
@@ -107,6 +107,7 @@ Item {
|
|||||||
color: root.author.color
|
color: root.author.color
|
||||||
}
|
}
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
|
id: replyName
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
color: root.author.color
|
color: root.author.color
|
||||||
@@ -117,7 +118,7 @@ Item {
|
|||||||
id: loader
|
id: loader
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.maximumHeight: loader.item && (root.type == DelegateType.Image || root.type == DelegateType.Sticker) ? loader.item.height : -1
|
Layout.maximumHeight: loader.item && (root.type == DelegateType.Image || root.type == DelegateType.Sticker) ? loader.item.height : loader.item.implicitHeight
|
||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
|
|
||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
@@ -152,7 +153,6 @@ Item {
|
|||||||
id: textComponent
|
id: textComponent
|
||||||
RichLabel {
|
RichLabel {
|
||||||
textMessage: root.display
|
textMessage: root.display
|
||||||
textFormat: Text.RichText
|
|
||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
enabled: !hoveredLink
|
enabled: !hoveredLink
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ MessageDelegate {
|
|||||||
|
|
||||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, display, label.selectedText)
|
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, display, label.selectedText)
|
||||||
|
|
||||||
innerObject: ColumnLayout {
|
bubbleContent: ColumnLayout {
|
||||||
Layout.maximumWidth: root.contentMaxWidth
|
|
||||||
RichLabel {
|
RichLabel {
|
||||||
id: label
|
id: label
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ MessageDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
innerObject: Video {
|
bubbleContent: Video {
|
||||||
id: vid
|
id: vid
|
||||||
Layout.preferredWidth: mediaSizeHelper.currentSize.width
|
implicitWidth: mediaSizeHelper.currentSize.width
|
||||||
Layout.preferredHeight: mediaSizeHelper.currentSize.height
|
implicitHeight: mediaSizeHelper.currentSize.height
|
||||||
|
|
||||||
fillMode: VideoOutput.PreserveAspectFit
|
fillMode: VideoOutput.PreserveAspectFit
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,7 @@ QQC2.ScrollView {
|
|||||||
// This is because itemAt returns null in the spaces.
|
// This is because itemAt returns null in the spaces.
|
||||||
// All spacing should be handled by the delegates themselves
|
// All spacing should be handled by the delegates themselves
|
||||||
spacing: 0
|
spacing: 0
|
||||||
// Ensures that the top item is not covered by sectionBanner if the page is scrolled all the way up
|
|
||||||
// topMargin: sectionBanner.height
|
|
||||||
verticalLayoutDirection: ListView.BottomToTop
|
verticalLayoutDirection: ListView.BottomToTop
|
||||||
highlightMoveDuration: 500
|
|
||||||
clip: true
|
clip: true
|
||||||
interactive: Kirigami.Settings.isMobile
|
interactive: Kirigami.Settings.isMobile
|
||||||
bottomMargin: Kirigami.Units.largeSpacing + Math.round(Kirigami.Theme.defaultFont.pointSize * 2)
|
bottomMargin: Kirigami.Units.largeSpacing + Math.round(Kirigami.Theme.defaultFont.pointSize * 2)
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
<file alias="StateDelegate.qml">qml/Component/Timeline/StateDelegate.qml</file>
|
<file alias="StateDelegate.qml">qml/Component/Timeline/StateDelegate.qml</file>
|
||||||
<file alias="RichLabel.qml">qml/Component/Timeline/RichLabel.qml</file>
|
<file alias="RichLabel.qml">qml/Component/Timeline/RichLabel.qml</file>
|
||||||
<file alias="MessageDelegate.qml">qml/Component/Timeline/MessageDelegate.qml</file>
|
<file alias="MessageDelegate.qml">qml/Component/Timeline/MessageDelegate.qml</file>
|
||||||
|
<file alias="Bubble.qml">qml/Component/Timeline/Bubble.qml</file>
|
||||||
<file alias="SectionDelegate.qml">qml/Component/Timeline/SectionDelegate.qml</file>
|
<file alias="SectionDelegate.qml">qml/Component/Timeline/SectionDelegate.qml</file>
|
||||||
<file alias="VideoDelegate.qml">qml/Component/Timeline/VideoDelegate.qml</file>
|
<file alias="VideoDelegate.qml">qml/Component/Timeline/VideoDelegate.qml</file>
|
||||||
<file alias="ReactionDelegate.qml">qml/Component/Timeline/ReactionDelegate.qml</file>
|
<file alias="ReactionDelegate.qml">qml/Component/Timeline/ReactionDelegate.qml</file>
|
||||||
|
|||||||
Reference in New Issue
Block a user