// SPDX-FileCopyrightText: Nheko Contributors // // SPDX-License-Identifier: GPL-3.0-or-later import QtQuick import QtQuick.Controls import QtQuick.Window import im.nheko import "./components" Column { required property var day required property bool isSender required property bool isStateEvent required property int parentWidth required property var previousMessageDay required property bool previousMessageIsStateEvent required property string previousMessageUserId required property date timestamp required property string userId required property string userName required property string userPowerlevel bottomPadding: Settings.bubbles ? (isSender && previousMessageDay == day ? 0 : 2) : 3 spacing: 8 topPadding: userName_.visible ? 4 : 0 visible: (previousMessageUserId !== userId || previousMessageDay !== day || isStateEvent !== previousMessageIsStateEvent) width: parentWidth Label { id: dateBubble anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined color: palette.text height: Math.round(fontMetrics.height * 1.4) horizontalAlignment: Text.AlignHCenter text: room ? room.formatDateSeparator(timestamp) : "" verticalAlignment: Text.AlignVCenter visible: room && previousMessageDay !== day width: contentWidth * 1.2 background: Rectangle { color: palette.window radius: parent.height / 2 } } Row { id: userInfo property int remainingWidth: chat.delegateMaxWidth - spacing - messageUserAvatar.width height: userName_.height spacing: 8 visible: !isStateEvent && (!isSender || !Settings.bubbles) Avatar { id: messageUserAvatar ToolTip.delay: Nheko.tooltipDelay ToolTip.text: userid ToolTip.visible: messageUserAvatar.hovered displayName: userName height: Nheko.avatarSize * (Settings.smallAvatars ? 0.5 : 1) url: !room ? "" : room.avatarUrl(userId).replace("mxc://", "image://MxcImage/") userid: userId width: Nheko.avatarSize * (Settings.smallAvatars ? 0.5 : 1) onClicked: room.openUserProfile(userId) } Connections { function onRoomAvatarUrlChanged() { messageUserAvatar.url = room.avatarUrl(userId).replace("mxc://", "image://MxcImage/"); } function onScrollToIndex(index) { chat.positionViewAtIndex(index, ListView.Center); } target: room } AbstractButton { id: userNameButton ToolTip.delay: Nheko.tooltipDelay ToolTip.text: userId ToolTip.visible: hovered leftInset: 0 leftPadding: powerlevelIndicator.visible ? 16 : 0 rightInset: 0 rightPadding: 0 contentItem: Label { id: userName_ color: TimelineManager.userColor(userId, palette.base) text: TimelineManager.escapeEmoji(userNameTextMetrics.elidedText) textFormat: Text.RichText } onClicked: room.openUserProfile(userId) PowerlevelIndicator { id: powerlevelIndicator anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter height: fontMetrics.ascent permissions: room ? room.permissions : null powerlevel: userPowerlevel sourceSize.height: fontMetrics.lineSpacing sourceSize.width: fontMetrics.lineSpacing visible: isAdmin || isModerator width: height } TextMetrics { id: userNameTextMetrics elide: Text.ElideRight elideWidth: userInfo.remainingWidth - Math.min(statusMsg.implicitWidth, userInfo.remainingWidth / 3) text: userName } NhekoCursorShape { anchors.fill: parent cursorShape: Qt.PointingHandCursor } } Label { id: statusMsg property string userStatus: Presence.userStatus(userId) ToolTip.delay: Nheko.tooltipDelay ToolTip.text: qsTr("%1's status message").arg(userName) ToolTip.visible: statusMsgHoverHandler.hovered anchors.baseline: userNameButton.baseline color: palette.buttonText elide: Text.ElideRight font.italic: true font.pointSize: Math.floor(fontMetrics.font.pointSize * 0.8) text: userStatus.replace(/\n/g, " ") textFormat: Text.PlainText width: Math.min(implicitWidth, userInfo.remainingWidth - userName_.width - parent.spacing) HoverHandler { id: statusMsgHoverHandler } Connections { function onPresenceChanged(id) { if (id == userId) statusMsg.userStatus = Presence.userStatus(userId); } target: Presence } } } }