diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index 1716d2d4..ae18d505 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -18,6 +18,10 @@ Item { roleValue: model.data.type anchors.fill: parent + DelegateChoice { + roleValue: MtxEvent.UnknownMessage + Placeholder { text: "Unretrieved event" } + } DelegateChoice { roleValue: MtxEvent.TextMessage TextMessage {} diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 41d864bd..a1367bf3 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -70,8 +70,9 @@ struct RoomEventType case EventType::Tag: return qml_mtx_events::EventType::Tag; case EventType::Unsupported: - default: return qml_mtx_events::EventType::Unsupported; + default: + return qml_mtx_events::EventType::UnknownMessage; } } qml_mtx_events::EventType operator()(const mtx::events::Event &) @@ -175,6 +176,17 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj connect( this, &TimelineModel::nextPendingMessage, this, &TimelineModel::processOnePendingMessage); connect(this, &TimelineModel::newMessageToSend, this, &TimelineModel::addPendingMessage); + + connect(this, + &TimelineModel::replyFetched, + this, + [this](QString requestingEvent, mtx::events::collections::TimelineEvents event) { + events.insert(QString::fromStdString(mtx::accessors::event_id(event)), + event); + auto idx = idToIndex(requestingEvent); + if (idx >= 0) + emit dataChanged(index(idx, 0), index(idx, 0)); + }); } QHash @@ -216,20 +228,15 @@ QVariantMap TimelineModel::getDump(QString eventId) const { if (events.contains(eventId)) - return data(index(idToIndex(eventId), 0), Dump).toMap(); + return data(eventId, Dump).toMap(); return {}; } QVariant -TimelineModel::data(const QModelIndex &index, int role) const +TimelineModel::data(const QString &id, int role) const { using namespace mtx::accessors; - namespace acc = mtx::accessors; - if (index.row() < 0 && index.row() >= (int)eventOrder.size()) - return QVariant(); - - QString id = eventOrder[index.row()]; - + namespace acc = mtx::accessors; mtx::events::collections::TimelineEvents event = events.value(id); if (auto e = @@ -238,28 +245,6 @@ TimelineModel::data(const QModelIndex &index, int role) const } switch (role) { - case Section: { - QDateTime date = origin_server_ts(event); - date.setTime(QTime()); - - std::string userId = acc::sender(event); - - for (size_t r = index.row() + 1; r < eventOrder.size(); r++) { - auto tempEv = events.value(eventOrder[r]); - QDateTime prevDate = origin_server_ts(tempEv); - prevDate.setTime(QTime()); - if (prevDate != date) - return QString("%2 %1") - .arg(date.toMSecsSinceEpoch()) - .arg(QString::fromStdString(userId)); - - std::string prevUserId = acc::sender(tempEv); - if (userId != prevUserId) - break; - } - - return QString("%1").arg(QString::fromStdString(userId)); - } case UserId: return QVariant(QString::fromStdString(acc::sender(event))); case UserName: @@ -329,28 +314,27 @@ TimelineModel::data(const QModelIndex &index, int role) const QVariantMap m; auto names = roleNames(); - // m.insert(names[Section], data(index, static_cast(Section))); - m.insert(names[Type], data(index, static_cast(Type))); - m.insert(names[Body], data(index, static_cast(Body))); - m.insert(names[FormattedBody], data(index, static_cast(FormattedBody))); - m.insert(names[UserId], data(index, static_cast(UserId))); - m.insert(names[UserName], data(index, static_cast(UserName))); - m.insert(names[Timestamp], data(index, static_cast(Timestamp))); - m.insert(names[Url], data(index, static_cast(Url))); - m.insert(names[ThumbnailUrl], data(index, static_cast(ThumbnailUrl))); - m.insert(names[Filename], data(index, static_cast(Filename))); - m.insert(names[Filesize], data(index, static_cast(Filesize))); - m.insert(names[MimeType], data(index, static_cast(MimeType))); - m.insert(names[Height], data(index, static_cast(Height))); - m.insert(names[Width], data(index, static_cast(Width))); - m.insert(names[ProportionalHeight], - data(index, static_cast(ProportionalHeight))); - m.insert(names[Id], data(index, static_cast(Id))); - m.insert(names[State], data(index, static_cast(State))); - m.insert(names[IsEncrypted], data(index, static_cast(IsEncrypted))); - m.insert(names[ReplyTo], data(index, static_cast(ReplyTo))); - m.insert(names[RoomName], data(index, static_cast(RoomName))); - m.insert(names[RoomTopic], data(index, static_cast(RoomTopic))); + // m.insert(names[Section], data(id, static_cast(Section))); + m.insert(names[Type], data(id, static_cast(Type))); + m.insert(names[Body], data(id, static_cast(Body))); + m.insert(names[FormattedBody], data(id, static_cast(FormattedBody))); + m.insert(names[UserId], data(id, static_cast(UserId))); + m.insert(names[UserName], data(id, static_cast(UserName))); + m.insert(names[Timestamp], data(id, static_cast(Timestamp))); + m.insert(names[Url], data(id, static_cast(Url))); + m.insert(names[ThumbnailUrl], data(id, static_cast(ThumbnailUrl))); + m.insert(names[Filename], data(id, static_cast(Filename))); + m.insert(names[Filesize], data(id, static_cast(Filesize))); + m.insert(names[MimeType], data(id, static_cast(MimeType))); + m.insert(names[Height], data(id, static_cast(Height))); + m.insert(names[Width], data(id, static_cast(Width))); + m.insert(names[ProportionalHeight], data(id, static_cast(ProportionalHeight))); + m.insert(names[Id], data(id, static_cast(Id))); + m.insert(names[State], data(id, static_cast(State))); + m.insert(names[IsEncrypted], data(id, static_cast(IsEncrypted))); + m.insert(names[ReplyTo], data(id, static_cast(ReplyTo))); + m.insert(names[RoomName], data(id, static_cast(RoomName))); + m.insert(names[RoomTopic], data(id, static_cast(RoomTopic))); return QVariant(m); } @@ -359,6 +343,44 @@ TimelineModel::data(const QModelIndex &index, int role) const } } +QVariant +TimelineModel::data(const QModelIndex &index, int role) const +{ + using namespace mtx::accessors; + namespace acc = mtx::accessors; + if (index.row() < 0 && index.row() >= (int)eventOrder.size()) + return QVariant(); + + QString id = eventOrder[index.row()]; + + mtx::events::collections::TimelineEvents event = events.value(id); + + if (role == Section) { + QDateTime date = origin_server_ts(event); + date.setTime(QTime()); + + std::string userId = acc::sender(event); + + for (size_t r = index.row() + 1; r < eventOrder.size(); r++) { + auto tempEv = events.value(eventOrder[r]); + QDateTime prevDate = origin_server_ts(tempEv); + prevDate.setTime(QTime()); + if (prevDate != date) + return QString("%2 %1") + .arg(date.toMSecsSinceEpoch()) + .arg(QString::fromStdString(userId)); + + std::string prevUserId = acc::sender(tempEv); + if (userId != prevUserId) + break; + } + + return QString("%1").arg(QString::fromStdString(userId)); + } + + return data(id, role); +} + bool TimelineModel::canFetchMore(const QModelIndex &) const { @@ -515,6 +537,27 @@ TimelineModel::internalAddEvents( this->events.insert(id, e); ids.push_back(id); + + auto replyTo = mtx::accessors::in_reply_to_event(e); + auto qReplyTo = QString::fromStdString(replyTo); + if (!replyTo.empty() && !events.contains(qReplyTo)) { + http::client()->get_event( + this->room_id_.toStdString(), + replyTo, + [this, id, replyTo]( + const mtx::events::collections::TimelineEvents &timeline, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->error( + "Failed to retrieve event with id {}, which was " + "requested to show the replyTo for event {}", + replyTo, + id.toStdString()); + return; + } + emit replyFetched(id, timeline); + }); + } } return ids; } diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 61dd6b69..ae505c17 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -153,6 +153,7 @@ public: QHash roleNames() const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant data(const QString &id, int role) const; bool canFetchMore(const QModelIndex &) const override; void fetchMore(const QModelIndex &) override; @@ -200,6 +201,7 @@ signals: void newMessageToSend(mtx::events::collections::TimelineEvents event); void mediaCached(QString mxcUrl, QString cacheUrl); void newEncryptedImage(mtx::crypto::EncryptedFile encryptionInfo); + void replyFetched(QString requestingEvent, mtx::events::collections::TimelineEvents event); private: DecryptionResult decryptEvent( diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 74e09a33..8cb204a6 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -12,6 +12,8 @@ #include "UserSettingsPage.h" #include "dialogs/ImageOverlay.h" +Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) + void TimelineViewManager::updateColorPalette() { @@ -59,6 +61,7 @@ TimelineViewManager::TimelineViewManager(QWidget *parent) "Can't instantiate enum!"); qmlRegisterType("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType("im.nheko", 1, 0, "DelegateChooser"); + qRegisterMetaType(); #ifdef USE_QUICK_VIEW view = new QQuickView();