mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 04:58:49 +03:00
Send read receipts
Automatically dismiss unread notifications when the window regains focus. fixes #111 fixes #68
This commit is contained in:
parent
c6cf6c2b41
commit
0f363b5f44
11 changed files with 126 additions and 4 deletions
|
@ -59,6 +59,7 @@ public:
|
||||||
void leaveRoom(const QString &roomId);
|
void leaveRoom(const QString &roomId);
|
||||||
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
|
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
|
||||||
void removeTypingNotification(const QString &roomid);
|
void removeTypingNotification(const QString &roomid);
|
||||||
|
void readEvent(const QString &room_id, const QString &event_id);
|
||||||
|
|
||||||
QUrl getHomeServer() { return server_; };
|
QUrl getHomeServer() { return server_; };
|
||||||
int transactionId() { return txn_id_; };
|
int transactionId() { return txn_id_; };
|
||||||
|
|
|
@ -66,6 +66,7 @@ public slots:
|
||||||
void closeJoinRoomDialog(bool isJoining, QString roomAlias);
|
void closeJoinRoomDialog(bool isJoining, QString roomAlias);
|
||||||
void openLeaveRoomDialog(const QString &room_id);
|
void openLeaveRoomDialog(const QString &room_id);
|
||||||
void closeLeaveRoomDialog(bool leaving, const QString &room_id);
|
void closeLeaveRoomDialog(bool leaving, const QString &room_id);
|
||||||
|
void clearRoomMessageCount(const QString &room_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calculateUnreadMessageCount();
|
void calculateUnreadMessageCount();
|
||||||
|
|
|
@ -66,7 +66,8 @@ public:
|
||||||
QWidget *parent);
|
QWidget *parent);
|
||||||
|
|
||||||
void setUserAvatar(const QImage &pixmap);
|
void setUserAvatar(const QImage &pixmap);
|
||||||
DescInfo descriptionMessage() const { return descriptionMsg_; };
|
DescInfo descriptionMessage() const { return descriptionMsg_; }
|
||||||
|
QString eventId() const { return event_id_; }
|
||||||
|
|
||||||
~TimelineItem();
|
~TimelineItem();
|
||||||
|
|
||||||
|
@ -85,6 +86,7 @@ private:
|
||||||
void setupSimpleLayout();
|
void setupSimpleLayout();
|
||||||
|
|
||||||
QString replaceEmoji(const QString &body);
|
QString replaceEmoji(const QString &body);
|
||||||
|
QString event_id_;
|
||||||
|
|
||||||
DescInfo descriptionMsg_;
|
DescInfo descriptionMsg_;
|
||||||
|
|
||||||
|
|
|
@ -121,15 +121,20 @@ private slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateLastTimelineMessage(const QString &user, const DescInfo &info);
|
void updateLastTimelineMessage(const QString &user, const DescInfo &info);
|
||||||
|
void clearUnreadMessageCount(const QString &room_id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
bool event(QEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void addTimelineItem(TimelineItem *item, TimelineDirection direction);
|
void addTimelineItem(TimelineItem *item, TimelineDirection direction);
|
||||||
void updateLastSender(const QString &user_id, TimelineDirection direction);
|
void updateLastSender(const QString &user_id, TimelineDirection direction);
|
||||||
void notifyForLastEvent();
|
void notifyForLastEvent();
|
||||||
|
void readLastEvent() const;
|
||||||
|
QString getLastEventId() const;
|
||||||
|
|
||||||
// Used to determine whether or not we should prefix a message with the
|
// Used to determine whether or not we should prefix a message with the
|
||||||
// sender's name.
|
// sender's name.
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
static QMap<QString, QString> DISPLAY_NAMES;
|
static QMap<QString, QString> DISPLAY_NAMES;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void clearRoomMessageCount(QString roomid);
|
||||||
void unreadMessages(QString roomid, int count);
|
void unreadMessages(QString roomid, int count);
|
||||||
void updateRoomsLastMessage(const QString &user, const DescInfo &info);
|
void updateRoomsLastMessage(const QString &user, const DescInfo &info);
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,11 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
connect(
|
connect(
|
||||||
room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
|
room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
|
||||||
|
|
||||||
|
connect(view_manager_,
|
||||||
|
&TimelineViewManager::clearRoomMessageCount,
|
||||||
|
room_list_,
|
||||||
|
&RoomList::clearRoomMessageCount);
|
||||||
|
|
||||||
connect(view_manager_,
|
connect(view_manager_,
|
||||||
&TimelineViewManager::unreadMessages,
|
&TimelineViewManager::unreadMessages,
|
||||||
this,
|
this,
|
||||||
|
|
|
@ -847,3 +847,31 @@ MatrixClient::removeTypingNotification(const QString &roomid)
|
||||||
|
|
||||||
put(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -203,6 +203,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
|
void
|
||||||
RoomList::highlightSelectedRoom(const QString &room_id)
|
RoomList::highlightSelectedRoom(const QString &room_id)
|
||||||
{
|
{
|
||||||
|
@ -213,9 +225,7 @@ RoomList::highlightSelectedRoom(const QString &room_id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Send a read receipt for the last event.
|
clearRoomMessageCount(room_id);
|
||||||
auto room = rooms_[room_id];
|
|
||||||
room->clearUnreadMessageCount();
|
|
||||||
|
|
||||||
calculateUnreadMessageCount();
|
calculateUnreadMessageCount();
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,8 @@ TimelineItem::TimelineItem(ImageItem *image,
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
event_id_ = event.eventId();
|
||||||
|
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(event.sender());
|
||||||
|
|
||||||
|
@ -193,6 +195,9 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
event_id_ = event.eventId();
|
||||||
|
|
||||||
descriptionMsg_ = {TimelineViewManager::displayName(event.sender()),
|
descriptionMsg_ = {TimelineViewManager::displayName(event.sender()),
|
||||||
event.sender(),
|
event.sender(),
|
||||||
" sent a notification",
|
" sent a notification",
|
||||||
|
@ -234,6 +239,8 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event,
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
event_id_ = event.eventId();
|
||||||
|
|
||||||
auto body = event.content().body().trimmed();
|
auto body = event.content().body().trimmed();
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(event.sender());
|
||||||
|
@ -273,6 +280,8 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event,
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
event_id_ = event.eventId();
|
||||||
|
|
||||||
auto body = event.content().body().trimmed();
|
auto body = event.content().body().trimmed();
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(event.sender());
|
||||||
|
|
|
@ -379,6 +379,9 @@ TimelineView::addEvents(const Timeline &timeline)
|
||||||
if (!timeline.events().isEmpty() && scroll_layout_->count() > 1)
|
if (!timeline.events().isEmpty() && scroll_layout_->count() > 1)
|
||||||
notifyForLastEvent();
|
notifyForLastEvent();
|
||||||
|
|
||||||
|
if (isActiveWindow() && isVisible() && timeline.events().size() > 0)
|
||||||
|
readLastEvent();
|
||||||
|
|
||||||
return message_count;
|
return message_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,3 +651,52 @@ TimelineView::paintEvent(QPaintEvent *)
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &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);
|
||||||
|
}
|
||||||
|
|
|
@ -131,6 +131,10 @@ TimelineViewManager::addRoom(const JoinedRoom &room, const QString &room_id)
|
||||||
&TimelineView::updateLastTimelineMessage,
|
&TimelineView::updateLastTimelineMessage,
|
||||||
this,
|
this,
|
||||||
&TimelineViewManager::updateRoomsLastMessage);
|
&TimelineViewManager::updateRoomsLastMessage);
|
||||||
|
connect(view,
|
||||||
|
&TimelineView::clearUnreadMessageCount,
|
||||||
|
this,
|
||||||
|
&TimelineViewManager::clearRoomMessageCount);
|
||||||
|
|
||||||
// Add the view in the widget stack.
|
// Add the view in the widget stack.
|
||||||
addWidget(view);
|
addWidget(view);
|
||||||
|
@ -147,6 +151,10 @@ TimelineViewManager::addRoom(const QString &room_id)
|
||||||
&TimelineView::updateLastTimelineMessage,
|
&TimelineView::updateLastTimelineMessage,
|
||||||
this,
|
this,
|
||||||
&TimelineViewManager::updateRoomsLastMessage);
|
&TimelineViewManager::updateRoomsLastMessage);
|
||||||
|
connect(view,
|
||||||
|
&TimelineView::clearUnreadMessageCount,
|
||||||
|
this,
|
||||||
|
&TimelineViewManager::clearRoomMessageCount);
|
||||||
|
|
||||||
// Add the view in the widget stack.
|
// Add the view in the widget stack.
|
||||||
addWidget(view);
|
addWidget(view);
|
||||||
|
|
Loading…
Reference in a new issue