diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bd4d5086c..df0b74666 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -141,6 +141,8 @@ add_library(neochat STATIC
colorschemer.h
models/notificationsmodel.cpp
models/notificationsmodel.h
+ models/timelinemodel.cpp
+ models/timelinemodel.h
)
qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
@@ -293,6 +295,8 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/SelectSpacesDialog.qml
qml/AttachDialog.qml
qml/NotificationsView.qml
+ qml/LoadingDelegate.qml
+ qml/TimelineEndDelegate.qml
RESOURCES
qml/confetti.png
qml/glowdot.png
diff --git a/src/enums/delegatetype.h b/src/enums/delegatetype.h
index d1e63030d..f1095f5d3 100644
--- a/src/enums/delegatetype.h
+++ b/src/enums/delegatetype.h
@@ -40,6 +40,8 @@ public:
Poll, /**< The initial event for a poll. */
Location, /**< A location event. */
LiveLocation, /**< The initial event of a shared live location (i.e., the place where this is supposed to be shown in the timeline). */
+ Loading, /**< A delegate to tell the user more messages are being loaded. */
+ TimelineEnd, /**< A delegate to inform that all messages are loaded. */
Other, /**< Anything that cannot be classified as another type. */
};
Q_ENUM(Type);
diff --git a/src/models/messageeventmodel.cpp b/src/models/messageeventmodel.cpp
index 95809fc71..d464395d0 100644
--- a/src/models/messageeventmodel.cpp
+++ b/src/models/messageeventmodel.cpp
@@ -389,13 +389,7 @@ int MessageEventModel::rowCount(const QModelIndex &parent) const
return 0;
}
- const auto firstIt = m_currentRoom->messageEvents().crbegin();
- if (firstIt != m_currentRoom->messageEvents().crend()) {
- const auto &firstEvt = **firstIt;
- return m_currentRoom->timelineSize() + (lastReadEventId != firstEvt.id() ? 1 : 0);
- } else {
- return m_currentRoom->timelineSize();
- }
+ return int(m_currentRoom->pendingEvents().size()) + m_currentRoom->timelineSize() + (m_lastReadEventIndex.isValid() ? 1 : 0);
}
bool MessageEventModel::canFetchMore(const QModelIndex &parent) const
@@ -422,7 +416,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
const auto row = idx.row();
- if (!m_currentRoom || row < 0 || row >= int(m_currentRoom->pendingEvents().size()) + m_currentRoom->timelineSize()) {
+ if (!m_currentRoom || row < 0 || row >= rowCount()) {
return {};
};
@@ -465,7 +459,6 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
return (reason.isEmpty()) ? i18n("[This message was deleted]")
: i18n("[This message was deleted: %1]", evt.redactedBecause()->reason());
}
-
return eventHandler.getRichBody();
}
diff --git a/src/models/messagefiltermodel.cpp b/src/models/messagefiltermodel.cpp
index 2935ccc60..9d84235ee 100644
--- a/src/models/messagefiltermodel.cpp
+++ b/src/models/messagefiltermodel.cpp
@@ -8,14 +8,15 @@
#include "enums/delegatetype.h"
#include "messageeventmodel.h"
#include "neochatconfig.h"
+#include "timelinemodel.h"
using namespace Quotient;
-MessageFilterModel::MessageFilterModel(QObject *parent, MessageEventModel *sourceMessageModel)
+MessageFilterModel::MessageFilterModel(QObject *parent, TimelineModel *sourceModel)
: QSortFilterProxyModel(parent)
{
- Q_ASSERT(sourceMessageModel);
- setSourceModel(sourceMessageModel);
+ Q_ASSERT(sourceModel);
+ setSourceModel(sourceModel);
connect(NeoChatConfig::self(), &NeoChatConfig::ShowStateEventChanged, this, [this] {
invalidateFilter();
diff --git a/src/models/messagefiltermodel.h b/src/models/messagefiltermodel.h
index c50e4c174..768eb95bb 100644
--- a/src/models/messagefiltermodel.h
+++ b/src/models/messagefiltermodel.h
@@ -7,6 +7,7 @@
#include
#include "messageeventmodel.h"
+#include "timelinemodel.h"
/**
* @class MessageFilterModel
@@ -36,7 +37,7 @@ public:
LastRole, // Keep this last
};
- explicit MessageFilterModel(QObject *parent = nullptr, MessageEventModel *sourceMessageModel = nullptr);
+ explicit MessageFilterModel(QObject *parent = nullptr, TimelineModel *sourceModel = nullptr);
/**
* @brief Custom filter function to remove hidden messages.
diff --git a/src/models/timelinemodel.cpp b/src/models/timelinemodel.cpp
new file mode 100644
index 000000000..a8918d448
--- /dev/null
+++ b/src/models/timelinemodel.cpp
@@ -0,0 +1,95 @@
+// SPDX-FileCopyrightText: 2022 James Graham
+// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+
+#include "timelinemodel.h"
+
+#include "delegatetype.h"
+
+TimelineModel::TimelineModel(QObject *parent)
+ : QConcatenateTablesProxyModel(parent)
+{
+ m_messageEventModel = new MessageEventModel(this);
+ addSourceModel(m_messageEventModel);
+ m_timelineEndModel = new TimelineEndModel(this);
+ addSourceModel(m_timelineEndModel);
+}
+
+NeoChatRoom *TimelineModel::room() const
+{
+ return m_messageEventModel->room();
+}
+
+void TimelineModel::setRoom(NeoChatRoom *room)
+{
+ // Both models do their own null checking so just pass along.
+ m_messageEventModel->setRoom(room);
+ m_timelineEndModel->setRoom(room);
+}
+
+MessageEventModel *TimelineModel::messageEventModel() const
+{
+ return m_messageEventModel;
+}
+
+QHash TimelineModel::roleNames() const
+{
+ return m_messageEventModel->roleNames();
+}
+
+TimelineEndModel::TimelineEndModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void TimelineEndModel::setRoom(NeoChatRoom *room)
+{
+ if (room == m_room) {
+ return;
+ }
+
+ beginResetModel();
+
+ if (m_room != nullptr) {
+ m_room->disconnect(this);
+ }
+
+ m_room = room;
+
+ if (m_room != nullptr) {
+ connect(m_room, &Quotient::Room::eventsHistoryJobChanged, this, [this]() {
+ if (m_room->allHistoryLoaded()) {
+ // HACK: We have to do it this way because DelegateChooser doesn't update dynamically.
+ beginRemoveRows({}, 0, 0);
+ endRemoveRows();
+ beginInsertRows({}, 0, 0);
+ endInsertRows();
+ }
+ });
+ }
+
+ endResetModel();
+}
+
+QVariant TimelineEndModel::data(const QModelIndex &idx, int role) const
+{
+ Q_UNUSED(idx)
+ if (m_room == nullptr) {
+ return {};
+ }
+
+ if (role == DelegateTypeRole) {
+ return m_room->allHistoryLoaded() ? DelegateType::TimelineEnd : DelegateType::Loading;
+ }
+ return {};
+}
+
+int TimelineEndModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return 1;
+}
+
+QHash TimelineEndModel::roleNames() const
+{
+ return {{DelegateTypeRole, "delegateType"}};
+}
diff --git a/src/models/timelinemodel.h b/src/models/timelinemodel.h
new file mode 100644
index 000000000..1c8f993ba
--- /dev/null
+++ b/src/models/timelinemodel.h
@@ -0,0 +1,112 @@
+// SPDX-FileCopyrightText: 2022 James Graham
+// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+
+#pragma once
+
+#include
+#include
+#include
+
+#include "messageeventmodel.h"
+#include "neochatroom.h"
+
+/**
+ * @class TimelineEndModel
+ *
+ * A model to provide a single delegate to mark the end of the timeline.
+ *
+ * The delegate will either be a loading delegate if more events are being loaded
+ * or a timeline end delegate if all history is loaded.
+ */
+class TimelineEndModel : public QAbstractListModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ /**
+ * @brief Defines the model roles.
+ */
+ enum Roles {
+ DelegateTypeRole = MessageEventModel::DelegateTypeRole, /**< The delegate type of the message. */
+ };
+ Q_ENUM(Roles)
+
+ explicit TimelineEndModel(QObject *parent = nullptr);
+
+ /**
+ * @brief Set the room for the timeline.
+ */
+ void setRoom(NeoChatRoom *room);
+
+ /**
+ * @brief Get the given role value at the given index.
+ *
+ * @sa QAbstractItemModel::data
+ */
+ [[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
+
+ /**
+ * @brief 1, the answer is always 1.
+ *
+ * @sa QAbstractItemModel::rowCount
+ */
+ [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ /**
+ * @brief Returns a map with DelegateTypeRole it's the only one.
+ *
+ * @sa Roles, QAbstractItemModel::roleNames()
+ */
+ [[nodiscard]] QHash roleNames() const override;
+
+private:
+ NeoChatRoom *m_room = nullptr;
+};
+
+/**
+ * @class TimelineModel
+ *
+ * A model to visualise a room timeline.
+ *
+ * This model combines a MessageEventModel with a TimelineEndModel.
+ *
+ * @sa MessageEventModel, TimelineEndModel
+ */
+class TimelineModel : public QConcatenateTablesProxyModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+ /**
+ * @brief The current room that the model is getting its messages from.
+ */
+ Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
+
+ /**
+ * @brief The MessageEventModel for the timeline.
+ */
+ Q_PROPERTY(MessageEventModel *messageEventModel READ messageEventModel CONSTANT)
+
+public:
+ TimelineModel(QObject *parent = nullptr);
+
+ [[nodiscard]] NeoChatRoom *room() const;
+ void setRoom(NeoChatRoom *room);
+
+ MessageEventModel *messageEventModel() const;
+
+ /**
+ * @brief Returns a mapping from Role enum values to role names.
+ *
+ * @sa Roles, QAbstractProxyModel::roleNames()
+ */
+ [[nodiscard]] QHash roleNames() const override;
+
+Q_SIGNALS:
+ void roomChanged();
+
+private:
+ MessageEventModel *m_messageEventModel = nullptr;
+ TimelineEndModel *m_timelineEndModel = nullptr;
+};
diff --git a/src/qml/EventDelegate.qml b/src/qml/EventDelegate.qml
index cc0965f17..65f04b554 100644
--- a/src/qml/EventDelegate.qml
+++ b/src/qml/EventDelegate.qml
@@ -99,6 +99,7 @@ DelegateChooser {
connection: root.connection
}
}
+
DelegateChoice {
roleValue: DelegateType.LiveLocation
delegate: LiveLocationDelegate {
@@ -107,6 +108,18 @@ DelegateChooser {
}
}
+ DelegateChoice {
+ roleValue: DelegateType.Loading
+ delegate: LoadingDelegate {}
+ }
+
+ DelegateChoice {
+ roleValue: DelegateType.TimelineEnd
+ delegate: TimelineEndDelegate {
+ room: root.room
+ }
+ }
+
DelegateChoice {
roleValue: DelegateType.Other
delegate: Item {}
diff --git a/src/qml/LoadingDelegate.qml b/src/qml/LoadingDelegate.qml
new file mode 100644
index 000000000..2bb94631a
--- /dev/null
+++ b/src/qml/LoadingDelegate.qml
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2023 James Graham
+// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+
+import QtQuick
+
+import org.kde.kirigami as Kirigami
+
+import org.kde.neochat
+
+TimelineDelegate {
+ id: root
+ contentItem: Kirigami.PlaceholderMessage {
+ text: i18n("Loading…")
+ }
+}
diff --git a/src/qml/RoomPage.qml b/src/qml/RoomPage.qml
index fe06245d5..413c587f5 100644
--- a/src/qml/RoomPage.qml
+++ b/src/qml/RoomPage.qml
@@ -23,17 +23,17 @@ Kirigami.Page {
required property NeoChatConnection connection
/**
- * @brief The MessageEventModel to use.
+ * @brief The TimelineModel to use.
*
* Required so that new events can be requested when the end of the current
* local timeline is reached.
*
* @note For loading a room in a different window, override this with a new
- * MessageEventModel set with the room to be shown.
+ * TimelineModel set with the room to be shown.
*
- * @sa MessageEventModel
+ * @sa TimelineModel
*/
- property MessageEventModel messageEventModel: RoomManager.messageEventModel
+ property TimelineModel timelineModel: RoomManager.timelineModel
/**
* @brief The MessageFilterModel to use.
@@ -41,9 +41,9 @@ Kirigami.Page {
* This model has the filtered list of events that should be shown in the timeline.
*
* @note For loading a room in a different window, override this with a new
- * MessageFilterModel with the new MessageEventModel as the source model.
+ * MessageFilterModel with the new TimelineModel as the source model.
*
- * @sa MessageEventModel, MessageFilterModel
+ * @sa TimelineModel, MessageFilterModel
*/
property MessageFilterModel messageFilterModel: RoomManager.messageFilterModel
@@ -56,7 +56,7 @@ Kirigami.Page {
* @note For loading a room in a different window, override this with a new
* MediaMessageFilterModel with the new MessageFilterModel as the source model.
*
- * @sa MessageEventModel, MessageFilterModel
+ * @sa TimelineModel, MessageFilterModel
*/
property MediaMessageFilterModel mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
@@ -120,7 +120,7 @@ Kirigami.Page {
sourceComponent: TimelineView {
id: timelineView
currentRoom: root.currentRoom
- messageEventModel: root.messageEventModel
+ timelineModel: root.timelineModel
messageFilterModel: root.messageFilterModel
actionsHandler: root.actionsHandler
onFocusChatBar: {
diff --git a/src/qml/RoomWindow.qml b/src/qml/RoomWindow.qml
index 974da13b0..ab880fb5b 100644
--- a/src/qml/RoomWindow.qml
+++ b/src/qml/RoomWindow.qml
@@ -29,7 +29,7 @@ Kirigami.ApplicationWindow {
disableCancelShortcut: true
connection: root.connection
- messageEventModel: MessageEventModel {
+ timelineModel: TimelineModel {
room: currentRoom
}
messageFilterModel: MessageFilterModel {
diff --git a/src/qml/TimelineEndDelegate.qml b/src/qml/TimelineEndDelegate.qml
new file mode 100644
index 000000000..82e98873f
--- /dev/null
+++ b/src/qml/TimelineEndDelegate.qml
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: 2023 James Graham
+// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
+
+import QtQuick
+import QtQuick.Layouts
+
+import org.kde.kirigami as Kirigami
+import org.kde.kirigamiaddons.labs.components as KirigamiComponents
+
+import org.kde.neochat
+
+TimelineDelegate {
+ id: root
+
+ /**
+ * @brief The current room that user is viewing.
+ */
+ required property NeoChatRoom room
+
+ contentItem: ColumnLayout {
+ RowLayout {
+ Layout.topMargin: Kirigami.Units.largeSpacing
+ Layout.bottomMargin: Kirigami.Units.largeSpacing
+ Layout.leftMargin: Kirigami.Units.largeSpacing
+ Layout.rightMargin: Kirigami.Units.largeSpacing
+ spacing: Kirigami.Units.largeSpacing
+
+ KirigamiComponents.Avatar {
+ Layout.preferredWidth: Kirigami.Units.iconSizes.large
+ Layout.preferredHeight: Kirigami.Units.iconSizes.large
+
+ name: root.room ? root.room.displayName : ""
+ source: root.room && root.room.avatarMediaId ? ("image://mxc/" + root.room.avatarMediaId) : ""
+
+ Rectangle {
+ visible: room.usesEncryption
+ color: Kirigami.Theme.backgroundColor
+
+ width: Kirigami.Units.gridUnit
+ height: Kirigami.Units.gridUnit
+
+ anchors {
+ bottom: parent.bottom
+ right: parent.right
+ }
+
+ radius: Math.round(width / 2)
+
+ Kirigami.Icon {
+ source: "channel-secure-symbolic"
+ anchors.fill: parent
+ }
+ }
+ }
+
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+ spacing: 0
+
+ Kirigami.Heading {
+ Layout.fillWidth: true
+ text: root.room ? root.room.displayName : i18n("No name")
+ textFormat: Text.PlainText
+ wrapMode: Text.Wrap
+ }
+
+ Kirigami.SelectableLabel {
+ Layout.fillWidth: true
+ font: Kirigami.Theme.smallFont
+ textFormat: TextEdit.PlainText
+ visible: root.room && root.room.canonicalAlias
+ text: root.room && root.room.canonicalAlias ? root.room.canonicalAlias : ""
+ }
+ }
+ }
+
+ Kirigami.SelectableLabel {
+ Layout.fillWidth: true
+ Layout.leftMargin: Kirigami.Units.largeSpacing
+ Layout.rightMargin: Kirigami.Units.largeSpacing
+ Layout.bottomMargin: Kirigami.Units.largeSpacing
+
+ text: i18n("This is the beginning of the chat. There are no historical messages beyond this point.")
+ wrapMode: Text.Wrap
+ onLinkActivated: link => UrlHelper.openUrl(link)
+ }
+ }
+}
diff --git a/src/qml/TimelineView.qml b/src/qml/TimelineView.qml
index 4ad5c570a..239bb228a 100644
--- a/src/qml/TimelineView.qml
+++ b/src/qml/TimelineView.qml
@@ -28,12 +28,12 @@ QQC2.ScrollView {
property bool roomChanging: false
/**
- * @brief The MessageEventModel to use.
+ * @brief The TimelineModel to use.
*
* Required so that new events can be requested when the end of the current
* local timeline is reached.
*/
- required property MessageEventModel messageEventModel
+ required property TimelineModel timelineModel
/**
* @brief The MessageFilterModel to use.
@@ -85,16 +85,16 @@ QQC2.ScrollView {
running: messageListView.atYBeginning
triggeredOnStart: true
onTriggered: {
- if (messageListView.atYBeginning && root.messageEventModel.canFetchMore(root.messageEventModel.index(0, 0))) {
- root.messageEventModel.fetchMore(root.messageEventModel.index(0, 0));
+ if (messageListView.atYBeginning && root.timelineModel.messageEventModel.canFetchMore(root.timelineModel.index(0, 0))) {
+ root.timelineModel.messageEventModel.fetchMore(root.timelineModel.index(0, 0));
}
}
repeat: true
}
// HACK: The view should do this automatically but doesn't.
- onAtYBeginningChanged: if (atYBeginning && root.messageEventModel.canFetchMore(root.messageEventModel.index(0, 0))) {
- root.messageEventModel.fetchMore(root.messageEventModel.index(0, 0));
+ onAtYBeginningChanged: if (atYBeginning && root.timelineModel.messageEventModel.canFetchMore(root.timelineModel.index(0, 0))) {
+ root.timelineModel.messageEventModel.fetchMore(root.timelineModel.index(0, 0));
}
Timer {
@@ -270,7 +270,7 @@ QQC2.ScrollView {
}
Connections {
- target: root.messageEventModel
+ target: root.timelineModel
function onRowsInserted() {
markReadIfVisibleTimer.restart()
@@ -311,7 +311,7 @@ QQC2.ScrollView {
Connections {
//enabled: Config.showFancyEffects
- target: root.messageEventModel
+ target: root.timelineModel.messageEventModel
function onFancyEffectsReasonFound(fancyEffect) {
fancyEffectsContainer.processFancyEffectsReason(fancyEffect)
@@ -336,10 +336,10 @@ QQC2.ScrollView {
}
function eventToIndex(eventID) {
- const index = root.messageEventModel.eventIdToRow(eventID)
+ const index = root.timelineModel.messageEventModel.eventIdToRow(eventID)
if (index === -1)
return -1
- return root.messageFilterModel.mapFromSource(root.messageEventModel.index(index, 0)).row
+ return root.messageFilterModel.mapFromSource(root.timelineModel.index(index, 0)).row
}
function firstVisibleIndex() {
diff --git a/src/roommanager.cpp b/src/roommanager.cpp
index c867ac482..a875f820e 100644
--- a/src/roommanager.cpp
+++ b/src/roommanager.cpp
@@ -8,8 +8,10 @@
#include "controller.h"
#include "enums/delegatetype.h"
#include "models/messageeventmodel.h"
+#include "models/timelinemodel.h"
#include "neochatconfig.h"
#include "neochatroom.h"
+
#include
#include
#include
@@ -29,14 +31,14 @@ RoomManager::RoomManager(QObject *parent)
, m_currentRoom(nullptr)
, m_lastCurrentRoom(nullptr)
, m_config(KSharedConfig::openStateConfig())
- , m_messageEventModel(new MessageEventModel(this))
- , m_messageFilterModel(new MessageFilterModel(this, m_messageEventModel))
+ , m_timelineModel(new TimelineModel(this))
+ , m_messageFilterModel(new MessageFilterModel(this, m_timelineModel))
, m_mediaMessageFilterModel(new MediaMessageFilterModel(this, m_messageFilterModel))
{
m_lastRoomConfig = m_config->group(QStringLiteral("LastOpenRoom"));
connect(this, &RoomManager::currentRoomChanged, this, [this]() {
- m_messageEventModel->setRoom(m_currentRoom);
+ m_timelineModel->setRoom(m_currentRoom);
});
}
@@ -55,9 +57,9 @@ NeoChatRoom *RoomManager::currentRoom() const
return m_currentRoom;
}
-MessageEventModel *RoomManager::messageEventModel() const
+TimelineModel *RoomManager::timelineModel() const
{
- return m_messageEventModel;
+ return m_timelineModel;
}
MessageFilterModel *RoomManager::messageFilterModel() const
diff --git a/src/roommanager.h b/src/roommanager.h
index 55c9b8d76..ff53b4de1 100644
--- a/src/roommanager.h
+++ b/src/roommanager.h
@@ -15,6 +15,7 @@
#include "models/mediamessagefiltermodel.h"
#include "models/messageeventmodel.h"
#include "models/messagefiltermodel.h"
+#include "models/timelinemodel.h"
class NeoChatRoom;
class NeoChatConnection;
@@ -48,7 +49,7 @@ class RoomManager : public QObject, public UriResolverBase
Q_PROPERTY(NeoChatRoom *currentRoom READ currentRoom NOTIFY currentRoomChanged)
/**
- * @brief The MessageEventModel that should be used for room message visualisation.
+ * @brief The TimelineModel that should be used for room message visualisation.
*
* The room object the model uses to get the data will be updated by this class
* so there is no need to do this manually or replace the model when a room
@@ -57,7 +58,7 @@ class RoomManager : public QObject, public UriResolverBase
* @note Available here so that the room page and drawer both have access to the
* same model.
*/
- Q_PROPERTY(MessageEventModel *messageEventModel READ messageEventModel CONSTANT)
+ Q_PROPERTY(TimelineModel *timelineModel READ timelineModel CONSTANT)
/**
* @brief The MessageFilterModel that should be used for room message visualisation.
@@ -101,7 +102,7 @@ public:
NeoChatRoom *currentRoom() const;
- MessageEventModel *messageEventModel() const;
+ TimelineModel *timelineModel() const;
MessageFilterModel *messageFilterModel() const;
MediaMessageFilterModel *mediaMessageFilterModel() const;
@@ -383,7 +384,7 @@ private:
KConfigGroup m_lastRoomConfig;
QPointer m_chatDocumentHandler;
- MessageEventModel *m_messageEventModel;
+ TimelineModel *m_timelineModel;
MessageFilterModel *m_messageFilterModel;
MediaMessageFilterModel *m_mediaMessageFilterModel;
NeoChatConnection *m_connection;