diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index fcf88167..3d4c1147 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -9,12 +9,6 @@ Rectangle { text: qsTr("No room open") font.pointSize: 24 } - Text { - visible: timelineManager.timeline != null - anchors.centerIn: parent - text: qsTr("room open") - font.pointSize: 24 - } ListView { visible: timelineManager.timeline != null diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp index b13a1e6a..10a5d3bf 100644 --- a/src/timeline2/TimelineModel.cpp +++ b/src/timeline2/TimelineModel.cpp @@ -24,6 +24,14 @@ senderId(const T &event) } } +TimelineModel::TimelineModel(QString room_id, QObject *parent) + : QAbstractListModel(parent) + , room_id_(room_id) +{ + connect( + this, &TimelineModel::oldMessagesRetrieved, this, &TimelineModel::addBackwardsEvents); +} + QHash TimelineModel::roleNames() const { @@ -65,6 +73,11 @@ TimelineModel::data(const QModelIndex &index, int role) const void TimelineModel::addEvents(const mtx::responses::Timeline &events) { + if (isInitialSync) { + prev_batch_token_ = QString::fromStdString(events.prev_batch); + isInitialSync = false; + } + nhlog::ui()->info("add {} events", events.events.size()); std::vector ids; for (const auto &e : events.events) { @@ -83,6 +96,58 @@ TimelineModel::addEvents(const mtx::responses::Timeline &events) endInsertRows(); } +void +TimelineModel::fetchHistory() +{ + if (paginationInProgress) { + nhlog::ui()->warn("Already loading older messages"); + return; + } + + paginationInProgress = true; + mtx::http::MessagesOpts opts; + opts.room_id = room_id_.toStdString(); + opts.from = prev_batch_token_.toStdString(); + + nhlog::ui()->info("Paginationg room {}", opts.room_id); + + http::client()->messages( + opts, [this, opts](const mtx::responses::Messages &res, mtx::http::RequestErr err) { + if (err) { + nhlog::net()->error("failed to call /messages ({}): {} - {}", + opts.room_id, + mtx::errors::to_string(err->matrix_error.errcode), + err->matrix_error.error); + return; + } + + emit oldMessagesRetrieved(std::move(res)); + }); +} + +void +TimelineModel::addBackwardsEvents(const mtx::responses::Messages &msgs) +{ + nhlog::ui()->info("add {} backwards events", msgs.chunk.size()); + std::vector ids; + for (const auto &e : msgs.chunk) { + QString id = + boost::apply_visitor([](const auto &e) -> QString { return eventId(e); }, e); + + this->events.insert(id, e); + ids.push_back(id); + nhlog::ui()->info("add event {}", id.toStdString()); + } + + beginInsertRows(QModelIndex(), 0, static_cast(ids.size() - 1)); + this->eventOrder.insert(this->eventOrder.begin(), ids.rbegin(), ids.rend()); + endInsertRows(); + + prev_batch_token_ = QString::fromStdString(msgs.end); + + paginationInProgress = false; +} + QColor TimelineModel::userColor(QString id, QColor background) { diff --git a/src/timeline2/TimelineModel.h b/src/timeline2/TimelineModel.h index 2252621c..a4224538 100644 --- a/src/timeline2/TimelineModel.h +++ b/src/timeline2/TimelineModel.h @@ -11,9 +11,7 @@ class TimelineModel : public QAbstractListModel Q_OBJECT public: - explicit TimelineModel(QObject *parent = 0) - : QAbstractListModel(parent) - {} + explicit TimelineModel(QString room_id, QObject *parent = 0); enum Roles { @@ -31,12 +29,29 @@ public: Q_INVOKABLE QColor userColor(QString id, QColor background); + void addEvents(const mtx::responses::Timeline &events); +public slots: + void fetchHistory(); + +private slots: + // Add old events at the top of the timeline. + void addBackwardsEvents(const mtx::responses::Messages &msgs); + +signals: + void oldMessagesRetrieved(const mtx::responses::Messages &res); + private: QHash events; std::vector eventOrder; + QString room_id_; + QString prev_batch_token_; + + bool isInitialSync = true; + bool paginationInProgress = false; + QHash userColors; }; diff --git a/src/timeline2/TimelineViewManager.cpp b/src/timeline2/TimelineViewManager.cpp index 0468fc2a..32321fd2 100644 --- a/src/timeline2/TimelineViewManager.cpp +++ b/src/timeline2/TimelineViewManager.cpp @@ -27,7 +27,7 @@ void TimelineViewManager::addRoom(const QString &room_id) { if (!models.contains(room_id)) - models.insert(room_id, QSharedPointer(new TimelineModel())); + models.insert(room_id, QSharedPointer(new TimelineModel(room_id))); } void @@ -38,6 +38,7 @@ TimelineViewManager::setHistoryView(const QString &room_id) auto room = models.find(room_id); if (room != models.end()) { timeline_ = room.value().get(); + timeline_->fetchHistory(); emit activeTimelineChanged(timeline_); nhlog::ui()->info("Activated room {}", room_id.toStdString()); }