diff --git a/src/Cache.cpp b/src/Cache.cpp
index c41b66cc..4a99dd59 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -2045,21 +2045,57 @@ Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id)
return fallbackDesc;
}
-std::map<QString, bool>
+QHash<QString, RoomInfo>
Cache::invites()
{
- std::map<QString, bool> result;
+ QHash<QString, RoomInfo> result;
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
auto cursor = lmdb::cursor::open(txn, invitesDb_);
- std::string_view room_id, unused;
+ std::string_view room_id, room_data;
- while (cursor.get(room_id, unused, MDB_NEXT))
- result.emplace(QString::fromStdString(std::string(room_id)), true);
+ while (cursor.get(room_id, room_data, MDB_NEXT)) {
+ try {
+ RoomInfo tmp = json::parse(room_data);
+ tmp.member_count = getInviteMembersDb(txn, std::string(room_id)).size(txn);
+ result.insert(QString::fromStdString(std::string(room_id)), std::move(tmp));
+ } catch (const json::exception &e) {
+ nhlog::db()->warn("failed to parse room info for invite: "
+ "room_id ({}), {}: {}",
+ room_id,
+ std::string(room_data),
+ e.what());
+ }
+ }
cursor.close();
- txn.commit();
+
+ return result;
+}
+
+std::optional<RoomInfo>
+Cache::invite(std::string_view roomid)
+{
+ std::optional<RoomInfo> result;
+
+ auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
+
+ std::string_view room_data;
+
+ if (invitesDb_.get(txn, roomid, room_data)) {
+ try {
+ RoomInfo tmp = json::parse(room_data);
+ tmp.member_count = getInviteMembersDb(txn, std::string(roomid)).size(txn);
+ result = std::move(tmp);
+ } catch (const json::exception &e) {
+ nhlog::db()->warn("failed to parse room info for invite: "
+ "room_id ({}), {}: {}",
+ roomid,
+ std::string(room_data),
+ e.what());
+ }
+ }
return result;
}
@@ -4064,7 +4100,7 @@ roomInfo(bool withInvites)
{
return instance_->roomInfo(withInvites);
}
-std::map<QString, bool>
+QHash<QString, RoomInfo>
invites()
{
return instance_->invites();
diff --git a/src/Cache.h b/src/Cache.h
index 427dbafc..74ec9695 100644
--- a/src/Cache.h
+++ b/src/Cache.h
@@ -62,7 +62,7 @@ joinedRooms();
QMap<QString, RoomInfo>
roomInfo(bool withInvites = true);
-std::map<QString, bool>
+QHash<QString, RoomInfo>
invites();
//! Calculate & return the name of the room.
diff --git a/src/Cache_p.h b/src/Cache_p.h
index c55fa601..f2911622 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -70,7 +70,8 @@ public:
QMap<QString, RoomInfo> roomInfo(bool withInvites = true);
std::optional<mtx::events::state::CanonicalAlias> getRoomAliases(const std::string &roomid);
- std::map<QString, bool> invites();
+ QHash<QString, RoomInfo> invites();
+ std::optional<RoomInfo> invite(std::string_view roomid);
//! Calculate & return the name of the room.
QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 58b76174..166c03ec 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -313,7 +313,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
connect(this,
&ChatPage::initializeEmptyViews,
view_manager_,
- &TimelineViewManager::initWithMessages);
+ &TimelineViewManager::initializeRoomlist);
connect(this,
&ChatPage::initializeMentions,
user_mentions_popup_,
@@ -554,7 +554,7 @@ ChatPage::loadStateFromCache()
try {
olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
- emit initializeEmptyViews(cache::client()->roomIds());
+ emit initializeEmptyViews();
emit initializeRoomList(cache::roomInfo());
emit initializeMentions(cache::getTimelineMentions());
emit syncTags(cache::roomInfo().toStdMap());
diff --git a/src/ChatPage.h b/src/ChatPage.h
index 84e7cdff..eb60047d 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -147,7 +147,7 @@ signals:
void initializeRoomList(QMap<QString, RoomInfo>);
void initializeViews(const mtx::responses::Rooms &rooms);
- void initializeEmptyViews(const std::vector<QString> &roomIds);
+ void initializeEmptyViews();
void initializeMentions(const QMap<QString, mtx::responses::Notifications> ¬ifs);
void syncUI(const mtx::responses::Rooms &rooms);
void syncRoomlist(const std::map<QString, RoomInfo> &updates);
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index 5c41a7a1..5839c4a0 100644
--- a/src/RoomList.cpp
+++ b/src/RoomList.cpp
@@ -183,7 +183,7 @@ RoomList::initialize(const QMap<QString, RoomInfo> &info)
}
void
-RoomList::cleanupInvites(const std::map<QString, bool> &invites)
+RoomList::cleanupInvites(const QHash<QString, RoomInfo> &invites)
{
if (invites.size() == 0)
return;
diff --git a/src/RoomList.h b/src/RoomList.h
index 74152c55..af792fd7 100644
--- a/src/RoomList.h
+++ b/src/RoomList.h
@@ -48,7 +48,7 @@ public:
//! Show all the available rooms.
void removeFilter(const std::set<QString> &roomsToHide);
void updateRoom(const QString &room_id, const RoomInfo &info);
- void cleanupInvites(const std::map<QString, bool> &invites);
+ void cleanupInvites(const QHash<QString, RoomInfo> &invites);
signals:
void roomChanged(const QString &room_id);
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 28c3cf46..f3d4dad7 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -57,31 +57,64 @@ RoomlistModel::data(const QModelIndex &index, int role) const
{
if (index.row() >= 0 && static_cast<size_t>(index.row()) < roomids.size()) {
auto roomid = roomids.at(index.row());
- auto room = models.value(roomid);
- switch (role) {
- case Roles::AvatarUrl:
- return room->roomAvatarUrl();
- case Roles::RoomName:
- return room->plainRoomName();
- case Roles::RoomId:
- return room->roomId();
- case Roles::LastMessage:
- return room->lastMessage().body;
- case Roles::Time:
- return room->lastMessage().descriptiveTime;
- case Roles::Timestamp:
- return QVariant(static_cast<quint64>(room->lastMessage().timestamp));
- case Roles::HasUnreadMessages:
- return this->roomReadStatus.count(roomid) &&
- this->roomReadStatus.at(roomid);
- case Roles::HasLoudNotification:
- return room->hasMentions();
- case Roles::NotificationCount:
- return room->notificationCount();
- case Roles::IsInvite:
- case Roles::IsSpace:
- return false;
- default:
+
+ if (models.contains(roomid)) {
+ auto room = models.value(roomid);
+ switch (role) {
+ case Roles::AvatarUrl:
+ return room->roomAvatarUrl();
+ case Roles::RoomName:
+ return room->plainRoomName();
+ case Roles::RoomId:
+ return room->roomId();
+ case Roles::LastMessage:
+ return room->lastMessage().body;
+ case Roles::Time:
+ return room->lastMessage().descriptiveTime;
+ case Roles::Timestamp:
+ return QVariant(
+ static_cast<quint64>(room->lastMessage().timestamp));
+ case Roles::HasUnreadMessages:
+ return this->roomReadStatus.count(roomid) &&
+ this->roomReadStatus.at(roomid);
+ case Roles::HasLoudNotification:
+ return room->hasMentions();
+ case Roles::NotificationCount:
+ return room->notificationCount();
+ case Roles::IsInvite:
+ case Roles::IsSpace:
+ return false;
+ default:
+ return {};
+ }
+ } else if (invites.contains(roomid)) {
+ auto room = invites.value(roomid);
+ switch (role) {
+ case Roles::AvatarUrl:
+ return QString::fromStdString(room.avatar_url);
+ case Roles::RoomName:
+ return QString::fromStdString(room.name);
+ case Roles::RoomId:
+ return roomid;
+ case Roles::LastMessage:
+ return room.msgInfo.body;
+ case Roles::Time:
+ return room.msgInfo.descriptiveTime;
+ case Roles::Timestamp:
+ return QVariant(static_cast<quint64>(room.msgInfo.timestamp));
+ case Roles::HasUnreadMessages:
+ case Roles::HasLoudNotification:
+ return false;
+ case Roles::NotificationCount:
+ return 0;
+ case Roles::IsInvite:
+ return true;
+ case Roles::IsSpace:
+ return false;
+ default:
+ return {};
+ }
+ } else {
return {};
}
} else {
@@ -109,7 +142,7 @@ RoomlistModel::updateReadStatus(const std::map<QString, bool> roomReadStatus_)
Roles::HasUnreadMessages,
});
}
-};
+}
void
RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
{
@@ -186,11 +219,21 @@ RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
newRoom->updateLastMessage();
- if (!suppressInsertNotification)
+ bool wasInvite = invites.contains(room_id);
+ if (!suppressInsertNotification && !wasInvite)
beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size());
+
models.insert(room_id, std::move(newRoom));
- roomids.push_back(room_id);
- if (!suppressInsertNotification)
+
+ if (wasInvite) {
+ auto idx = roomidToIndex(room_id);
+ invites.remove(room_id);
+ emit dataChanged(index(idx), index(idx));
+ } else {
+ roomids.push_back(room_id);
+ }
+
+ if (!suppressInsertNotification && !wasInvite)
endInsertRows();
}
}
@@ -234,20 +277,50 @@ RoomlistModel::sync(const mtx::responses::Rooms &rooms)
if (idx != -1) {
beginRemoveRows(QModelIndex(), idx, idx);
roomids.erase(roomids.begin() + idx);
- models.remove(QString::fromStdString(room_id));
+ if (models.contains(QString::fromStdString(room_id)))
+ models.remove(QString::fromStdString(room_id));
+ else if (invites.contains(QString::fromStdString(room_id)))
+ invites.remove(QString::fromStdString(room_id));
endRemoveRows();
}
}
+
+ for (const auto &[room_id, room] : rooms.invite) {
+ (void)room_id;
+ auto qroomid = QString::fromStdString(room_id);
+
+ auto invite = cache::client()->invite(room_id);
+ if (!invite)
+ continue;
+
+ if (invites.contains(qroomid)) {
+ invites[qroomid] = *invite;
+ auto idx = roomidToIndex(qroomid);
+ emit dataChanged(index(idx), index(idx));
+ } else {
+ beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size());
+ invites.insert(qroomid, *invite);
+ roomids.push_back(std::move(qroomid));
+ endInsertRows();
+ }
+ }
}
void
-RoomlistModel::initializeRooms(const std::vector<QString> &roomIds_)
+RoomlistModel::initializeRooms()
{
beginResetModel();
models.clear();
roomids.clear();
- for (const auto &id : roomIds_)
+ invites.clear();
+
+ invites = cache::client()->invites();
+ for (const auto &id : invites.keys())
+ roomids.push_back(id);
+
+ for (const auto &id : cache::client()->roomIds())
addRoom(id, true);
+
endResetModel();
}
@@ -256,10 +329,42 @@ RoomlistModel::clear()
{
beginResetModel();
models.clear();
+ invites.clear();
roomids.clear();
endResetModel();
}
+void
+RoomlistModel::acceptInvite(QString roomid)
+{
+ if (invites.contains(roomid)) {
+ auto idx = roomidToIndex(roomid);
+
+ if (idx != -1) {
+ beginRemoveRows(QModelIndex(), idx, idx);
+ roomids.erase(roomids.begin() + idx);
+ invites.remove(roomid);
+ endRemoveRows();
+ ChatPage::instance()->joinRoom(roomid);
+ }
+ }
+}
+void
+RoomlistModel::declineInvite(QString roomid)
+{
+ if (invites.contains(roomid)) {
+ auto idx = roomidToIndex(roomid);
+
+ if (idx != -1) {
+ beginRemoveRows(QModelIndex(), idx, idx);
+ roomids.erase(roomids.begin() + idx);
+ invites.remove(roomid);
+ endRemoveRows();
+ ChatPage::instance()->leaveRoom(roomid);
+ }
+ }
+}
+
namespace {
enum NotificationImportance : short
{
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index c3374bd2..ff85614c 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -4,6 +4,7 @@
#pragma once
+#include <CacheStructs.h>
#include <QAbstractListModel>
#include <QHash>
#include <QSharedPointer>
@@ -51,7 +52,7 @@ public:
}
public slots:
- void initializeRooms(const std::vector<QString> &roomids);
+ void initializeRooms();
void sync(const mtx::responses::Rooms &rooms);
void clear();
int roomidToIndex(QString roomid)
@@ -63,6 +64,8 @@ public slots:
return -1;
}
+ void acceptInvite(QString roomid);
+ void declineInvite(QString roomid);
private slots:
void updateReadStatus(const std::map<QString, bool> roomReadStatus_);
@@ -75,6 +78,7 @@ private:
TimelineViewManager *manager = nullptr;
std::vector<QString> roomids;
+ QHash<QString, RoomInfo> invites;
QHash<QString, QSharedPointer<TimelineModel>> models;
std::map<QString, bool> roomReadStatus;
@@ -94,6 +98,8 @@ public slots:
return mapFromSource(roomlistmodel->index(roomlistmodel->roomidToIndex(roomid)))
.row();
}
+ void acceptInvite(QString roomid) { roomlistmodel->acceptInvite(roomid); }
+ void declineInvite(QString roomid) { roomlistmodel->declineInvite(roomid); }
private:
short int calculateImportance(const QModelIndex &idx) const;
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index c84e0df8..9fa7f8b6 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -499,9 +499,9 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s
}
void
-TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
+TimelineViewManager::initializeRoomlist()
{
- rooms->initializeRooms(roomIds);
+ rooms->initializeRooms();
}
void
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 609f5a4a..37e50804 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -100,7 +100,7 @@ signals:
public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
- void initWithMessages(const std::vector<QString> &roomIds);
+ void initializeRoomlist();
void chatFocusChanged(bool focused)
{
isWindowFocused_ = focused;
diff --git a/src/ui/Theme.cpp b/src/ui/Theme.cpp
index b6c9579a..26119393 100644
--- a/src/ui/Theme.cpp
+++ b/src/ui/Theme.cpp
@@ -60,12 +60,15 @@ Theme::Theme(std::string_view theme)
separator_ = p.mid().color();
if (theme == "light") {
sidebarBackground_ = QColor("#233649");
+ alternateButton_ = QColor("#ccc");
red_ = QColor("#a82353");
} else if (theme == "dark") {
sidebarBackground_ = QColor("#2d3139");
+ alternateButton_ = QColor("#414A59");
red_ = QColor("#a82353");
} else {
sidebarBackground_ = p.window().color();
+ alternateButton_ = p.dark().color();
red_ = QColor("red");
}
}
diff --git a/src/ui/Theme.h b/src/ui/Theme.h
index 834571c0..b5bcd4dd 100644
--- a/src/ui/Theme.h
+++ b/src/ui/Theme.h
@@ -65,6 +65,7 @@ class Theme : public QPalette
{
Q_GADGET
Q_PROPERTY(QColor sidebarBackground READ sidebarBackground CONSTANT)
+ Q_PROPERTY(QColor alternateButton READ alternateButton CONSTANT)
Q_PROPERTY(QColor separator READ separator CONSTANT)
Q_PROPERTY(QColor red READ red CONSTANT)
public:
@@ -73,9 +74,10 @@ public:
static QPalette paletteFromTheme(std::string_view theme);
QColor sidebarBackground() const { return sidebarBackground_; }
+ QColor alternateButton() const { return alternateButton_; }
QColor separator() const { return separator_; }
QColor red() const { return red_; }
private:
- QColor sidebarBackground_, separator_, red_;
+ QColor sidebarBackground_, separator_, red_, alternateButton_;
};
|