Rework MessageDelegate in cpp
Rework MessageDelegate to be mostly a cpp class. This allows us to only load the components that are actually needed saving memory. In testing using memtest it saved ~30% versus the current implementation.
This commit is contained in:
240
src/timeline/messagedelegate.h
Normal file
240
src/timeline/messagedelegate.h
Normal file
@@ -0,0 +1,240 @@
|
||||
// SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QQmlIncubator>
|
||||
#include <QQuickItem>
|
||||
#include <QTimer>
|
||||
|
||||
#include "neochatroommember.h"
|
||||
#include "timelinedelegate.h"
|
||||
|
||||
/**
|
||||
* @brief Incubator for creating instances of components as required.
|
||||
*/
|
||||
class MessageObjectIncubator : public QQmlIncubator
|
||||
{
|
||||
public:
|
||||
MessageObjectIncubator(std::function<void(QQuickItem *)> initialCallback,
|
||||
std::function<void(MessageObjectIncubator *)> completedCallback,
|
||||
std::function<void(MessageObjectIncubator *)> errorCallback);
|
||||
|
||||
private:
|
||||
void setInitialState(QObject *object) override;
|
||||
std::function<void(QQuickItem *)> m_initialCallback;
|
||||
void statusChanged(QQmlIncubator::Status status) override;
|
||||
std::function<void(MessageObjectIncubator *)> m_completedCallback;
|
||||
std::function<void(MessageObjectIncubator *)> m_errorCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Delegate Item for all messages in the timeline.
|
||||
*/
|
||||
class MessageDelegateBase : public TimelineDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief The message author.
|
||||
*
|
||||
* @sa NeochatRoomMember
|
||||
*/
|
||||
Q_PROPERTY(NeochatRoomMember *author READ author WRITE setAuthor NOTIFY authorChanged FINAL REQUIRED)
|
||||
|
||||
/**
|
||||
* @brief Whether the message is threaded.
|
||||
*/
|
||||
Q_PROPERTY(bool isThreaded READ isThreaded WRITE setIsThreaded NOTIFY isThreadedChanged FINAL REQUIRED)
|
||||
|
||||
/**
|
||||
* @brief The maximum width available to the content item.
|
||||
*/
|
||||
Q_PROPERTY(qreal maxContentWidth READ maxContentWidth NOTIFY maxContentWidthChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief The component to use to visualize a user avatar.
|
||||
*/
|
||||
Q_PROPERTY(QQmlComponent *avatarComponent READ avatarComponent WRITE setAvatarComponent NOTIFY avatarComponentChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief Whether the user avatar should be shown.
|
||||
*
|
||||
* @note An avatar is only shown if enabled.
|
||||
*/
|
||||
Q_PROPERTY(bool showAuthor READ showAuthor WRITE setShowAuthor NOTIFY showAuthorChanged FINAL REQUIRED)
|
||||
|
||||
/**
|
||||
* @brief Whether user avatars are enabled.
|
||||
*/
|
||||
Q_PROPERTY(bool enableAvatars READ enableAvatars WRITE setEnableAvatars NOTIFY enableAvatarsChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief The component to use to visualize a section.
|
||||
*/
|
||||
Q_PROPERTY(QQmlComponent *sectionComponent READ sectionComponent WRITE setSectionComponent NOTIFY sectionComponentChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief Whether to show the section component.
|
||||
*/
|
||||
Q_PROPERTY(bool showSection READ showSection WRITE setShowSection NOTIFY showSectionChanged FINAL REQUIRED)
|
||||
|
||||
/**
|
||||
* @brief The component to use to visualize other user read markers.
|
||||
*/
|
||||
Q_PROPERTY(QQmlComponent *readMarkerComponent READ readMarkerComponent WRITE setReadMarkerComponent NOTIFY readMarkerComponentChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief Whether to show the other user read markers.
|
||||
*/
|
||||
Q_PROPERTY(bool showReadMarkers READ showReadMarkers WRITE setShowReadMarkers NOTIFY showReadMarkersChanged FINAL REQUIRED)
|
||||
|
||||
/**
|
||||
* @brief The component to use to visualize the hover state in compact mode.
|
||||
*/
|
||||
Q_PROPERTY(QQmlComponent *compactBackgroundComponent READ compactBackgroundComponent WRITE setCompactBackgroundComponentt NOTIFY
|
||||
compactBackgroundComponentChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief Whether to use the compact mode appearance.
|
||||
*/
|
||||
Q_PROPERTY(bool compactMode READ compactMode WRITE setCompactMode NOTIFY compactModeChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief Whether to show messages by the local user on the right in bubble mode.
|
||||
*/
|
||||
Q_PROPERTY(bool showLocalMessagesOnRight READ showLocalMessagesOnRight WRITE setShowLocalMessagesOnRight NOTIFY showLocalMessagesOnRightChanged FINAL)
|
||||
|
||||
/**
|
||||
* @brief Whether the message should be highlighted temporarily.
|
||||
*
|
||||
* Normally triggered when jumping to the event in the timeline, e.g. when a reply
|
||||
* is clicked.
|
||||
*/
|
||||
Q_PROPERTY(bool isTemporaryHighlighted READ isTemporaryHighlighted WRITE setIsTemporaryHighlighted NOTIFY isTemporaryHighlightedChanged FINAL)
|
||||
|
||||
public:
|
||||
MessageDelegateBase(QQuickItem *parent = nullptr);
|
||||
|
||||
NeochatRoomMember *author() const;
|
||||
void setAuthor(NeochatRoomMember *author);
|
||||
|
||||
bool isThreaded() const;
|
||||
void setIsThreaded(bool isThreaded);
|
||||
|
||||
qreal maxContentWidth() const;
|
||||
|
||||
QQmlComponent *avatarComponent() const;
|
||||
void setAvatarComponent(QQmlComponent *avatarComponent);
|
||||
bool showAuthor() const;
|
||||
void setShowAuthor(bool showAuthor);
|
||||
bool enableAvatars() const;
|
||||
void setEnableAvatars(bool enableAvatars);
|
||||
|
||||
QQmlComponent *sectionComponent() const;
|
||||
void setSectionComponent(QQmlComponent *sectionComponent);
|
||||
bool showSection() const;
|
||||
void setShowSection(bool showSection);
|
||||
|
||||
QQmlComponent *readMarkerComponent() const;
|
||||
void setReadMarkerComponent(QQmlComponent *readMarkerComponent);
|
||||
bool showReadMarkers() const;
|
||||
void setShowReadMarkers(bool showReadMarkers);
|
||||
|
||||
QQmlComponent *compactBackgroundComponent() const;
|
||||
void setCompactBackgroundComponentt(QQmlComponent *compactBackgroundComponent);
|
||||
bool compactMode() const;
|
||||
void setCompactMode(bool compactMode);
|
||||
|
||||
bool showLocalMessagesOnRight() const;
|
||||
void setShowLocalMessagesOnRight(bool showLocalMessagesOnRight);
|
||||
|
||||
bool isTemporaryHighlighted() const;
|
||||
void setIsTemporaryHighlighted(bool isTemporaryHighlighted);
|
||||
|
||||
Q_SIGNALS:
|
||||
void authorChanged();
|
||||
void isThreadedChanged();
|
||||
void maxContentWidthChanged();
|
||||
void avatarComponentChanged();
|
||||
void showAuthorChanged();
|
||||
void enableAvatarsChanged();
|
||||
void sectionComponentChanged();
|
||||
void showSectionChanged();
|
||||
void readMarkerComponentChanged();
|
||||
void showReadMarkersChanged();
|
||||
void compactBackgroundComponentChanged();
|
||||
void compactModeChanged();
|
||||
void showLocalMessagesOnRightChanged();
|
||||
void isTemporaryHighlightedChanged();
|
||||
|
||||
private:
|
||||
DelegateSizeHelper m_contentSizeHelper;
|
||||
|
||||
QPointer<NeochatRoomMember> m_author;
|
||||
|
||||
bool m_isThreaded = false;
|
||||
|
||||
QPointer<QQmlComponent> m_avatarComponent;
|
||||
bool m_avatarIncubating = false;
|
||||
QPointer<QQuickItem> m_avatarItem;
|
||||
bool m_showAuthor = false;
|
||||
bool m_enableAvatars = true;
|
||||
bool leaveAvatarSpace() const;
|
||||
bool showAvatar() const;
|
||||
void updateAvatar();
|
||||
|
||||
QPointer<QQmlComponent> m_sectionComponent;
|
||||
bool m_sectionIncubating = false;
|
||||
QPointer<QQuickItem> m_sectionItem;
|
||||
bool m_showSection = false;
|
||||
void updateSection();
|
||||
|
||||
QPointer<QQmlComponent> m_readMarkerComponent;
|
||||
bool m_readMarkerIncubating = false;
|
||||
QPointer<QQuickItem> m_readMarkerItem;
|
||||
bool m_showReadMarkers = false;
|
||||
void updateReadMarker();
|
||||
|
||||
QPointer<QQmlComponent> m_compactBackgroundComponent;
|
||||
bool m_compactBackgroundIncubating = false;
|
||||
QPointer<QQuickItem> m_compactBackgroundItem;
|
||||
bool m_compactMode = false;
|
||||
void updateBackground();
|
||||
|
||||
bool m_showLocalMessagesOnRight = true;
|
||||
|
||||
bool m_hovered = false;
|
||||
void hoverEnterEvent(QHoverEvent *event) override;
|
||||
void hoverMoveEvent(QHoverEvent *event) override;
|
||||
void hoverLeaveEvent(QHoverEvent *event) override;
|
||||
|
||||
std::function<void(QQuickItem *)> m_objectInitialCallback = [this](QQuickItem *object) {
|
||||
object->setParentItem(this);
|
||||
connect(object, &QQuickItem::implicitWidthChanged, this, &MessageDelegateBase::markAsDirty);
|
||||
connect(object, &QQuickItem::implicitHeightChanged, this, &MessageDelegateBase::markAsDirty);
|
||||
connect(object, &QQuickItem::visibleChanged, this, &MessageDelegateBase::markAsDirty);
|
||||
};
|
||||
std::function<void(MessageObjectIncubator *)> m_errorCallback = [this](MessageObjectIncubator *incubator) {
|
||||
if (incubator->object()) {
|
||||
incubator->object()->deleteLater();
|
||||
}
|
||||
cleanupIncubator(incubator);
|
||||
};
|
||||
void cleanupIncubator(MessageObjectIncubator *incubator);
|
||||
void cleanupItem(QQuickItem *item);
|
||||
|
||||
qreal m_spacing = 0.0;
|
||||
qreal m_avatarSize = 0.0;
|
||||
|
||||
void setCurveValues() override;
|
||||
void setBaseRightPadding();
|
||||
void setPercentageValues(bool fillWidth = false);
|
||||
void setContentPadding();
|
||||
void updateImplicitHeight() override;
|
||||
bool showMessageOnRight() const;
|
||||
void resizeContent() override;
|
||||
|
||||
QPointer<QTimer> m_temporaryHighlightTimer;
|
||||
};
|
||||
Reference in New Issue
Block a user