summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2017-11-24 00:10:58 +0200
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2017-11-24 00:10:58 +0200
commit0f363b5f4424cc4cdf0e36d7aa5b62b8e8ea52bc (patch)
treeb216baa489755bbb3343f350aa6c6d3e17725fba
parentc6cf6c2b4148c30f5e1dd0ff744baf0293cfe1ff (diff)
Send read receipts
Automatically dismiss unread notifications when the window regains focus. fixes #111 fixes #68
-rw-r--r--include/MatrixClient.h1
-rw-r--r--include/RoomList.h1
-rw-r--r--include/TimelineItem.h4
-rw-r--r--include/TimelineView.h5
-rw-r--r--include/TimelineViewManager.h1
-rw-r--r--src/ChatPage.cc5
-rw-r--r--src/MatrixClient.cc28
-rw-r--r--src/RoomList.cc16
-rw-r--r--src/TimelineItem.cc9
-rw-r--r--src/TimelineView.cc52
-rw-r--r--src/TimelineViewManager.cc8
11 files changed, 126 insertions, 4 deletions
diff --git a/include/MatrixClient.h b/include/MatrixClient.h
index 422e4cfa..999fbe47 100644
--- a/include/MatrixClient.h
+++ b/include/MatrixClient.h
@@ -59,6 +59,7 @@ public:
void leaveRoom(const QString &roomId);
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
void removeTypingNotification(const QString &roomid);
+ void readEvent(const QString &room_id, const QString &event_id);
QUrl getHomeServer() { return server_; };
int transactionId() { return txn_id_; };
diff --git a/include/RoomList.h b/include/RoomList.h
index f1653a38..7a48f7bd 100644
--- a/include/RoomList.h
+++ b/include/RoomList.h
@@ -66,6 +66,7 @@ public slots:
void closeJoinRoomDialog(bool isJoining, QString roomAlias);
void openLeaveRoomDialog(const QString &room_id);
void closeLeaveRoomDialog(bool leaving, const QString &room_id);
+ void clearRoomMessageCount(const QString &room_id);
private:
void calculateUnreadMessageCount();
diff --git a/include/TimelineItem.h b/include/TimelineItem.h
index d90810d5..cd522308 100644
--- a/include/TimelineItem.h
+++ b/include/TimelineItem.h
@@ -66,7 +66,8 @@ public:
QWidget *parent);
void setUserAvatar(const QImage &pixmap);
- DescInfo descriptionMessage() const { return descriptionMsg_; };
+ DescInfo descriptionMessage() const { return descriptionMsg_; }
+ QString eventId() const { return event_id_; }
~TimelineItem();
@@ -85,6 +86,7 @@ private:
void setupSimpleLayout();
QString replaceEmoji(const QString &body);
+ QString event_id_;
DescInfo descriptionMsg_;
diff --git a/include/TimelineView.h b/include/TimelineView.h
index 78c31e8e..3f506002 100644
--- a/include/TimelineView.h
+++ b/include/TimelineView.h
@@ -121,15 +121,20 @@ private slots:
signals:
void updateLastTimelineMessage(const QString &user, const DescInfo &info);
+ void clearUnreadMessageCount(const QString &room_id);
protected:
void paintEvent(QPaintEvent *event) override;
+ void showEvent(QShowEvent *event) override;
+ bool event(QEvent *event) override;
private:
void init();
void addTimelineItem(TimelineItem *item, TimelineDirection direction);
void updateLastSender(const QString &user_id, TimelineDirection direction);
void notifyForLastEvent();
+ void readLastEvent() const;
+ QString getLastEventId() const;
// Used to determine whether or not we should prefix a message with the
// sender's name.
diff --git a/include/TimelineViewManager.h b/include/TimelineViewManager.h
index 5bd3054f..d9fb730e 100644
--- a/include/TimelineViewManager.h
+++ b/include/TimelineViewManager.h
@@ -58,6 +58,7 @@ public:
static QMap<QString, QString> DISPLAY_NAMES;
signals:
+ void clearRoomMessageCount(QString roomid);
void unreadMessages(QString roomid, int count);
void updateRoomsLastMessage(const QString &user, const DescInfo &info);
diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index 4dbda90d..82e694a1 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -126,6 +126,11 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
connect(view_manager_,
+ &TimelineViewManager::clearRoomMessageCount,
+ room_list_,
+ &RoomList::clearRoomMessageCount);
+
+ connect(view_manager_,
&TimelineViewManager::unreadMessages,
this,
[=](const QString &roomid, int count) {
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index 5589bdc7..dcf241a6 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -847,3 +847,31 @@ MatrixClient::removeTypingNotification(const QString &roomid)
put(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
}
+
+void
+MatrixClient::readEvent(const QString &room_id, const QString &event_id)
+{
+ QUrlQuery query;
+ query.addQueryItem("access_token", token_);
+
+ QUrl endpoint(server_);
+ endpoint.setPath(clientApiUrl_ +
+ QString("/rooms/%1/receipt/m.read/%2").arg(room_id).arg(event_id));
+ endpoint.setQuery(query);
+
+ QNetworkRequest request(QString(endpoint.toEncoded()));
+ request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
+
+ auto reply = post(request, "{}");
+
+ connect(reply, &QNetworkReply::finished, this, [this, reply]() {
+ reply->deleteLater();
+
+ int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+
+ if (status == 0 || status >= 400) {
+ qWarning() << reply->errorString();
+ return;
+ }
+ });
+}
diff --git a/src/RoomList.cc b/src/RoomList.cc
index b1d3a9ca..402633c3 100644
--- a/src/RoomList.cc
+++ b/src/RoomList.cc
@@ -204,6 +204,18 @@ RoomList::sync(const QMap<QString, RoomState> &states,
}
void
+RoomList::clearRoomMessageCount(const QString &room_id)
+{
+ if (!rooms_.contains(room_id))
+ return;
+
+ auto room = rooms_[room_id];
+ room->clearUnreadMessageCount();
+
+ calculateUnreadMessageCount();
+}
+
+void
RoomList::highlightSelectedRoom(const QString &room_id)
{
emit roomChanged(room_id);
@@ -213,9 +225,7 @@ RoomList::highlightSelectedRoom(const QString &room_id)
return;
}
- // TODO: Send a read receipt for the last event.
- auto room = rooms_[room_id];
- room->clearUnreadMessageCount();
+ clearRoomMessageCount(room_id);
calculateUnreadMessageCount();
diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc
index 8c21e61d..263eb70d 100644
--- a/src/TimelineItem.cc
+++ b/src/TimelineItem.cc
@@ -154,6 +154,8 @@ TimelineItem::TimelineItem(ImageItem *image,
{
init();
+ event_id_ = event.eventId();
+
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
auto displayName = TimelineViewManager::displayName(event.sender());
@@ -193,6 +195,9 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
: QWidget(parent)
{
init();
+
+ event_id_ = event.eventId();
+
descriptionMsg_ = {TimelineViewManager::displayName(event.sender()),
event.sender(),
" sent a notification",
@@ -234,6 +239,8 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event,
{
init();
+ event_id_ = event.eventId();
+
auto body = event.content().body().trimmed();
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
auto displayName = TimelineViewManager::displayName(event.sender());
@@ -273,6 +280,8 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event,
{
init();
+ event_id_ = event.eventId();
+
auto body = event.content().body().trimmed();
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
auto displayName = TimelineViewManager::displayName(event.sender());
diff --git a/src/TimelineView.cc b/src/TimelineView.cc
index 267fbbff..44f3b9d8 100644
--- a/src/TimelineView.cc
+++ b/src/TimelineView.cc
@@ -379,6 +379,9 @@ TimelineView::addEvents(const Timeline &timeline)
if (!timeline.events().isEmpty() && scroll_layout_->count() > 1)
notifyForLastEvent();
+ if (isActiveWindow() && isVisible() && timeline.events().size() > 0)
+ readLastEvent();
+
return message_count;
}
@@ -648,3 +651,52 @@ TimelineView::paintEvent(QPaintEvent *)
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
+
+void
+TimelineView::readLastEvent() const
+{
+ const auto eventId = getLastEventId();
+
+ if (!eventId.isEmpty())
+ client_->readEvent(room_id_, eventId);
+}
+
+QString
+TimelineView::getLastEventId() const
+{
+ auto index = scroll_layout_->count();
+
+ // Search backwards for the first event that has a valid event id.
+ while (index > 0) {
+ --index;
+
+ auto lastItem = scroll_layout_->itemAt(index);
+ auto *lastTimelineItem = qobject_cast<TimelineItem *>(lastItem->widget());
+
+ if (lastTimelineItem && !lastTimelineItem->eventId().isEmpty())
+ return lastTimelineItem->eventId();
+ }
+
+ return QString("");
+}
+
+void
+TimelineView::showEvent(QShowEvent *event)
+{
+ readLastEvent();
+
+ QWidget::showEvent(event);
+}
+
+bool
+TimelineView::event(QEvent *event)
+{
+ if (event->type() == QEvent::WindowActivate) {
+ QTimer::singleShot(1000, this, [=]() {
+ emit clearUnreadMessageCount(room_id_);
+ readLastEvent();
+ });
+ }
+
+ return QWidget::event(event);
+}
diff --git a/src/TimelineViewManager.cc b/src/TimelineViewManager.cc
index ec7b8446..1f047d7c 100644
--- a/src/TimelineViewManager.cc
+++ b/src/TimelineViewManager.cc
@@ -131,6 +131,10 @@ TimelineViewManager::addRoom(const JoinedRoom &room, const QString &room_id)
&TimelineView::updateLastTimelineMessage,
this,
&TimelineViewManager::updateRoomsLastMessage);
+ connect(view,
+ &TimelineView::clearUnreadMessageCount,
+ this,
+ &TimelineViewManager::clearRoomMessageCount);
// Add the view in the widget stack.
addWidget(view);
@@ -147,6 +151,10 @@ TimelineViewManager::addRoom(const QString &room_id)
&TimelineView::updateLastTimelineMessage,
this,
&TimelineViewManager::updateRoomsLastMessage);
+ connect(view,
+ &TimelineView::clearUnreadMessageCount,
+ this,
+ &TimelineViewManager::clearRoomMessageCount);
// Add the view in the widget stack.
addWidget(view);