diff --git a/src/Cache.cpp b/src/Cache.cpp
index aca01c1a..8cfc4b55 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -960,9 +960,15 @@ Cache::saveState(const mtx::responses::Sync &res)
for (const auto &room : res.rooms.join) {
if (!room.second.ephemeral.receipts.empty()) {
std::vector<QString> receipts;
- for (const auto &receipt : room.second.ephemeral.receipts)
- if (receipt.first != user_id)
- receipts.push_back(QString::fromStdString(receipt.first));
+ for (const auto &receipt : room.second.ephemeral.receipts) {
+ for (const auto &receiptUsersTs : receipt.second) {
+ if (receiptUsersTs.first != user_id) {
+ receipts.push_back(
+ QString::fromStdString(receipt.first));
+ break;
+ }
+ }
+ }
if (!receipts.empty())
emit newReadReceipts(QString::fromStdString(room.first), receipts);
}
@@ -1314,16 +1320,33 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
std::string timestamp, msg;
- QSettings settings;
const auto local_user = utils::localUser();
+ DescInfo fallbackDesc{};
+
auto cursor = lmdb::cursor::open(txn, db);
while (cursor.get(timestamp, msg, MDB_NEXT)) {
auto obj = json::parse(msg);
- if (obj.count("event") == 0 || !(obj["event"]["type"] == "m.room.message" ||
- obj["event"]["type"] == "m.sticker" ||
- obj["event"]["type"] == "m.room.encrypted"))
+ if (obj.count("event") == 0)
+ continue;
+
+ if (fallbackDesc.event_id.isEmpty() && obj["event"]["type"] == "m.room.member" &&
+ obj["event"]["state_key"] == local_user.toStdString() &&
+ obj["event"]["content"]["membership"] == "join") {
+ uint64_t ts = obj["event"]["origin_server_ts"];
+ auto time = QDateTime::fromMSecsSinceEpoch(ts);
+ fallbackDesc = DescInfo{QString::fromStdString(obj["event"]["event_id"]),
+ local_user,
+ tr("You joined this room"),
+ utils::descriptiveTime(time),
+ ts,
+ time};
+ }
+
+ if (!(obj["event"]["type"] == "m.room.message" ||
+ obj["event"]["type"] == "m.sticker" ||
+ obj["event"]["type"] == "m.room.encrypted"))
continue;
mtx::events::collections::TimelineEvent event;
@@ -1335,7 +1358,7 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
}
cursor.close();
- return DescInfo{};
+ return fallbackDesc;
}
std::map<QString, bool>
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 689e9ca4..ae3c7a11 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -1009,13 +1009,13 @@ ChatPage::trySync()
cache::saveState(res);
olm::handle_to_device_messages(res.to_device);
- emit syncUI(res.rooms);
-
auto updates = cache::roomUpdates(res);
emit syncTopBar(updates);
emit syncRoomlist(updates);
+ emit syncUI(res.rooms);
+
emit syncTags(cache::roomTagUpdates(res));
// if we process a lot of syncs (1 every 200ms), this means we clean the
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index 981b1f11..85a22026 100644
--- a/src/RoomList.cpp
+++ b/src/RoomList.cpp
@@ -384,7 +384,7 @@ RoomList::sortRoomsByLastMessage()
{
isSortPending_ = false;
- std::sort(begin(rooms_sort_cache_), end(rooms_sort_cache_), room_sort{});
+ std::stable_sort(begin(rooms_sort_cache_), end(rooms_sort_cache_), room_sort{});
int newIndex = 0;
for (const auto &roomWidget : rooms_sort_cache_) {
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 836fd59f..388a5842 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -324,16 +324,24 @@ TimelineModel::data(const QString &id, int role) const
}
case Id:
return id;
- case State:
+ case State: {
+ auto containsOthers = [](const auto &vec) {
+ for (const auto &e : vec)
+ if (e.second != http::client()->user_id().to_string())
+ return true;
+ return false;
+ };
+
// only show read receipts for messages not from us
if (acc::sender(event) != http::client()->user_id().to_string())
return qml_mtx_events::Empty;
else if (pending.contains(id))
return qml_mtx_events::Sent;
- else if (read.contains(id) || cache::readReceipts(id, room_id_).size() > 1)
+ else if (read.contains(id) || containsOthers(cache::readReceipts(id, room_id_)))
return qml_mtx_events::Read;
else
return qml_mtx_events::Received;
+ }
case IsEncrypted: {
return std::holds_alternative<
mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(events[id]);
@@ -525,6 +533,20 @@ isMessage(const mtx::events::EncryptedEvent<T> &)
return true;
}
+// Workaround. We also want to see a room at the top, if we just joined it
+auto
+isYourJoin(const mtx::events::StateEvent<mtx::events::state::Member> &e)
+{
+ return e.content.membership == mtx::events::state::Membership::Join &&
+ e.state_key == http::client()->user_id().to_string();
+}
+template<typename T>
+auto
+isYourJoin(const mtx::events::Event<T> &)
+{
+ return false;
+}
+
void
TimelineModel::updateLastMessage()
{
@@ -537,6 +559,19 @@ TimelineModel::updateLastMessage()
}
}
+ if (std::visit([](const auto &e) -> bool { return isYourJoin(e); }, event)) {
+ auto time = mtx::accessors::origin_server_ts(event);
+ uint64_t ts = time.toMSecsSinceEpoch();
+ emit manager_->updateRoomsLastMessage(
+ room_id_,
+ DescInfo{QString::fromStdString(mtx::accessors::event_id(event)),
+ QString::fromStdString(http::client()->user_id().to_string()),
+ tr("You joined this room"),
+ utils::descriptiveTime(time),
+ ts,
+ time});
+ return;
+ }
if (!std::visit([](const auto &e) -> bool { return isMessage(e); }, event))
continue;
|