diff --git a/CMakeLists.txt b/CMakeLists.txt index 01070a82..548d5303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -713,6 +713,7 @@ set(QML_SOURCES resources/qml/UploadBox.qml resources/qml/MessageInput.qml resources/qml/MessageView.qml + resources/qml/TimelineEvent.qml resources/qml/PrivacyScreen.qml resources/qml/Reactions.qml resources/qml/ReplyPopup.qml diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 590d5bb8..9ebe0a40 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -145,7 +145,6 @@ Control { roleValue: "user" RowLayout { - anchors.centerIn: centerRowContent ? parent : undefined spacing: rowSpacing @@ -171,7 +170,6 @@ Control { roleValue: "emoji" RowLayout { - anchors.centerIn: parent spacing: rowSpacing @@ -207,7 +205,6 @@ Control { roleValue: "command" RowLayout { - anchors.centerIn: parent spacing: rowSpacing @@ -226,7 +223,6 @@ Control { roleValue: "room" RowLayout { - anchors.centerIn: centerRowContent ? parent : undefined spacing: rowSpacing @@ -251,7 +247,6 @@ Control { roleValue: "roomAliases" RowLayout { - anchors.centerIn: parent spacing: rowSpacing diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml index 0174e0f6..6f95c663 100644 --- a/resources/qml/ForwardCompleter.qml +++ b/resources/qml/ForwardCompleter.qml @@ -54,24 +54,8 @@ Popup { Reply { id: replyPreview - property var modelData: room ? room.getDump(mid, "") : {} - - blurhash: modelData.blurhash ?? "" - body: modelData.body ?? "" - encryptionError: modelData.encryptionError ?? "" - eventId: modelData.eventId ?? "" - filename: modelData.filename ?? "" - filesize: modelData.filesize ?? "" - formattedBody: modelData.formattedBody ?? "" - isOnlyEmoji: modelData.isOnlyEmoji ?? false - originalWidth: modelData.originalWidth ?? 0 - proportionalHeight: modelData.proportionalHeight ?? 1 - type: modelData.type ?? MtxEvent.UnknownMessage - typeString: modelData.typeString ?? "" - url: modelData.url ?? "" + eventId: mid userColor: TimelineManager.userColor(modelData.userId, palette.window) - userId: modelData.userId ?? "" - userName: modelData.userName ?? "" width: parent.width } MatrixTextField { diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index de15e078..bf953d56 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -11,25 +11,24 @@ TextArea { property alias cursorShape: cs.cursorShape - leftInset: 0 - bottomInset: 0 - rightInset: 0 - topInset: 0 - leftPadding: 0 - bottomPadding: 0 - rightPadding: 0 - topPadding: 0 - background: null - ToolTip.text: hoveredLink ToolTip.visible: hoveredLink || false + background: null + bottomInset: 0 + bottomPadding: 0 // this always has to be enabled, otherwise you can't click links anymore! //enabled: selectByMouse color: palette.text focus: false + leftInset: 0 + leftPadding: 0 readOnly: true + rightInset: 0 + rightPadding: 0 selectByMouse: !Settings.mobileMode textFormat: TextEdit.RichText + topInset: 0 + topPadding: 0 wrapMode: Text.Wrap // Setting a tooltip delay makes the hover text empty .-. @@ -40,8 +39,8 @@ TextArea { onLinkActivated: Nheko.openLink(link) // propagate events up - onPressAndHold: (event) => event.accepted = false - onPressed: (event) => event.accepted = (event.button == Qt.LeftButton) + onPressAndHold: event => event.accepted = false + onPressed: event => event.accepted = (event.button == Qt.LeftButton) NhekoCursorShape { id: cs diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml index 976312f2..2df9b731 100644 --- a/resources/qml/MessageView.qml +++ b/resources/qml/MessageView.qml @@ -59,7 +59,7 @@ Item { spacing: 2 verticalLayoutDirection: ListView.BottomToTop - delegate: EventDelegateChooser { + delegate: TimelineEvent { id: wrapper ListView.delayRemove: true width: chat.delegateMaxWidth @@ -69,7 +69,6 @@ Item { required property var day required property bool isSender - required property bool isStateEvent //required property var previousMessageDay //required property bool previousMessageIsStateEvent //required property string previousMessageUserId @@ -145,6 +144,8 @@ Item { } ColumnLayout { + spacing: 0 + AbstractButton { id: replyUserButton Layout.fillWidth: true @@ -222,314 +223,6 @@ Item { opacity: 0.2 } ] - - EventDelegateChoice { - roleValues: [ - MtxEvent.TextMessage, - MtxEvent.NoticeMessage, - MtxEvent.ElementEffectMessage, - MtxEvent.UnknownMessage, - ] - TextMessage { - keepFullText: true - required property string userId - required property string userName - required property string formattedBody - required property int type - - color: type == MtxEvent.NoticeMessage ? palette.buttonText : palette.text - font.italic: type == MtxEvent.NoticeMessage - formatted: formattedBody - - Layout.fillWidth: true - //Layout.maximumWidth: implicitWidth - - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.EmoteMessage, - ] - TextMessage { - keepFullText: true - required property string userId - required property string userName - required property string formattedBody - - formatted: TimelineManager.escapeEmoji(userName) + " " + formattedBody - - color: TimelineManager.userColor(userId, palette.base) - font.italic: true - - Layout.fillWidth: true - //Layout.maximumWidth: implicitWidth - - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.CanonicalAlias, - MtxEvent.ServerAcl, - MtxEvent.Name, - MtxEvent.Topic, - MtxEvent.Avatar, - MtxEvent.PinnedEvents, - MtxEvent.ImagePackInRoom, - MtxEvent.SpaceParent, - MtxEvent.RoomCreate, - MtxEvent.PowerLevels, - MtxEvent.PolicyRuleUser, - MtxEvent.PolicyRuleRoom, - MtxEvent.PolicyRuleServer, - MtxEvent.RoomJoinRules, - MtxEvent.RoomHistoryVisibility, - MtxEvent.RoomGuestAccess, - ] - TextMessage { - keepFullText: true - - required property string userId - required property string userName - required property string formattedStateEvent - - isOnlyEmoji: false - text: formattedStateEvent - formatted: '' - body: '' - horizontalAlignment: Text.AlignHCenter - - color: palette.buttonText - font.italic: true - - Layout.fillWidth: true - //Layout.maximumWidth: implicitWidth - - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.CallInvite, - ] - TextMessage { - keepFullText: true - - required property string userId - required property string userName - required property string callType - - isOnlyEmoji: false - body: formatted - formatted: { - switch (callType) { - case "voice": - return qsTr("%1 placed a voice call.").arg(TimelineManager.escapeEmoji(userName)); - case "video": - return qsTr("%1 placed a video call.").arg(TimelineManager.escapeEmoji(userName)); - default: - return qsTr("%1 placed a call.").arg(TimelineManager.escapeEmoji(userName)); - } - } - - color: palette.buttonText - font.italic: true - - Layout.fillWidth: true - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.CallAnswer, - MtxEvent.CallReject, - MtxEvent.CallSelectAnswer, - MtxEvent.CallHangUp, - MtxEvent.CallCandidates, - MtxEvent.CallNegotiate, - ] - TextMessage { - keepFullText: true - - required property string userId - required property string userName - required property int type - - isOnlyEmoji: false - body: formatted - formatted: { - switch (type) { - case MtxEvent.CallAnswer: - return qsTr("%1 answered the call.").arg(TimelineManager.escapeEmoji(userName)); - case MtxEvent.CallReject: - return qsTr("%1 rejected the call.").arg(TimelineManager.escapeEmoji(userName)); - case MtxEvent.CallSelectAnswer: - return qsTr("%1 selected answer.").arg(TimelineManager.escapeEmoji(userName)); - case MtxEvent.CallHangUp: - return qsTr("%1 ended the call.").arg(TimelineManager.escapeEmoji(userName)); - case MtxEvent.CallCandidates: - return qsTr("%1 is negotiating the call...").arg(TimelineManager.escapeEmoji(userName)); - case MtxEvent.CallNegotiate: - return qsTr("%1 is negotiating the call...").arg(TimelineManager.escapeEmoji(userName)); - } - } - - color: palette.buttonText - font.italic: true - - Layout.fillWidth: true - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.ImageMessage, - MtxEvent.Sticker, - ] - ImageMessage { - Layout.fillWidth: true - - containerHeight: timelineView.height - Layout.maximumWidth: tempWidth - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.FileMessage, - ] - FileMessage { - Layout.fillWidth: true - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.VideoMessage, - MtxEvent.AudioMessage, - ] - PlayableMediaMessage { - Layout.fillWidth: true - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.Encrypted, - ] - Encrypted { - Layout.fillWidth: true - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.Encryption, - ] - EncryptionEnabled { - Layout.fillWidth: true - } - } - - - EventDelegateChoice { - roleValues: [ - MtxEvent.Redacted - ] - - Redacted { - Layout.fillWidth: true - - required property string userId - required property string userName - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.Member - ] - - ColumnLayout { - id: member - - required property string userId - required property string userName - - required property bool isReply - required property Room room - required property string formattedStateEvent - - NoticeMessage { - body: formatted - isOnlyEmoji: false - isReply: tombstone.isReply - keepFullText: true - isStateEvent: true - Layout.fillWidth: true - formatted: member.formattedStateEvent - } - - Button { - visible: room.showAcceptKnockButton(eventId) - Layout.alignment: Qt.AlignHCenter - text: qsTr("Allow them in") - onClicked: room.acceptKnock(member.eventId) - } - - } - } - - EventDelegateChoice { - roleValues: [ - MtxEvent.Tombstone - ] - - ColumnLayout { - id: tombstone - - required property string userId - required property string userName - - required property string body - required property bool isReply - required property Room room - required property string eventId - - NoticeMessage { - body: formatted - isOnlyEmoji: false - isReply: tombstone.isReply - keepFullText: true - isStateEvent: true - Layout.fillWidth: true - formatted: qsTr("This room was replaced for the following reason: %1").arg(tombstone.body) - } - - Button { - Layout.alignment: Qt.AlignHCenter - text: qsTr("Go to replacement room") - onClicked: tombstone.room.joinReplacementRoom(tombstone.eventId) - } - - } - } - - EventDelegateChoice { - roleValues: [ - ] - MatrixText { - Layout.fillWidth: true - - required property string typeString - - text: "Unsupported: " + typeString - - required property string userId - required property string userName - } - } } footer: Item { anchors.horizontalCenter: parent.horizontalCenter diff --git a/resources/qml/Reactions.qml b/resources/qml/Reactions.qml index eff62fc1..5b994145 100644 --- a/resources/qml/Reactions.qml +++ b/resources/qml/Reactions.qml @@ -74,10 +74,10 @@ Flow { anchors.verticalCenter: divider.verticalCenter fillMode: Image.PreserveAspectFit height: textMetrics.height + mipmap: true source: modelData.key.startsWith("mxc://") ? (modelData.key.replace("mxc://", "image://MxcImage/") + "?scale") : "" visible: modelData.key.startsWith("mxc://") width: textMetrics.height - mipmap: true } Rectangle { id: divider diff --git a/resources/qml/ReplyPopup.qml b/resources/qml/ReplyPopup.qml index ce24297c..64c58e56 100644 --- a/resources/qml/ReplyPopup.qml +++ b/resources/qml/ReplyPopup.qml @@ -29,22 +29,8 @@ Rectangle { anchors.rightMargin: replyPopup.width < 450 ? 2 * (22 + 16) : 3 * (22 + 16) anchors.top: parent.top anchors.topMargin: Nheko.paddingSmall - blurhash: modelData.blurhash ?? "" - body: modelData.body ?? "" - encryptionError: modelData.encryptionError ?? 0 - eventId: modelData.eventId ?? "" - filename: modelData.filename ?? "" - filesize: modelData.filesize ?? "" - formattedBody: modelData.formattedBody ?? "" - isOnlyEmoji: modelData.isOnlyEmoji ?? false - originalWidth: modelData.originalWidth ?? 0 - proportionalHeight: modelData.proportionalHeight ?? 1 - type: modelData.type ?? MtxEvent.UnknownMessage - typeString: modelData.typeString ?? "" - url: modelData.url ?? "" + eventId: room.reply ?? "" userColor: TimelineManager.userColor(modelData.userId, palette.window) - userId: modelData.userId ?? "" - userName: modelData.userName ?? "" visible: room && room.reply width: parent.width } diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 20e5b95b..0c432189 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -728,9 +728,9 @@ Page { } Platform.MenuItem { text: qsTr("Mark as read") + onTriggered: Rooms.getRoomById(roomContextMenu.roomid).markRoomAsRead() } - Platform.MenuItem { text: qsTr("Room settings") diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml index 1e8a6a27..09a8f442 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml @@ -355,7 +355,6 @@ Pane { onAccepted: UIA.continue3pidReceived() } - Connections { function onConfirm3pidToken() { uiaConfirmationLinkDialog.open(); @@ -363,6 +362,18 @@ Pane { function onEmail() { uiaEmailPrompt.show(); } + function onFallbackAuth(fallback) { + var component = Qt.createComponent("qrc:/resources/qml/dialogs/FallbackAuthDialog.qml"); + if (component.status == Component.Ready) { + var dialog = component.createObject(timelineRoot, { + "fallback": fallback + }); + dialog.show(); + destroyOnClose(dialog); + } else { + console.error("Failed to create component: " + component.errorString()); + } + } function onPassword() { console.log("UIA: password needed"); uiaPassPrompt.show(); @@ -385,18 +396,6 @@ Pane { console.error("Failed to create component: " + component.errorString()); } } - function onFallbackAuth(fallback) { - var component = Qt.createComponent("qrc:/resources/qml/dialogs/FallbackAuthDialog.qml"); - if (component.status == Component.Ready) { - var dialog = component.createObject(timelineRoot, { - "fallback": fallback - }); - dialog.show(); - destroyOnClose(dialog); - } else { - console.error("Failed to create component: " + component.errorString()); - } - } target: UIA } diff --git a/resources/qml/TimelineEvent.qml b/resources/qml/TimelineEvent.qml new file mode 100644 index 00000000..787fb7dc --- /dev/null +++ b/resources/qml/TimelineEvent.qml @@ -0,0 +1,255 @@ +// SPDX-FileCopyrightText: Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import "./components" +import "./delegates" +import "./emoji" +import "./ui" +import "./dialogs" +import Qt.labs.platform 1.1 as Platform +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.13 +import im.nheko 1.0 + +EventDelegateChooser { + id: wrapper + + required property bool isStateEvent + + EventDelegateChoice { + roleValues: [MtxEvent.TextMessage, MtxEvent.NoticeMessage, MtxEvent.ElementEffectMessage, MtxEvent.UnknownMessage,] + + TextMessage { + required property string formattedBody + required property int type + required property string userId + required property string userName + + Layout.fillWidth: true + //Layout.maximumWidth: implicitWidth + + color: type == MtxEvent.NoticeMessage ? palette.buttonText : palette.text + font.italic: type == MtxEvent.NoticeMessage + formatted: formattedBody + keepFullText: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.EmoteMessage,] + + TextMessage { + required property string formattedBody + required property string userId + required property string userName + + Layout.fillWidth: true + //Layout.maximumWidth: implicitWidth + + color: TimelineManager.userColor(userId, palette.base) + font.italic: true + formatted: TimelineManager.escapeEmoji(userName) + " " + formattedBody + keepFullText: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.CanonicalAlias, MtxEvent.ServerAcl, MtxEvent.Name, MtxEvent.Topic, MtxEvent.Avatar, MtxEvent.PinnedEvents, MtxEvent.ImagePackInRoom, MtxEvent.SpaceParent, MtxEvent.RoomCreate, MtxEvent.PowerLevels, MtxEvent.PolicyRuleUser, MtxEvent.PolicyRuleRoom, MtxEvent.PolicyRuleServer, MtxEvent.RoomJoinRules, MtxEvent.RoomHistoryVisibility, MtxEvent.RoomGuestAccess,] + + TextMessage { + required property string formattedStateEvent + required property string userId + required property string userName + + Layout.fillWidth: true + //Layout.maximumWidth: implicitWidth + + body: '' + color: palette.buttonText + font.italic: true + formatted: '' + horizontalAlignment: Text.AlignHCenter + isOnlyEmoji: false + keepFullText: true + text: formattedStateEvent + } + } + EventDelegateChoice { + roleValues: [MtxEvent.CallInvite,] + + TextMessage { + required property string callType + required property string userId + required property string userName + + Layout.fillWidth: true + body: formatted + color: palette.buttonText + font.italic: true + formatted: { + switch (callType) { + case "voice": + return qsTr("%1 placed a voice call.").arg(TimelineManager.escapeEmoji(userName)); + case "video": + return qsTr("%1 placed a video call.").arg(TimelineManager.escapeEmoji(userName)); + default: + return qsTr("%1 placed a call.").arg(TimelineManager.escapeEmoji(userName)); + } + } + isOnlyEmoji: false + keepFullText: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.CallAnswer, MtxEvent.CallReject, MtxEvent.CallSelectAnswer, MtxEvent.CallHangUp, MtxEvent.CallCandidates, MtxEvent.CallNegotiate,] + + TextMessage { + required property int type + required property string userId + required property string userName + + Layout.fillWidth: true + body: formatted + color: palette.buttonText + font.italic: true + formatted: { + switch (type) { + case MtxEvent.CallAnswer: + return qsTr("%1 answered the call.").arg(TimelineManager.escapeEmoji(userName)); + case MtxEvent.CallReject: + return qsTr("%1 rejected the call.").arg(TimelineManager.escapeEmoji(userName)); + case MtxEvent.CallSelectAnswer: + return qsTr("%1 selected answer.").arg(TimelineManager.escapeEmoji(userName)); + case MtxEvent.CallHangUp: + return qsTr("%1 ended the call.").arg(TimelineManager.escapeEmoji(userName)); + case MtxEvent.CallCandidates: + return qsTr("%1 is negotiating the call...").arg(TimelineManager.escapeEmoji(userName)); + case MtxEvent.CallNegotiate: + return qsTr("%1 is negotiating the call...").arg(TimelineManager.escapeEmoji(userName)); + } + } + isOnlyEmoji: false + keepFullText: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.ImageMessage, MtxEvent.Sticker,] + + ImageMessage { + Layout.fillWidth: true + Layout.maximumWidth: tempWidth + containerHeight: timelineView.height + } + } + EventDelegateChoice { + roleValues: [MtxEvent.FileMessage,] + + FileMessage { + Layout.fillWidth: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.VideoMessage, MtxEvent.AudioMessage,] + + PlayableMediaMessage { + Layout.fillWidth: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.Encrypted,] + + Encrypted { + Layout.fillWidth: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.Encryption,] + + EncryptionEnabled { + Layout.fillWidth: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.Redacted] + + Redacted { + required property string userId + required property string userName + + Layout.fillWidth: true + } + } + EventDelegateChoice { + roleValues: [MtxEvent.Member] + + ColumnLayout { + id: member + + required property string formattedStateEvent + required property bool isReply + required property Room room + required property string userId + required property string userName + + NoticeMessage { + Layout.fillWidth: true + body: formatted + formatted: member.formattedStateEvent + isOnlyEmoji: false + isReply: member.isReply + isStateEvent: true + keepFullText: true + } + Button { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Allow them in") + visible: room.showAcceptKnockButton(eventId) + + onClicked: room.acceptKnock(member.eventId) + } + } + } + EventDelegateChoice { + roleValues: [MtxEvent.Tombstone] + + ColumnLayout { + id: tombstone + + required property string body + required property string eventId + required property bool isReply + required property Room room + required property string userId + required property string userName + + NoticeMessage { + Layout.fillWidth: true + body: formatted + formatted: qsTr("This room was replaced for the following reason: %1").arg(tombstone.body) + isOnlyEmoji: false + isReply: tombstone.isReply + isStateEvent: true + keepFullText: true + } + Button { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Go to replacement room") + + onClicked: tombstone.room.joinReplacementRoom(tombstone.eventId) + } + } + } + EventDelegateChoice { + roleValues: [] + + MatrixText { + required property string typeString + required property string userId + required property string userName + + Layout.fillWidth: true + text: "Unsupported: " + typeString + } + } +} diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index 64fa80b1..539882ed 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -147,7 +147,8 @@ AbstractButton { columns: Settings.bubbles ? 1 : 2 rowSpacing: 0 rows: Settings.bubbles ? 3 : 2 -/* + + /* anchors { left: parent.left leftMargin: 4 diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index 699595e6..4c70348b 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -286,24 +286,9 @@ Pane { property var e: room ? room.getDump(modelData, "pins") : {} Layout.fillWidth: true - Layout.preferredHeight: height - blurhash: e.blurhash ?? "" - body: e.body ?? "" - encryptionError: e.encryptionError ?? 0 + //Layout.preferredHeight: height eventId: e.eventId ?? "" - filename: e.filename ?? "" - filesize: e.filesize ?? "" - formattedBody: e.formattedBody ?? "" - isOnlyEmoji: e.isOnlyEmoji ?? false - keepFullText: true - originalWidth: e.originalWidth ?? 0 - proportionalHeight: e.proportionalHeight ?? 1 - type: e.type ?? MtxEvent.UnknownMessage - typeString: e.typeString ?? "" - url: e.url ?? "" userColor: TimelineManager.userColor(e.userId, palette.window) - userId: e.userId ?? "" - userName: e.userName ?? "" Connections { function onPinnedMessagesChanged() { diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml index 64eb65a3..55a376f7 100644 --- a/resources/qml/delegates/Reply.qml +++ b/resources/qml/delegates/Reply.qml @@ -14,102 +14,96 @@ AbstractButton { id: r property color userColor: "red" - property double proportionalHeight - property int type - property string typeString - property int originalWidth - property string blurhash - property string body - property string formattedBody - property string eventId - property string filename - property string filesize - property string url - property bool isOnlyEmoji - property bool isStateEvent - property string userId - property string userName - property string thumbnailUrl - property string roomTopic - property string roomName - property string callType - property int duration - property int encryptionError - property int relatedEventCacheBuster - property int maxWidth property bool keepFullText: false - height: replyContainer.height - implicitHeight: replyContainer.height - implicitWidth: visible? colorLine.width+Math.max(replyContainer.implicitWidth,userName_.fullTextWidth) : 0 // visible? seems to be causing issues + required property string eventId + + property var room_: room + + property string userId: eventId ? room.dataById(eventId, Room.UserId, "") : "" + property string userName: eventId ? room.dataById(eventId, Room.UserName, "") : "" + implicitHeight: replyContainer.implicitHeight + implicitWidth: replyContainer.implicitWidth NhekoCursorShape { anchors.fill: parent cursorShape: Qt.PointingHandCursor } - Rectangle { - id: colorLine - - anchors.top: replyContainer.top - anchors.bottom: replyContainer.bottom - width: 4 - color: TimelineManager.userColor(userId, palette.base) - } - onClicked: { - let link = reply.child.linkAt != undefined && reply.child.linkAt(pressX-colorLine.width, pressY - userName_.implicitHeight); + let link = reply.child.linkAt != undefined && reply.child.linkAt(pressX-colorline.width, pressY - userName_.implicitHeight); if (link) { Nheko.openLink(link) } else { room.showEvent(r.eventId) } } - onPressAndHold: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(pressX-colorLine.width, pressY - userName_.implicitHeight), r.eventId) + onPressAndHold: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(pressX-colorline.width, pressY - userName_.implicitHeight), r.eventId) - ColumnLayout { - id: replyContainer + contentItem: TimelineEvent { + id: timelineEvent - anchors.left: colorLine.right - width: parent.width - 4 - spacing: 0 + isStateEvent: false + room: room_ + eventId: r.eventId + replyTo: "" - TapHandler { - acceptedButtons: Qt.RightButton - onSingleTapped: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(eventPoint.position.x, eventPoint.position.y - userName_.implicitHeight), r.eventId) - gesturePolicy: TapHandler.ReleaseWithinBounds - acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad - } + width: parent.width + height: replyContainer.implicitHeight + + //height: replyContainer.implicitHeight + data: GridLayout { + id: replyContainer + + width: parent.width + columns: 2 + rows: 2 + columnSpacing: Nheko.paddingMedium + rowSpacing: Nheko.paddingSmall - AbstractButton { - Layout.leftMargin: 4 - Layout.fillWidth: true - contentItem: ElidedLabel { - id: userName_ - fullText: userName - color: r.userColor - textFormat: Text.RichText - width: parent.width - elideWidth: width + Rectangle { + id: colorline + + Layout.preferredWidth: 4 + Layout.rowSpan: 2 + Layout.fillHeight: true + + Layout.row: 0 + Layout.column: 0 + + color: TimelineManager.userColor(r.userId, palette.base) } - onClicked: room.openUserProfile(userId) - } - Rectangle { - Layout.leftMargin: 4 - Layout.preferredHeight: 20 - Layout.fillWidth: true - color: "green" - } + AbstractButton { + id: usernameBtn + Layout.fillWidth: true + + Layout.row: 0 + Layout.column: 1 + + contentItem: ElidedLabel { + id: userName_ + fullText: r.userName + color: r.userColor + textFormat: Text.RichText + width: parent.width + elideWidth: width + } + onClicked: room.openUserProfile(r.userId) + } + data: [ + colorline, usernameBtn, timelineEvent.main, + ] + + } } - Rectangle { + background: Rectangle { id: backgroundItem z: -1 - anchors.fill: replyContainer - property color userColor: TimelineManager.userColor(userId, palette.base) + property color userColor: TimelineManager.userColor(r.userId, palette.base) property color bgColor: palette.base color: Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.1)) }