Files
neochat/imports/NeoChat/Component/Timeline/TimelineContainer.qml
2021-03-20 18:02:41 +01:00

249 lines
9.4 KiB
QML

/**
* SPDX-FileCopyrightText: 2020 Black Hat <bhat@encom.eu.org>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
import QtQuick 2.15
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12 as QQC2
import QtGraphicalEffects 1.12
import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
import NeoChat.Setting 1.0
import NeoChat.Component 1.0
import NeoChat.Dialog 1.0
Item {
default property alias innerObject : column.children
readonly property bool sentByMe: author.isLocalUser
readonly property bool darkBackground: !sentByMe
readonly property bool replyVisible: reply ?? false
readonly property bool failed: marks == EventStatus.SendingFailed
readonly property color authorColor: eventType == "notice" ? Kirigami.Theme.activeTextColor : author.color
readonly property color replyAuthorColor: replyVisible ? reply.author.color : Kirigami.Theme.focusColor
property bool isEmote: false
property bool cardBackground: true
property bool isLoaded
property var hoverComponent
signal saveFileAs()
signal openExternally()
signal replyClicked(string eventID)
property alias hovered: controlContainer.hovered
//height: mainColumn.childrenRect.height + (readMarker ? Kirigami.Units.smallSpacing : 0)
height: mainColumn.implicitHeight + (readMarker ? Kirigami.Units.smallSpacing : 0)
property int hoverComponentX: column.width - hoverComponent.childWidth + Kirigami.Units.largeSpacing
property int hoverComponentY: -Kirigami.Units.largeSpacing - hoverComponent.childHeight * 1.5
// 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() {
hoverComponent.x = column.mapToItem(page, hoverComponentX, hoverComponentY).x;
hoverComponent.y = column.mapToItem(page, hoverComponentX, hoverComponentY).y;
hoverComponent.hovered = Qt.binding(() => controlContainer.hovered);
hoverComponent.showEdit = author.id === Controller.activeConnection.localUserId && (model.eventType === "emote" || model.eventType === "message");
hoverComponent.updateFunction = updateHoverComponent;
hoverComponent.editClicked = () => {
if (hoverComponent.showEdit) {
ChatBoxHelper.edit(message, formattedBody, eventId)
}
};
hoverComponent.replyClicked = () => {
ChatBoxHelper.replyToMessage(eventId, message, author);
};
hoverComponent.reacted = emoji => {
currentRoom.toggleReaction(eventId, emoji);
};
}
DragHandler {
enabled: Kirigami.Settings.isMobile
yAxis.enabled: false
xAxis.enabled: true
xAxis.maximum: 0
xAxis.minimum: -Kirigami.Units.gridUnit * 4
onActiveChanged: {
applicationWindow().pageStack.interactive = true;
if (!active && parent.x < -Kirigami.Units.gridUnit * 3) {
replyToMessage(author, message, eventId)
}
parent.x = 0;
}
}
onXChanged: if (x !== 0) {
applicationWindow().pageStack.interactive = false;
} else {
applicationWindow().pageStack.interactive = true;
}
ColumnLayout {
id: mainColumn
width: parent.width
spacing: 0
SectionDelegate {
id: sectionDelegate
Layout.maximumWidth: parent.width
Layout.alignment: Qt.AlignHCenter
visible: showSection
}
RowLayout {
id: root
spacing: Kirigami.Units.smallSpacing
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: 0
Layout.topMargin: model.showAuthor ? Kirigami.Units.smallSpacing : 0
Kirigami.Avatar {
Layout.minimumWidth: Kirigami.Units.gridUnit * 2
Layout.minimumHeight: Kirigami.Units.gridUnit * 2
Layout.maximumWidth: Kirigami.Units.gridUnit * 2
Layout.maximumHeight: Kirigami.Units.gridUnit * 2
Layout.alignment: Qt.AlignTop
visible: model.showAuthor && Config.showAvatarInTimeline
name: author.name ?? author.displayName
source: author.avatarMediaId ? ("image://mxc/" + author.avatarMediaId) : ""
color: author.color
Component {
id: userDetailDialog
UserDetailDialog {}
}
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()
cursorShape: Qt.PointingHandCursor
}
}
Item {
Layout.minimumWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: 1
visible: !model.showAuthor && Config.showAvatarInTimeline
}
// bubble
QQC2.ItemDelegate {
id: controlContainer
Layout.maximumWidth: mainColumn.width - Kirigami.Units.gridUnit * 2 - Kirigami.Units.largeSpacing * 2
implicitHeight: contentItem.implicitHeight
topPadding: Kirigami.Units.largeSpacing
bottomPadding: 0
leftPadding: 0
rightPadding: 0
hoverEnabled: true
contentItem: ColumnLayout {
id: column
spacing: 0
Loader {
id: topRow
active: model.showAuthor && !isEmote
visible: active
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: visible ? Kirigami.Units.smallSpacing : 0
sourceComponent: RowLayout {
id: rowLayout
QQC2.Label {
Layout.fillWidth: true
topInset: 0
visible: model.showAuthor && !isEmote
text: author.displayName
font.weight: Font.Bold
color: author.color
wrapMode: Text.Wrap
}
QQC2.Label {
visible: model.showAuthor && !isEmote
text: time.toLocaleTimeString(Locale.ShortFormat)
color: Kirigami.Theme.disabledTextColor
}
}
}
Loader {
id: replyLoader
source: 'qrc:imports/NeoChat/Component/Timeline/ReplyComponent.qml'
active: replyVisible
visible: active
Layout.bottomMargin: Kirigami.Units.smallSpacing
Connections {
target: replyLoader.item
function onClicked() {
replyClicked(reply.eventId)
}
}
}
}
background: Kirigami.ShadowedRectangle {
visible: cardBackground
color: model.isHighlighted ? Kirigami.Theme.positiveBackgroundColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
shadow.size: Kirigami.Units.smallSpacing
shadow.color: !model.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: Kirigami.Units.devicePixelRatio
}
}
}
Loader {
id: loader
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing * 2
Layout.topMargin: active ? Kirigami.Units.smallSpacing : 0
active: eventType !== "state" && eventType !== "notice" && reaction != undefined && reaction.length > 0
visible: active
sourceComponent: ReactionDelegate { }
}
}
Kirigami.Icon {
id: replyButton
visible: parent.x < - Kirigami.Units.gridUnit * 1
opacity: -(parent.x + Kirigami.Units.gridUnit) / Kirigami.Units.gridUnit / 3
anchors.left: parent.right
anchors.top: parent.top
source: "mail-replied-symbolic"
}
Rectangle {
width: parent.width * 0.9
x: parent.width * 0.05
height: Kirigami.Units.smallSpacing / 2
anchors.top: mainColumn.bottom
anchors.topMargin: Kirigami.Units.smallSpacing
visible: readMarker
color: Kirigami.Theme.positiveTextColor
}
}