Refactor Timeline Container
Update the base item in the timeline container to be a column layout. This means that all the items can be laid out automatically without the need to set lots of manual settings and anchoring. The overall height calculation for the delegate is vastly simplified (in fact it is removed) which deals with the fact that there were still instances where the manual calculation didn't work e.g. a delegate with a reaction followed by another message from the same user didn't give the correct bottom margin (see below) before:  after:  This also improves upon the recently changed hover highlight behaviour. The previous patched moved it to cover the avatar as well as the bubble however it also covered the section and reaction when present which didn't look good. The highlight now only covers the avatar and bubble before:  after:  This also cleans up some of the margins in both bubble and compact to ensure consistency.
This commit is contained in:
@@ -13,15 +13,13 @@ import org.kde.neochat 1.0
|
||||
TimelineContainer {
|
||||
id: audioDelegate
|
||||
|
||||
onReplyClicked: ListView.view.goToEvent(eventID)
|
||||
|
||||
onOpenContextMenu: openFileContext(model, audioDelegate)
|
||||
|
||||
readonly property bool downloaded: model.progressInfo && model.progressInfo.completed
|
||||
onDownloadedChanged: audio.play()
|
||||
|
||||
hoverComponent: hoverActions
|
||||
innerObject: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: audioDelegate.contentMaxWidth
|
||||
|
||||
Audio {
|
||||
|
||||
@@ -13,9 +13,6 @@ import org.kde.neochat 1.0
|
||||
TimelineContainer {
|
||||
id: fileDelegate
|
||||
|
||||
onReplyClicked: ListView.view.goToEvent(eventID)
|
||||
hoverComponent: hoverActions
|
||||
|
||||
onOpenContextMenu: openFileContext(model, fileDelegate)
|
||||
|
||||
readonly property bool downloaded: progressInfo && progressInfo.completed
|
||||
|
||||
@@ -13,9 +13,6 @@ import org.kde.neochat 1.0
|
||||
TimelineContainer {
|
||||
id: imageDelegate
|
||||
|
||||
onReplyClicked: ListView.view.goToEvent(eventID)
|
||||
hoverComponent: hoverActions
|
||||
|
||||
onOpenContextMenu: openFileContext(model, imageDelegate)
|
||||
|
||||
property var content: model.content
|
||||
|
||||
@@ -16,9 +16,6 @@ TimelineContainer {
|
||||
property bool isEmote: false
|
||||
onOpenContextMenu: openMessageContext(model, label.selectedText, Controller.plainText(label.textDocument))
|
||||
|
||||
onReplyClicked: ListView.view.goToEvent(eventID)
|
||||
hoverComponent: hoverActions
|
||||
|
||||
innerObject: ColumnLayout {
|
||||
Layout.maximumWidth: messageDelegate.contentMaxWidth
|
||||
RichLabel {
|
||||
@@ -29,7 +26,6 @@ TimelineContainer {
|
||||
Loader {
|
||||
id: linkPreviewLoader
|
||||
Layout.fillWidth: true
|
||||
height: active ? item.implicitHeight : 0
|
||||
active: !currentRoom.usesEncryption && model.display && model.display.includes("http")
|
||||
visible: Config.showLinkPreview && active
|
||||
sourceComponent: LinkPreviewDelegate {
|
||||
|
||||
@@ -9,7 +9,8 @@ import QtQuick.Layouts 1.15
|
||||
import org.kde.kirigami 2.15 as Kirigami
|
||||
|
||||
Flow {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Repeater {
|
||||
model: reaction ?? null
|
||||
|
||||
@@ -32,7 +33,6 @@ Flow {
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
|
||||
checkable: true
|
||||
|
||||
checked: modelData.hasLocalUser
|
||||
|
||||
@@ -9,15 +9,21 @@ import org.kde.kirigami 2.15 as Kirigami
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
QQC2.ItemDelegate {
|
||||
id: timelineContainer
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
signal openContextMenu
|
||||
signal openExternally()
|
||||
signal replyClicked(string eventID)
|
||||
|
||||
onReplyClicked: ListView.view.goToEvent(eventID)
|
||||
|
||||
default property alias innerObject : column.children
|
||||
// readonly property bool failed: marks == EventStatus.SendingFailed
|
||||
|
||||
readonly property bool sectionVisible: model.showSection
|
||||
|
||||
property Item hoverComponent: hoverActions
|
||||
property bool isEmote: false
|
||||
property bool cardBackground: true
|
||||
property bool showUserMessageOnRight: Config.showLocalMessagesOnRight && model.author.isLocalUser && !Config.compactLayout
|
||||
property bool isHighlighted: model.isHighlighted || isTemporaryHighlighted
|
||||
property bool isTemporaryHighlighted: false
|
||||
|
||||
@@ -30,58 +36,15 @@ QQC2.ItemDelegate {
|
||||
onTriggered: isTemporaryHighlighted = false
|
||||
}
|
||||
|
||||
signal openContextMenu
|
||||
|
||||
// The bubble and delegate widths are allowed to grow once the ListView gets beyond a certain size
|
||||
// extraWidth defines this as the excess after a certain ListView width, capped to a max value
|
||||
readonly property int extraWidth: messageListView.width >= Kirigami.Units.gridUnit * 46 ? Math.min((messageListView.width - Kirigami.Units.gridUnit * 46), Kirigami.Units.gridUnit * 20) : 0
|
||||
readonly property int bubbleMaxWidth: Kirigami.Units.gridUnit * 20 + extraWidth * 0.5
|
||||
readonly property int delegateMaxWidth: Config.compactLayout ? messageListView.width : Math.min(messageListView.width, Kirigami.Units.gridUnit * 40 + extraWidth)
|
||||
readonly property int delegateWidth: Config.compactLayout ? messageListView.width : Math.min(messageListView.width, Kirigami.Units.gridUnit * 40 + extraWidth)
|
||||
readonly property int contentMaxWidth: Config.compactLayout ? width - (Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 : 0) - Kirigami.Units.largeSpacing * 4 : Math.min(width - Kirigami.Units.gridUnit * 2 - Kirigami.Units.largeSpacing * 6, bubbleMaxWidth)
|
||||
|
||||
property bool showUserMessageOnRight: Config.showLocalMessagesOnRight &&
|
||||
model.author.isLocalUser && !Config.compactLayout
|
||||
|
||||
signal openExternally()
|
||||
signal replyClicked(string eventID)
|
||||
|
||||
Component.onCompleted: {
|
||||
if (model.isReply && model.reply === undefined) {
|
||||
messageEventModel.loadReply(sortedMessageEventModel.mapToSource(sortedMessageEventModel.index(model.index, 0)))
|
||||
}
|
||||
}
|
||||
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
topInset: showAuthor ? Kirigami.Units.largeSpacing : (Config.compactLayout ? 1 : Kirigami.Units.smallSpacing)
|
||||
leftInset: Kirigami.Units.smallSpacing
|
||||
rightInset: Kirigami.Units.smallSpacing
|
||||
width: delegateMaxWidth
|
||||
height: sectionDelegate.height + Math.max(model.showAuthor ? avatar.height : 0, bubble.implicitHeight) + loader.height + loader.anchors.topMargin + avatar.anchors.topMargin
|
||||
background: Rectangle {
|
||||
visible: timelineContainer.hovered
|
||||
color: Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
}
|
||||
|
||||
property Item hoverComponent
|
||||
|
||||
// show hover actions
|
||||
onHoveredChanged: {
|
||||
if (hovered && !Kirigami.Settings.isMobile) {
|
||||
updateHoverComponent();
|
||||
}
|
||||
}
|
||||
|
||||
// updates the global hover component to point to this delegate, and update its position
|
||||
function updateHoverComponent() {
|
||||
if (hoverComponent) {
|
||||
hoverComponent.delegate = timelineContainer
|
||||
hoverComponent.bubble = bubble
|
||||
hoverComponent.updateFunction = updateHoverComponent;
|
||||
hoverComponent.event = model
|
||||
}
|
||||
}
|
||||
width: delegateWidth
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
state: Config.compactLayout ? "alignLeft" : "alignCenter"
|
||||
// Align left when in compact mode and center when using bubbles
|
||||
@@ -89,7 +52,7 @@ QQC2.ItemDelegate {
|
||||
State {
|
||||
name: "alignLeft"
|
||||
AnchorChanges {
|
||||
target: timelineContainer
|
||||
target: root
|
||||
anchors.horizontalCenter: undefined
|
||||
anchors.left: parent ? parent.left : undefined
|
||||
}
|
||||
@@ -97,7 +60,7 @@ QQC2.ItemDelegate {
|
||||
State {
|
||||
name: "alignCenter"
|
||||
AnchorChanges {
|
||||
target: timelineContainer
|
||||
target: root
|
||||
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
|
||||
anchors.left: undefined
|
||||
}
|
||||
@@ -112,216 +75,244 @@ QQC2.ItemDelegate {
|
||||
|
||||
SectionDelegate {
|
||||
id: sectionDelegate
|
||||
anchors.left: timelineContainer.left
|
||||
anchors.right: timelineContainer.right
|
||||
visible: sectionVisible
|
||||
height: visible ? implicitHeight : 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
visible: model.showSection
|
||||
labelText: model.showSection ? section : ""
|
||||
}
|
||||
|
||||
Kirigami.Avatar {
|
||||
id: avatar
|
||||
width: visible || Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing * 2 : 0
|
||||
height: width
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
topInset: Kirigami.Units.smallSpacing
|
||||
bottomInset: Kirigami.Units.smallSpacing
|
||||
leftInset: Kirigami.Units.smallSpacing
|
||||
rightInset: Kirigami.Units.smallSpacing
|
||||
sourceSize.width: width
|
||||
sourceSize.height: width
|
||||
anchors {
|
||||
top: sectionDelegate.bottom
|
||||
topMargin: model.showAuthor ? Kirigami.Units.largeSpacing : (Config.compactLayout ? 1 : Kirigami.Units.smallSpacing)
|
||||
left: parent.left
|
||||
leftMargin: Kirigami.Units.smallSpacing
|
||||
}
|
||||
QQC2.ItemDelegate {
|
||||
id: mainContainer
|
||||
|
||||
visible: model.showAuthor &&
|
||||
Config.showAvatarInTimeline &&
|
||||
(Config.compactLayout || !showUserMessageOnRight)
|
||||
name: model.displayNameForInitials
|
||||
source: visible && model.author.avatarMediaId ? ("image://mxc/" + model.author.avatarMediaId) : ""
|
||||
color: model.author.color
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: showAuthor ? Kirigami.Units.largeSpacing : (Config.compactLayout ? 1 : Kirigami.Units.smallSpacing)
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
|
||||
room: currentRoom,
|
||||
user: author.object,
|
||||
displayName: author.displayName,
|
||||
avatarMediaId: author.avatarMediaId,
|
||||
avatarUrl: author.avatarUrl
|
||||
}).open();
|
||||
implicitHeight: Math.max(model.showAuthor ? avatar.implicitHeight : 0, bubble.height)
|
||||
|
||||
Component.onCompleted: {
|
||||
if (model.isReply && model.reply === undefined) {
|
||||
messageEventModel.loadReply(sortedMessageEventModel.mapToSource(sortedMessageEventModel.index(model.index, 0)))
|
||||
}
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Control {
|
||||
id: bubble
|
||||
topPadding: Config.compactLayout ? Kirigami.Units.smallSpacing / 2 : Kirigami.Units.largeSpacing
|
||||
bottomPadding: Config.compactLayout ? Kirigami.Units.mediumSpacing / 2 : Kirigami.Units.largeSpacing
|
||||
leftPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||
rightPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||
hoverEnabled: true
|
||||
|
||||
anchors {
|
||||
top: avatar.top
|
||||
leftMargin: Kirigami.Units.smallSpacing
|
||||
rightMargin: showUserMessageOnRight ? Kirigami.Units.smallSpacing : Kirigami.Units.largeSpacing
|
||||
// show hover actions
|
||||
onHoveredChanged: {
|
||||
if (hovered && !Kirigami.Settings.isMobile) {
|
||||
updateHoverComponent();
|
||||
}
|
||||
}
|
||||
// HACK: anchoring didn't reset anchors.right when switching from parent.right to undefined reliably
|
||||
width: Config.compactLayout ? timelineContainer.width - (Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 : 0) + Kirigami.Units.largeSpacing * 2 : implicitWidth
|
||||
|
||||
state: showUserMessageOnRight ? "userMessageOnRight" : "userMessageOnLeft"
|
||||
// states for anchor animations on window resize
|
||||
// as setting anchors to undefined did not work reliably
|
||||
states: [
|
||||
State {
|
||||
name: "userMessageOnRight"
|
||||
AnchorChanges {
|
||||
target: bubble
|
||||
anchors.left: undefined
|
||||
anchors.right: parent.right
|
||||
|
||||
// Show hover actions by updating the global hover component to this delegate
|
||||
function updateHoverComponent() {
|
||||
if (hovered && !Kirigami.Settings.isMobile) {
|
||||
hoverComponent.delegate = root
|
||||
hoverComponent.bubble = bubble
|
||||
hoverComponent.event = model
|
||||
hoverComponent.updateFunction = updateHoverComponent;
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Avatar {
|
||||
id: avatar
|
||||
width: visible || Config.showAvatarInTimeline ? Kirigami.Units.gridUnit * 2 + Kirigami.Units.smallSpacing * 2 : 0
|
||||
height: width
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
topInset: Kirigami.Units.smallSpacing
|
||||
bottomInset: Kirigami.Units.smallSpacing
|
||||
leftInset: Kirigami.Units.smallSpacing
|
||||
rightInset: Kirigami.Units.smallSpacing
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Kirigami.Units.smallSpacing
|
||||
}
|
||||
|
||||
visible: model.showAuthor &&
|
||||
Config.showAvatarInTimeline &&
|
||||
(Config.compactLayout || !showUserMessageOnRight)
|
||||
name: model.author.name ?? model.author.displayName
|
||||
source: visible && model.author.avatarMediaId ? ("image://mxc/" + model.author.avatarMediaId) : ""
|
||||
color: model.author.color
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
|
||||
room: currentRoom,
|
||||
user: author.object,
|
||||
displayName: author.displayName,
|
||||
avatarMediaId: author.avatarMediaId,
|
||||
avatarUrl: author.avatarUrl
|
||||
}).open();
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "userMessageOnLeft"
|
||||
AnchorChanges {
|
||||
target: bubble
|
||||
anchors.left: avatar.right
|
||||
anchors.right: undefined
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Control {
|
||||
id: bubble
|
||||
topPadding: Config.compactLayout ? Kirigami.Units.smallSpacing / 2 : Kirigami.Units.largeSpacing
|
||||
bottomPadding: Config.compactLayout ? Kirigami.Units.mediumSpacing / 2 : Kirigami.Units.largeSpacing
|
||||
leftPadding: Config.compactLayout ? 0 : Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||
rightPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||
hoverEnabled: true
|
||||
|
||||
anchors {
|
||||
leftMargin: Kirigami.Units.smallSpacing
|
||||
rightMargin: Kirigami.Units.largeSpacing
|
||||
}
|
||||
// HACK: anchoring didn't reset anchors.right when switching from parent.right to undefined reliably
|
||||
width: Config.compactLayout ? 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
|
||||
// as setting anchors to undefined did not work reliably
|
||||
states: [
|
||||
State {
|
||||
name: "userMessageOnRight"
|
||||
AnchorChanges {
|
||||
target: bubble
|
||||
anchors.left: undefined
|
||||
anchors.right: parent.right
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "userMessageOnLeft"
|
||||
AnchorChanges {
|
||||
target: bubble
|
||||
anchors.left: avatar.right
|
||||
anchors.right: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
AnchorAnimation{duration: Kirigami.Units.longDuration; easing.type: Easing.OutCubic}
|
||||
}
|
||||
]
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: column
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
transitions: [
|
||||
Transition {
|
||||
AnchorAnimation{duration: Kirigami.Units.longDuration; easing.type: Easing.OutCubic}
|
||||
}
|
||||
]
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: column
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
visible: model.showAuthor && !isEmote
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
|
||||
QQC2.Label {
|
||||
id: nameLabel
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
visible: model.showAuthor && !isEmote
|
||||
|
||||
Layout.maximumWidth: contentMaxWidth - timeLabel.implicitWidth - rowLayout.spacing
|
||||
QQC2.Label {
|
||||
id: nameLabel
|
||||
|
||||
text: visible ? author.displayName : ""
|
||||
textFormat: Text.PlainText
|
||||
font.weight: Font.Bold
|
||||
color: author.color
|
||||
elide: Text.ElideRight
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
|
||||
room: currentRoom,
|
||||
user: author.object,
|
||||
displayName: author.displayName,
|
||||
avatarMediaId: author.avatarMediaId,
|
||||
avatarUrl: author.avatarUrl
|
||||
}).open();
|
||||
Layout.maximumWidth: contentMaxWidth - timeLabel.implicitWidth - rowLayout.spacing
|
||||
|
||||
text: visible ? author.displayName : ""
|
||||
textFormat: Text.PlainText
|
||||
font.weight: Font.Bold
|
||||
color: author.color
|
||||
elide: Text.ElideRight
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
|
||||
room: currentRoom,
|
||||
user: author.object,
|
||||
displayName: author.displayName,
|
||||
avatarMediaId: author.avatarMediaId,
|
||||
avatarUrl: author.avatarUrl
|
||||
}).open();
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.Label {
|
||||
id: timeLabel
|
||||
|
||||
text: visible ? time.toLocaleTimeString(Qt.locale(), Locale.ShortFormat) : ""
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
QQC2.ToolTip.visible: hoverHandler.hovered
|
||||
QQC2.ToolTip.text: time.toLocaleString(Qt.locale(), Locale.LongFormat)
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.Label {
|
||||
id: timeLabel
|
||||
Loader {
|
||||
id: replyLoader
|
||||
|
||||
text: visible ? time.toLocaleTimeString(Qt.locale(), Locale.ShortFormat) : ""
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
QQC2.ToolTip.visible: hoverHandler.hovered
|
||||
QQC2.ToolTip.text: time.toLocaleString(Qt.locale(), Locale.LongFormat)
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
Layout.maximumWidth: contentMaxWidth
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
active: model.reply !== undefined
|
||||
visible: active
|
||||
|
||||
sourceComponent: ReplyComponent {
|
||||
name: currentRoom.htmlSafeMemberName(reply.author.id)
|
||||
avatar: reply.author.avatarMediaId ? ("image://mxc/" + reply.author.avatarMediaId) : ""
|
||||
color: reply.author.color
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: replyLoader.item
|
||||
function onReplyClicked() {
|
||||
replyClicked(reply.eventId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: replyLoader
|
||||
|
||||
Layout.maximumWidth: contentMaxWidth
|
||||
background: Item {
|
||||
Kirigami.ShadowedRectangle {
|
||||
id: bubbleBackground
|
||||
visible: cardBackground && !Config.compactLayout
|
||||
anchors.fill: parent
|
||||
color: {
|
||||
if (model.author.isLocalUser) {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
|
||||
} else if (root.isHighlighted) {
|
||||
return Kirigami.Theme.positiveBackgroundColor
|
||||
} else {
|
||||
return Kirigami.Theme.backgroundColor
|
||||
}
|
||||
}
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
shadow.size: Kirigami.Units.smallSpacing
|
||||
shadow.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)
|
||||
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
|
||||
border.width: 1
|
||||
|
||||
active: model.reply !== undefined
|
||||
visible: active
|
||||
|
||||
sourceComponent: ReplyComponent {
|
||||
name: currentRoom.htmlSafeMemberName(reply.author.id)
|
||||
avatar: reply.author.avatarMediaId ? ("image://mxc/" + reply.author.avatarMediaId) : ""
|
||||
color: reply.author.color
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: replyLoader.item
|
||||
function onReplyClicked() {
|
||||
replyClicked(reply.eventId)
|
||||
Behavior on color {
|
||||
ColorAnimation {target: bubbleBackground; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.InOutCubic}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
Kirigami.ShadowedRectangle {
|
||||
id: bubbleBackground
|
||||
visible: cardBackground && !Config.compactLayout
|
||||
anchors.fill: parent
|
||||
color: {
|
||||
if (model.author.isLocalUser) {
|
||||
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
|
||||
} else if (timelineContainer.isHighlighted) {
|
||||
return Kirigami.Theme.positiveBackgroundColor
|
||||
} else {
|
||||
return Kirigami.Theme.backgroundColor
|
||||
}
|
||||
}
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
shadow.size: Kirigami.Units.smallSpacing
|
||||
shadow.color: timelineContainer.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)
|
||||
border.color: Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
|
||||
border.width: 1
|
||||
background: Rectangle {
|
||||
visible: mainContainer.hovered
|
||||
color: Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, Kirigami.Theme.highlightColor, 0.15)
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {target: bubbleBackground; duration: Kirigami.Units.veryLongDuration; easing.type: Easing.InOutCubic}
|
||||
}
|
||||
}
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.RightButton
|
||||
onTapped: root.openContextMenu()
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onLongPressed: root.openContextMenu()
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors {
|
||||
left: bubble.left
|
||||
right: parent.right
|
||||
top: bubble.bottom
|
||||
topMargin: active ? Kirigami.Units.smallSpacing : 0
|
||||
}
|
||||
height: active ? item.implicitHeight : 0
|
||||
active: eventType !== MessageEventModel.State && eventType !== MessageEventModel.Notice && reaction != undefined && reaction.length > 0
|
||||
visible: active
|
||||
sourceComponent: ReactionDelegate { }
|
||||
}
|
||||
ReactionDelegate {
|
||||
Layout.maximumWidth: delegateWidth - Kirigami.Units.largeSpacing * 2
|
||||
Layout.alignment: showUserMessageOnRight ? Qt.AlignRight : Qt.AlignLeft
|
||||
Layout.leftMargin: showUserMessageOnRight ? 0 : bubble.x + bubble.anchors.leftMargin
|
||||
Layout.rightMargin: showUserMessageOnRight ? Kirigami.Units.largeSpacing : 0
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.RightButton
|
||||
acceptedDevices: PointerDevice.Mouse
|
||||
onTapped: timelineContainer.openContextMenu()
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onLongPressed: timelineContainer.openContextMenu()
|
||||
visible: eventType !== MessageEventModel.State && eventType !== MessageEventModel.Notice && reaction != undefined && reaction.length > 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,6 @@ import org.kde.neochat 1.0
|
||||
TimelineContainer {
|
||||
id: videoDelegate
|
||||
|
||||
onReplyClicked: ListView.view.goToEvent(eventID)
|
||||
hoverComponent: hoverActions
|
||||
|
||||
property bool playOnFinished: false
|
||||
readonly property bool downloaded: progressInfo && progressInfo.completed
|
||||
|
||||
|
||||
@@ -463,6 +463,7 @@ Kirigami.ScrollablePage {
|
||||
property var bubble: null
|
||||
property var hovered: bubble && bubble.hovered
|
||||
property var visibleDelayed: (hovered || hoverHandler.hovered) && !Kirigami.Settings.isMobile
|
||||
property var updateFunction
|
||||
onVisibleDelayedChanged: if (visibleDelayed) {
|
||||
visible = true;
|
||||
} else {
|
||||
@@ -482,8 +483,6 @@ Kirigami.ScrollablePage {
|
||||
|
||||
visible: false
|
||||
|
||||
property var updateFunction
|
||||
|
||||
property alias childWidth: hoverActionsRow.width
|
||||
property alias childHeight: hoverActionsRow.height
|
||||
|
||||
|
||||
Reference in New Issue
Block a user