mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
parent
9f3de8679d
commit
8767ea181d
11 changed files with 127 additions and 18 deletions
|
@ -825,8 +825,10 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
|
|||
}
|
||||
|
||||
void
|
||||
Cache::notifyForReadReceipts(lmdb::txn &txn, const std::string &room_id)
|
||||
Cache::notifyForReadReceipts(const std::string &room_id)
|
||||
{
|
||||
auto txn = lmdb::txn::begin(env_);
|
||||
|
||||
QSettings settings;
|
||||
auto local_user = settings.value("auth/user_id").toString();
|
||||
|
||||
|
@ -839,6 +841,47 @@ Cache::notifyForReadReceipts(lmdb::txn &txn, const std::string &room_id)
|
|||
|
||||
if (!matches.empty())
|
||||
emit newReadReceipts(QString::fromStdString(room_id), matches);
|
||||
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
void
|
||||
Cache::calculateRoomReadStatus()
|
||||
{
|
||||
const auto joined_rooms = joinedRooms();
|
||||
|
||||
std::map<QString, bool> readStatus;
|
||||
|
||||
for (const auto &room : joined_rooms)
|
||||
readStatus.emplace(QString::fromStdString(room), calculateRoomReadStatus(room));
|
||||
|
||||
emit roomReadStatus(readStatus);
|
||||
}
|
||||
|
||||
bool
|
||||
Cache::calculateRoomReadStatus(const std::string &room_id)
|
||||
{
|
||||
auto txn = lmdb::txn::begin(env_);
|
||||
|
||||
// Get last event id on the room.
|
||||
const auto last_event_id = getLastMessageInfo(txn, room_id).event_id;
|
||||
const auto localUser = utils::localUser().toStdString();
|
||||
|
||||
txn.commit();
|
||||
|
||||
// Retrieve all read receipts for that event.
|
||||
const auto receipts = readReceipts(last_event_id, QString::fromStdString(room_id));
|
||||
|
||||
if (receipts.size() == 0)
|
||||
return true;
|
||||
|
||||
// Check if the local user has a read receipt for it.
|
||||
for (auto it = receipts.cbegin(); it != receipts.cend(); it++) {
|
||||
if (it->second == localUser)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -880,11 +923,15 @@ Cache::saveState(const mtx::responses::Sync &res)
|
|||
|
||||
txn.commit();
|
||||
|
||||
std::map<QString, bool> readStatus;
|
||||
|
||||
for (const auto &room : res.rooms.join) {
|
||||
auto tmpTxn = lmdb::txn::begin(env_);
|
||||
notifyForReadReceipts(tmpTxn, room.first);
|
||||
tmpTxn.commit();
|
||||
notifyForReadReceipts(room.first);
|
||||
readStatus.emplace(QString::fromStdString(room.first),
|
||||
calculateRoomReadStatus(room.first));
|
||||
}
|
||||
|
||||
emit roomReadStatus(readStatus);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -89,6 +89,7 @@ from_json(const json &j, ReadReceiptKey &key)
|
|||
|
||||
struct DescInfo
|
||||
{
|
||||
QString event_id;
|
||||
QString username;
|
||||
QString userid;
|
||||
QString body;
|
||||
|
@ -356,7 +357,7 @@ public:
|
|||
void removePendingReceipt(lmdb::txn &txn,
|
||||
const std::string &room_id,
|
||||
const std::string &event_id);
|
||||
void notifyForReadReceipts(lmdb::txn &txn, const std::string &room_id);
|
||||
void notifyForReadReceipts(const std::string &room_id);
|
||||
std::vector<QString> pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
|
||||
|
||||
QByteArray image(const QString &url) const;
|
||||
|
@ -376,6 +377,11 @@ public:
|
|||
return getRoomInfo(roomsWithStateUpdates(sync));
|
||||
}
|
||||
|
||||
//! Calculates which the read status of a room.
|
||||
//! Whether all the events in the timeline have been read.
|
||||
bool calculateRoomReadStatus(const std::string &room_id);
|
||||
void calculateRoomReadStatus();
|
||||
|
||||
QVector<SearchResult> searchUsers(const std::string &room_id,
|
||||
const std::string &query,
|
||||
std::uint8_t max_items = 5);
|
||||
|
@ -444,6 +450,7 @@ public:
|
|||
|
||||
signals:
|
||||
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||
void roomReadStatus(const std::map<QString, bool> &status);
|
||||
|
||||
private:
|
||||
//! Save an invited room.
|
||||
|
|
|
@ -677,6 +677,9 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
|||
view_manager_,
|
||||
&TimelineViewManager::updateReadReceipts);
|
||||
|
||||
connect(
|
||||
cache::client(), &Cache::roomReadStatus, room_list_, &RoomList::updateReadStatus);
|
||||
|
||||
const bool isInitialized = cache::client()->isInitialized();
|
||||
const bool isValid = cache::client()->isFormatValid();
|
||||
|
||||
|
@ -794,6 +797,8 @@ ChatPage::loadStateFromCache()
|
|||
emit initializeEmptyViews(cache::client()->roomMessages());
|
||||
emit initializeRoomList(cache::client()->roomInfo());
|
||||
|
||||
cache::client()->calculateRoomReadStatus();
|
||||
|
||||
} catch (const mtx::crypto::olm_exception &e) {
|
||||
nhlog::crypto()->critical("failed to restore olm account: {}", e.what());
|
||||
emit dropToLoginPageCb(
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
|
||||
constexpr int MaxUnreadCountDisplayed = 99;
|
||||
|
||||
constexpr int Padding = 9;
|
||||
constexpr int IconSize = 44;
|
||||
constexpr int MaxHeight = IconSize + 2 * Padding;
|
||||
constexpr int Padding = 9;
|
||||
constexpr int UnreadLineWidth = 4;
|
||||
constexpr int UnreadLineOffset = 4;
|
||||
constexpr int IconSize = 44;
|
||||
constexpr int MaxHeight = IconSize + 2 * Padding;
|
||||
|
||||
constexpr int InviteBtnX = IconSize + 2 * Padding;
|
||||
constexpr int InviteBtnY = IconSize / 2 + Padding + Padding / 3;
|
||||
|
@ -89,6 +91,8 @@ RoomInfoListItem::RoomInfoListItem(QString room_id, RoomInfo info, QWidget *pare
|
|||
{
|
||||
init(parent);
|
||||
|
||||
QString emptyEventId;
|
||||
|
||||
// HACK
|
||||
// We use fake message info with an old date to pin
|
||||
// the invite events to the top.
|
||||
|
@ -96,7 +100,8 @@ RoomInfoListItem::RoomInfoListItem(QString room_id, RoomInfo info, QWidget *pare
|
|||
// State events in invited rooms don't contain timestamp info,
|
||||
// so we can't use them for sorting.
|
||||
if (roomType_ == RoomType::Invited)
|
||||
lastMsgInfo_ = {"-", "-", "-", "-", QDateTime::currentDateTime().addYears(10)};
|
||||
lastMsgInfo_ = {
|
||||
emptyEventId, "-", "-", "-", "-", QDateTime::currentDateTime().addYears(10)};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -305,6 +310,15 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
|
|||
p.setBrush(Qt::NoBrush);
|
||||
p.drawText(r.translated(0, -0.5), Qt::AlignCenter, countTxt);
|
||||
}
|
||||
|
||||
if (!isPressed_ && hasUnreadMessages_) {
|
||||
QPen pen;
|
||||
pen.setWidth(UnreadLineWidth);
|
||||
pen.setColor(highlightedBackgroundColor_);
|
||||
|
||||
p.setPen(pen);
|
||||
p.drawLine(0, UnreadLineOffset, 0, height() - UnreadLineOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -121,6 +121,13 @@ public:
|
|||
}
|
||||
|
||||
bool isInvite() { return roomType_ == RoomType::Invited; }
|
||||
void setReadState(bool hasUnreadMessages)
|
||||
{
|
||||
if (hasUnreadMessages_ != hasUnreadMessages) {
|
||||
hasUnreadMessages_ = hasUnreadMessages;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void clicked(const QString &room_id);
|
||||
|
@ -164,7 +171,8 @@ private:
|
|||
Menu *menu_;
|
||||
QAction *leaveRoom_;
|
||||
|
||||
bool isPressed_ = false;
|
||||
bool isPressed_ = false;
|
||||
bool hasUnreadMessages_ = true;
|
||||
|
||||
int unreadMsgCount_ = 0;
|
||||
|
||||
|
|
|
@ -455,3 +455,16 @@ RoomList::firstRoom() const
|
|||
return std::pair<QString, QSharedPointer<RoomInfoListItem>>(firstRoom->first,
|
||||
firstRoom->second);
|
||||
}
|
||||
|
||||
void
|
||||
RoomList::updateReadStatus(const std::map<QString, bool> &status)
|
||||
{
|
||||
for (const auto &room : status) {
|
||||
if (roomExists(room.first)) {
|
||||
auto item = rooms_.at(room.first);
|
||||
|
||||
if (item)
|
||||
item->setReadState(room.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ public slots:
|
|||
void updateUnreadMessageCount(const QString &roomid, int count);
|
||||
void updateRoomDescription(const QString &roomid, const DescInfo &info);
|
||||
void closeJoinRoomDialog(bool isJoining, QString roomAlias);
|
||||
void updateReadStatus(const std::map<QString, bool> &status);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
|
|
@ -126,6 +126,7 @@ utils::getMessageDescription(const TimelineEvent &event,
|
|||
info.userid = sender;
|
||||
info.body = QString(" %1").arg(messageDescription<Encrypted>());
|
||||
info.timestamp = utils::descriptiveTime(ts);
|
||||
info.event_id = QString::fromStdString(msg.event_id);
|
||||
info.datetime = ts;
|
||||
|
||||
return info;
|
||||
|
|
|
@ -109,6 +109,7 @@ createDescriptionInfo(const Event &event, const QString &localUser, const QStrin
|
|||
bool isEmote = std::is_same<T, Emote>::value;
|
||||
|
||||
return DescInfo{
|
||||
QString::fromStdString(msg.event_id),
|
||||
isEmote ? "" : (sender == localUser ? "You" : username),
|
||||
sender,
|
||||
(isText || isEmote)
|
||||
|
|
|
@ -317,16 +317,23 @@ TimelineItem::TimelineItem(mtx::events::MessageType ty,
|
|||
if (formatted_body == body.trimmed().toHtmlEscaped())
|
||||
formatted_body = body.toHtmlEscaped();
|
||||
|
||||
QString emptyEventId;
|
||||
|
||||
if (ty == mtx::events::MessageType::Emote) {
|
||||
formatted_body = QString("<em>%1</em>").arg(formatted_body);
|
||||
descriptionMsg_ = {"",
|
||||
descriptionMsg_ = {emptyEventId,
|
||||
"",
|
||||
userid,
|
||||
QString("* %1 %2").arg(displayName).arg(body),
|
||||
utils::descriptiveTime(timestamp),
|
||||
timestamp};
|
||||
} else {
|
||||
descriptionMsg_ = {
|
||||
"You: ", userid, body, utils::descriptiveTime(timestamp), timestamp};
|
||||
descriptionMsg_ = {emptyEventId,
|
||||
"You: ",
|
||||
userid,
|
||||
body,
|
||||
utils::descriptiveTime(timestamp),
|
||||
timestamp};
|
||||
}
|
||||
|
||||
formatted_body = utils::linkifyMessage(formatted_body);
|
||||
|
@ -496,7 +503,8 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice
|
|||
auto formatted_body = utils::linkifyMessage(utils::getMessageBody(event).trimmed());
|
||||
auto body = QString::fromStdString(event.content.body).trimmed().toHtmlEscaped();
|
||||
|
||||
descriptionMsg_ = {Cache::displayName(room_id_, sender),
|
||||
descriptionMsg_ = {event_id_,
|
||||
Cache::displayName(room_id_, sender),
|
||||
sender,
|
||||
" sent a notification",
|
||||
utils::descriptiveTime(timestamp),
|
||||
|
@ -545,7 +553,8 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote>
|
|||
auto displayName = Cache::displayName(room_id_, sender);
|
||||
formatted_body = QString("<em>%1</em>").arg(formatted_body);
|
||||
|
||||
descriptionMsg_ = {"",
|
||||
descriptionMsg_ = {event_id_,
|
||||
"",
|
||||
sender,
|
||||
QString("* %1 %2").arg(displayName).arg(body),
|
||||
utils::descriptiveTime(timestamp),
|
||||
|
@ -592,7 +601,8 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text>
|
|||
auto displayName = Cache::displayName(room_id_, sender);
|
||||
|
||||
QSettings settings;
|
||||
descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||
descriptionMsg_ = {event_id_,
|
||||
sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||
sender,
|
||||
QString(": %1").arg(body),
|
||||
utils::descriptiveTime(timestamp),
|
||||
|
|
|
@ -319,7 +319,8 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget, const QString &userid, bool
|
|||
auto displayName = Cache::displayName(room_id_, userid);
|
||||
auto timestamp = QDateTime::currentDateTime();
|
||||
|
||||
descriptionMsg_ = {"You",
|
||||
descriptionMsg_ = {"", // No event_id up until this point.
|
||||
"You",
|
||||
userid,
|
||||
QString(" %1").arg(utils::messageDescription<Widget>()),
|
||||
utils::descriptiveTime(timestamp),
|
||||
|
@ -358,7 +359,8 @@ TimelineItem::setupWidgetLayout(Widget *widget, const Event &event, bool withSen
|
|||
auto displayName = Cache::displayName(room_id_, sender);
|
||||
|
||||
QSettings settings;
|
||||
descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||
descriptionMsg_ = {event_id_,
|
||||
sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||
sender,
|
||||
QString(" %1").arg(utils::messageDescription<Widget>()),
|
||||
utils::descriptiveTime(timestamp),
|
||||
|
|
Loading…
Reference in a new issue