mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 03:00:46 +03:00
Reimplement reply delegate by moving out the timeline event without layout
This commit is contained in:
parent
aef0cb9884
commit
b187440e68
13 changed files with 352 additions and 460 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -728,9 +728,9 @@ Page {
|
|||
}
|
||||
Platform.MenuItem {
|
||||
text: qsTr("Mark as read")
|
||||
|
||||
onTriggered: Rooms.getRoomById(roomContextMenu.roomid).markRoomAsRead()
|
||||
}
|
||||
|
||||
Platform.MenuItem {
|
||||
text: qsTr("Room settings")
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
255
resources/qml/TimelineEvent.qml
Normal file
255
resources/qml/TimelineEvent.qml
Normal file
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -147,7 +147,8 @@ AbstractButton {
|
|||
columns: Settings.bubbles ? 1 : 2
|
||||
rowSpacing: 0
|
||||
rows: Settings.bubbles ? 3 : 2
|
||||
/*
|
||||
|
||||
/*
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 4
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
||||
AbstractButton {
|
||||
Layout.leftMargin: 4
|
||||
Layout.fillWidth: true
|
||||
contentItem: ElidedLabel {
|
||||
id: userName_
|
||||
fullText: userName
|
||||
color: r.userColor
|
||||
textFormat: Text.RichText
|
||||
width: parent.width
|
||||
elideWidth: width
|
||||
//height: replyContainer.implicitHeight
|
||||
data: GridLayout {
|
||||
id: replyContainer
|
||||
|
||||
width: parent.width
|
||||
columns: 2
|
||||
rows: 2
|
||||
columnSpacing: Nheko.paddingMedium
|
||||
rowSpacing: Nheko.paddingSmall
|
||||
|
||||
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))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue