Warning, /network/neochat/src/qml/Bubble.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0003
0004 import QtQuick
0005 import QtQuick.Controls as QQC2
0006 import QtQuick.Layouts
0007
0008 import org.kde.kirigami as Kirigami
0009
0010 import org.kde.neochat
0011
0012 /**
0013 * @brief A chat bubble for displaying the content of message events.
0014 *
0015 * The content of the bubble is set via the content property which is then managed
0016 * by the bubble to apply the correct sizing (including limiting the width if a
0017 * maxContentWidth is set).
0018 *
0019 * The bubble also supports a header with the author and message timestamp and a
0020 * reply.
0021 */
0022 QQC2.Control {
0023 id: root
0024
0025 /**
0026 * @brief The message author.
0027 *
0028 * This should consist of the following:
0029 * - id - The matrix ID of the author.
0030 * - isLocalUser - Whether the author is the local user.
0031 * - avatarSource - The mxc URL for the author's avatar in the current room.
0032 * - avatarMediaId - The media ID of the author's avatar.
0033 * - avatarUrl - The mxc URL for the author's avatar.
0034 * - displayName - The display name of the author.
0035 * - display - The name of the author.
0036 * - color - The color for the author.
0037 * - object - The Quotient::User object for the author.
0038 *
0039 * @sa Quotient::User
0040 */
0041 property var author
0042
0043 /**
0044 * @brief Whether the author should be shown.
0045 */
0046 required property bool showAuthor
0047
0048 /**
0049 * @brief The timestamp of the message.
0050 */
0051 property var time
0052
0053 /**
0054 * @brief The timestamp of the message as a string.
0055 */
0056 property string timeString
0057
0058 /**
0059 * @brief Whether the message should be highlighted.
0060 */
0061 property bool showHighlight: false
0062
0063 /**
0064 * @brief The main delegate content item to show in the bubble.
0065 */
0066 property Item content
0067
0068 /**
0069 * @brief Whether this message is replying to another.
0070 */
0071 property bool isReply: false
0072
0073 /**
0074 * @brief The matrix ID of the reply event.
0075 */
0076 required property var replyId
0077
0078 /**
0079 * @brief The reply author.
0080 *
0081 * This should consist of the following:
0082 * - id - The matrix ID of the reply author.
0083 * - isLocalUser - Whether the reply author is the local user.
0084 * - avatarSource - The mxc URL for the reply author's avatar in the current room.
0085 * - avatarMediaId - The media ID of the reply author's avatar.
0086 * - avatarUrl - The mxc URL for the reply author's avatar.
0087 * - displayName - The display name of the reply author.
0088 * - display - The name of the reply author.
0089 * - color - The color for the reply author.
0090 * - object - The Quotient::User object for the reply author.
0091 *
0092 * @sa Quotient::User
0093 */
0094 required property var replyAuthor
0095
0096 /**
0097 * @brief The delegate type of the message replied to.
0098 */
0099 required property int replyDelegateType
0100
0101 /**
0102 * @brief The display text of the message replied to.
0103 */
0104 required property string replyDisplay
0105
0106 /**
0107 * @brief The media info for the reply event.
0108 *
0109 * This could be an image, audio, video or file.
0110 *
0111 * This should consist of the following:
0112 * - source - The mxc URL for the media.
0113 * - mimeType - The MIME type of the media.
0114 * - mimeIcon - The MIME icon name.
0115 * - size - The file size in bytes.
0116 * - duration - The length in seconds of the audio media (audio/video only).
0117 * - width - The width in pixels of the audio media (image/video only).
0118 * - height - The height in pixels of the audio media (image/video only).
0119 * - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads (image/video only).
0120 */
0121 required property var replyMediaInfo
0122
0123 /**
0124 * @brief Whether the bubble background should be shown.
0125 */
0126 property alias showBackground: bubbleBackground.visible
0127
0128 /**
0129 * @brief The maximum width that the bubble's content can be.
0130 */
0131 property real maxContentWidth: -1
0132
0133 /**
0134 * @brief The reply has been clicked.
0135 */
0136 signal replyClicked(string eventID)
0137
0138 contentItem: ColumnLayout {
0139 RowLayout {
0140 Layout.maximumWidth: root.maxContentWidth
0141 visible: root.showAuthor
0142 QQC2.AbstractButton {
0143 Layout.fillWidth: true
0144 contentItem: QQC2.Label {
0145 text: root.author.displayName
0146 color: root.author.color
0147 textFormat: Text.PlainText
0148 font.weight: Font.Bold
0149 elide: Text.ElideRight
0150 }
0151 Accessible.name: contentItem.text
0152 onClicked: RoomManager.resolveResource(root.author.id, "mention")
0153 }
0154 QQC2.Label {
0155 text: root.timeString
0156 horizontalAlignment: Text.AlignRight
0157 color: Kirigami.Theme.disabledTextColor
0158 QQC2.ToolTip.visible: timeHoverHandler.hovered
0159 QQC2.ToolTip.text: root.time.toLocaleString(Qt.locale(), Locale.LongFormat)
0160 QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
0161
0162 HoverHandler {
0163 id: timeHoverHandler
0164 }
0165 }
0166 }
0167 Loader {
0168 id: replyLoader
0169 Layout.fillWidth: true
0170 Layout.maximumWidth: root.maxContentWidth
0171
0172 active: root.isReply && root.replyDelegateType !== DelegateType.Other
0173 visible: active
0174
0175 sourceComponent: ReplyComponent {
0176 author: root.replyAuthor
0177 type: root.replyDelegateType
0178 display: root.replyDisplay
0179 mediaInfo: root.replyMediaInfo
0180 contentMaxWidth: root.maxContentWidth
0181 }
0182
0183 Connections {
0184 target: replyLoader.item
0185 function onReplyClicked() {
0186 replyClicked(root.replyId);
0187 }
0188 }
0189 }
0190 Item {
0191 id: contentParent
0192 Layout.fillWidth: true
0193 Layout.maximumWidth: root.maxContentWidth
0194 implicitWidth: root.content ? root.content.implicitWidth : 0
0195 implicitHeight: root.content ? root.content.implicitHeight : 0
0196 }
0197 }
0198
0199 background: Kirigami.ShadowedRectangle {
0200 id: bubbleBackground
0201 visible: root.showBackground
0202 Kirigami.Theme.colorSet: Kirigami.Theme.View
0203 Kirigami.Theme.inherit: false
0204 color: if (root.author.isLocalUser) {
0205 return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15);
0206 } else if (root.showHighlight) {
0207 return Kirigami.Theme.positiveBackgroundColor;
0208 } else {
0209 return Kirigami.Theme.backgroundColor;
0210 }
0211 radius: Kirigami.Units.smallSpacing
0212 shadow {
0213 size: Kirigami.Units.smallSpacing
0214 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)
0215 }
0216
0217 Behavior on color {
0218 ColorAnimation {
0219 duration: Kirigami.Units.shortDuration
0220 }
0221 }
0222 }
0223
0224 onContentChanged: {
0225 if (!root.content) {
0226 return;
0227 }
0228 root.content.parent = contentParent;
0229 root.content.anchors.fill = contentParent;
0230 }
0231 }