diff --git a/include/ChatPage.h b/include/ChatPage.h
index c753aa97..cd516a71 100644
--- a/include/ChatPage.h
+++ b/include/ChatPage.h
@@ -72,6 +72,10 @@ public:
{
client_->readEvent(room_id, event_id);
}
+ void redactEvent(const QString &room_id, const QString &event_id)
+ {
+ client_->redactEvent(room_id, event_id);
+ }
QSharedPointer<UserSettings> userSettings() { return userSettings_; }
diff --git a/include/MatrixClient.h b/include/MatrixClient.h
index 69fa72bc..3052a118 100644
--- a/include/MatrixClient.h
+++ b/include/MatrixClient.h
@@ -86,6 +86,7 @@ public:
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
void removeTypingNotification(const QString &roomid);
void readEvent(const QString &room_id, const QString &event_id);
+ void redactEvent(const QString &room_id, const QString &event_id);
void inviteUser(const QString &room_id, const QString &user);
void createRoom(const mtx::requests::CreateRoom &request);
@@ -171,6 +172,9 @@ signals:
void leftRoom(const QString &room_id);
void roomCreationFailed(const QString &msg);
+ void redactionFailed(const QString &error);
+ void redactionCompleted(const QString &room_id, const QString &event_id);
+
private:
QNetworkReply *makeUploadRequest(QSharedPointer<QIODevice> iodev);
QJsonObject getUploadReply(QNetworkReply *reply);
diff --git a/include/timeline/TimelineItem.h b/include/timeline/TimelineItem.h
index 7c04e167..ade2f834 100644
--- a/include/timeline/TimelineItem.h
+++ b/include/timeline/TimelineItem.h
@@ -93,6 +93,9 @@ public:
ChatPage::instance()->readEvent(room_id_, event_id_);
}
+ //! Add a user avatar for this event.
+ void addAvatar();
+
protected:
void paintEvent(QPaintEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
@@ -130,20 +133,18 @@ private:
QMenu *contextMenu_;
QAction *showReadReceipts_;
QAction *markAsRead_;
+ QAction *redactMsg_;
- QHBoxLayout *topLayout_;
- //! The message and the timestamp/checkmark.
- QHBoxLayout *messageLayout_;
- //! Avatar or Timestamp
- QVBoxLayout *sideLayout_;
- //! Header & Message body
- QVBoxLayout *mainLayout_;
-
- QVBoxLayout *headerLayout_; // Username (&) Timestamp
+ QHBoxLayout *topLayout_ = nullptr;
+ QHBoxLayout *messageLayout_ = nullptr;
+ QVBoxLayout *mainLayout_ = nullptr;
+ QVBoxLayout *headerLayout_ = nullptr;
+ QHBoxLayout *widgetLayout_ = nullptr;
Avatar *userAvatar_;
QFont font_;
+ QFont usernameFont_;
QLabel *timestamp_;
QLabel *checkmark_;
@@ -169,26 +170,23 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget,
generateTimestamp(timestamp);
- auto widgetLayout = new QHBoxLayout();
- widgetLayout->setContentsMargins(0, 5, 0, 0);
- widgetLayout->addWidget(widget);
- widgetLayout->addStretch(1);
-
- messageLayout_->setContentsMargins(0, 0, 20, 4);
- messageLayout_->setSpacing(20);
+ widgetLayout_ = new QHBoxLayout;
+ widgetLayout_->setContentsMargins(0, 5, 0, 0);
+ widgetLayout_->addWidget(widget);
+ widgetLayout_->addStretch(1);
if (withSender) {
generateBody(displayName, "");
setupAvatarLayout(displayName);
- headerLayout_->addLayout(widgetLayout);
+ headerLayout_->addLayout(widgetLayout_);
messageLayout_->addLayout(headerLayout_, 1);
AvatarProvider::resolve(userid, [this](const QImage &img) { setUserAvatar(img); });
} else {
setupSimpleLayout();
- messageLayout_->addLayout(widgetLayout, 1);
+ messageLayout_->addLayout(widgetLayout_, 1);
}
messageLayout_->addWidget(checkmark_);
@@ -220,26 +218,23 @@ TimelineItem::setupWidgetLayout(Widget *widget,
generateTimestamp(timestamp);
- auto widgetLayout = new QHBoxLayout();
- widgetLayout->setContentsMargins(0, 5, 0, 0);
- widgetLayout->addWidget(widget);
- widgetLayout->addStretch(1);
-
- messageLayout_->setContentsMargins(0, 0, 20, 4);
- messageLayout_->setSpacing(20);
+ widgetLayout_ = new QHBoxLayout();
+ widgetLayout_->setContentsMargins(0, 5, 0, 0);
+ widgetLayout_->addWidget(widget);
+ widgetLayout_->addStretch(1);
if (withSender) {
generateBody(displayName, "");
setupAvatarLayout(displayName);
- headerLayout_->addLayout(widgetLayout);
+ headerLayout_->addLayout(widgetLayout_);
messageLayout_->addLayout(headerLayout_, 1);
AvatarProvider::resolve(sender, [this](const QImage &img) { setUserAvatar(img); });
} else {
setupSimpleLayout();
- messageLayout_->addLayout(widgetLayout, 1);
+ messageLayout_->addLayout(widgetLayout_, 1);
}
messageLayout_->addWidget(checkmark_);
diff --git a/include/timeline/TimelineView.h b/include/timeline/TimelineView.h
index 2876cc60..78e092b3 100644
--- a/include/timeline/TimelineView.h
+++ b/include/timeline/TimelineView.h
@@ -101,6 +101,9 @@ public:
void scrollDown();
QLabel *createDateSeparator(QDateTime datetime);
+ //! Remove an item from the timeline with the given Event ID.
+ void removeEvent(const QString &event_id);
+
public slots:
void sliderRangeChanged(int min, int max);
void sliderMoved(int position);
@@ -128,6 +131,8 @@ protected:
private:
using TimelineEvent = mtx::events::collections::TimelineEvents;
+ QWidget *relativeWidget(TimelineItem *item, int dt) const;
+
//! HACK: Fixing layout flickering when adding to the bottom
//! of the timeline.
void pushTimelineItem(TimelineItem *item)
@@ -232,7 +237,7 @@ private:
inline bool isNotifiable(const TimelineEvent &event) const;
// The events currently rendered. Used for duplicate detection.
- QMap<QString, bool> eventIds_;
+ QMap<QString, TimelineItem *> eventIds_;
QQueue<PendingMessage> pending_msgs_;
QList<PendingMessage> pending_sent_msgs_;
QSharedPointer<MatrixClient> client_;
@@ -295,13 +300,9 @@ TimelineView::processMessageEvent(const Event &event, TimelineDirection directio
const auto event_id = QString::fromStdString(event.event_id);
const auto sender = QString::fromStdString(event.sender);
- if (isDuplicate(event_id))
- return nullptr;
-
- eventIds_[event_id] = true;
-
const QString txnid = QString::fromStdString(event.unsigned_data.transaction_id);
- if (!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) {
+ if ((!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) ||
+ isDuplicate(event_id)) {
removePendingMessage(txnid);
return nullptr;
}
@@ -310,7 +311,11 @@ TimelineView::processMessageEvent(const Event &event, TimelineDirection directio
updateLastSender(sender, direction);
- return createTimelineItem<Event>(event, with_sender);
+ auto item = createTimelineItem<Event>(event, with_sender);
+
+ eventIds_[event_id] = item;
+
+ return item;
}
template<class Event, class Widget>
@@ -320,13 +325,9 @@ TimelineView::processMessageEvent(const Event &event, TimelineDirection directio
const auto event_id = QString::fromStdString(event.event_id);
const auto sender = QString::fromStdString(event.sender);
- if (isDuplicate(event_id))
- return nullptr;
-
- eventIds_[event_id] = true;
-
const QString txnid = QString::fromStdString(event.unsigned_data.transaction_id);
- if (!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) {
+ if ((!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) ||
+ isDuplicate(event_id)) {
removePendingMessage(txnid);
return nullptr;
}
@@ -335,5 +336,9 @@ TimelineView::processMessageEvent(const Event &event, TimelineDirection directio
updateLastSender(sender, direction);
- return createTimelineItem<Event, Widget>(event, with_sender);
+ auto item = createTimelineItem<Event, Widget>(event, with_sender);
+
+ eventIds_[event_id] = item;
+
+ return item;
}
|