// Copyright Mirage authors & contributors // SPDX-License-Identifier: LGPL-3.0-or-later import QtQuick 2.12 import QtQuick.Layouts 1.12 import Clipboard 0.1 import "../../.." import "../../../Base" HColumnLayout { id: eventDelegate property string fetchProfilesFutureId: "" // Remember timeline goes from newest message at index 0 to oldest readonly property var previousModel: eventList.model.get(model.index + 1) readonly property var nextModel: eventList.model.get(model.index - 1) readonly property QtObject currentModel: model readonly property bool isFocused: model.index === eventList.currentIndex readonly property bool compact: window.settings.General.compact readonly property bool checked: model.id in eventList.checked readonly property bool isOwn: chat.userId === model.sender_id readonly property bool isRedacted: model.event_type === "RedactedEvent" readonly property bool onRight: ! eventList.ownEventsOnLeft && isOwn readonly property bool combine: eventList.canCombine(previousModel, model) readonly property bool talkBreak: eventList.canTalkBreak(previousModel, model) readonly property bool dayBreak: eventList.canDayBreak(previousModel, model) readonly property bool hideNameLine: model.event_type === "RoomMessageEmote" || ! ( model.event_type.startsWith("RoomMessage") || model.event_type.startsWith("RoomEncrypted") ) || onRight || combine readonly property int cursorShape: eventContent.hoveredLink ? Qt.PointingHandCursor : eventContent.hoveredSelectable ? Qt.IBeamCursor : Qt.ArrowCursor readonly property int separationSpacing: theme.spacing * ( dayBreak ? 4 : talkBreak ? 6 : combine && compact ? 0.25 : combine ? 0.5 : compact ? 1 : 2 ) readonly property alias eventContent: eventContent function dict() { let event = eventList.model.get(model.index) event = JSON.parse(JSON.stringify(event)) event.source = JSON.parse(event.source) return event } function openContextMenu() { eventList.contextMenu.spawn( model.index, eventDelegate, eventContent.hoveredLink, ) } function toggleChecked() { eventList.toggleCheck(model.index) } visible: !model.hidden width: eventList.width - eventList.leftMargin - eventList.rightMargin // Needed because of eventList's MouseArea which steals the // HSelectableLabel's MouseArea hover events onCursorShapeChanged: eventList.cursorShape = cursorShape Component.onCompleted: { if (model.fetch_profile) fetchProfilesFutureId = py.callClientCoro( chat.userId, "get_event_profiles", [chat.roomId, model.id], // The if avoids segfault if eventDelegate is already destroyed () => { if (eventDelegate) fetchProfilesFutureId = "" } ) // Workaround for hiding messages of certain types if (!eventDelegate.visible) eventDelegate.height = 0 } Component.onDestruction: if (fetchProfilesFutureId) py.cancelCoro(fetchProfilesFutureId) ListView.onRemove: eventList.uncheck(model.id) DelegateTransitionFixer {} Item { Layout.fillWidth: true visible: model.event_type !== "RoomCreateEvent" Layout.preferredHeight: separationSpacing } DayBreak { visible: dayBreak Layout.fillWidth: true Layout.minimumWidth: parent.width Layout.bottomMargin: separationSpacing } EventContent { id: eventContent Layout.fillWidth: true } TapHandler { acceptedButtons: Qt.LeftButton acceptedModifiers: Qt.NoModifier onTapped: toggleChecked() } TapHandler { acceptedButtons: Qt.LeftButton acceptedModifiers: Qt.ShiftModifier onTapped: eventList.checkFromLastToHere(model.index) } TapHandler { acceptedButtons: Qt.RightButton acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen onTapped: openContextMenu() } TapHandler { acceptedPointerTypes: PointerDevice.Finger | PointerDevice.Pen onLongPressed: openContextMenu() } }