diff --git a/include/AvatarProvider.h b/include/AvatarProvider.h
index 95a5765d..dabd609c 100644
--- a/include/AvatarProvider.h
+++ b/include/AvatarProvider.h
@@ -17,45 +17,30 @@
#pragma once
+#include <QHash>
#include <QImage>
#include <QSharedPointer>
-#include <QUrl>
#include <functional>
class MatrixClient;
class TimelineItem;
-//! Saved cache data per user.
-struct AvatarData
-{
- //! The avatar image of the user.
- QImage img;
- //! The url that was used to download the avatar.
- QUrl url;
-};
-
class AvatarProvider : public QObject
{
Q_OBJECT
public:
- static void init(QSharedPointer<MatrixClient> client);
+ static void init(QSharedPointer<MatrixClient> client) { client_ = client; }
//! The callback is called with the downloaded avatar for the given user
//! or the avatar is downloaded first and then saved for re-use.
- static void resolve(const QString &userId,
+ static void resolve(const QString &room_id,
+ const QString &userId,
QObject *receiver,
std::function<void(QImage)> callback);
- //! Used to initialize the mapping user -> avatar url.
- static void setAvatarUrl(const QString &userId, const QUrl &url);
//! Remove all saved data.
static void clear() { avatars_.clear(); };
private:
- //! Update the cache with the downloaded avatar.
- static void updateAvatar(const QString &uid, const QImage &img);
-
static QSharedPointer<MatrixClient> client_;
-
- using UserID = QString;
- static std::map<UserID, AvatarData> avatars_;
+ static QHash<QString, QImage> avatars_;
};
diff --git a/include/Cache.h b/include/Cache.h
index 93668b8c..b3bc085b 100644
--- a/include/Cache.h
+++ b/include/Cache.h
@@ -17,12 +17,23 @@
#pragma once
+#include <QDebug>
#include <QDir>
#include <json.hpp>
#include <lmdb++.h>
#include <mtx/responses.hpp>
#include "RoomState.h"
+#include "Utils.h"
+
+struct SearchResult
+{
+ QString user_id;
+ QString display_name;
+};
+
+Q_DECLARE_METATYPE(SearchResult)
+Q_DECLARE_METATYPE(QVector<SearchResult>)
//! Used to uniquely identify a list of read receipts.
struct ReadReceiptKey
@@ -44,6 +55,60 @@ from_json(const json &j, ReadReceiptKey &key)
key.room_id = j.at("room_id").get<std::string>();
}
+//! UI info associated with a room.
+struct RoomInfo
+{
+ //! The calculated name of the room.
+ std::string name;
+ //! The topic of the room.
+ std::string topic;
+ //! The calculated avatar url of the room.
+ std::string avatar_url;
+ //! Whether or not the room is an invite.
+ bool is_invite = false;
+};
+
+inline void
+to_json(json &j, const RoomInfo &info)
+{
+ j["name"] = info.name;
+ j["topic"] = info.topic;
+ j["avatar_url"] = info.avatar_url;
+ j["is_invite"] = info.is_invite;
+}
+
+inline void
+from_json(const json &j, RoomInfo &info)
+{
+ info.name = j.at("name");
+ info.topic = j.at("topic");
+ info.avatar_url = j.at("avatar_url");
+ info.is_invite = j.at("is_invite");
+}
+
+//! Basic information per member;
+struct MemberInfo
+{
+ std::string name;
+ std::string avatar_url;
+};
+
+inline void
+to_json(json &j, const MemberInfo &info)
+{
+ j["name"] = info.name;
+ j["avatar_url"] = info.avatar_url;
+}
+
+inline void
+from_json(const json &j, MemberInfo &info)
+{
+ info.name = j.at("name");
+ info.avatar_url = j.at("avatar_url");
+}
+
+Q_DECLARE_METATYPE(RoomInfo)
+
class Cache : public QObject
{
Q_OBJECT
@@ -51,22 +116,50 @@ class Cache : public QObject
public:
Cache(const QString &userId, QObject *parent = nullptr);
- void setState(const QString &nextBatchToken,
- const std::map<QString, QSharedPointer<RoomState>> &states);
+ static QHash<QString, QString> DisplayNames;
+ static QHash<QString, QString> AvatarUrls;
+
+ static std::string displayName(const std::string &room_id, const std::string &user_id);
+ static QString displayName(const QString &room_id, const QString &user_id);
+ static QString avatarUrl(const QString &room_id, const QString &user_id);
+
+ static void removeDisplayName(const QString &room_id, const QString &user_id);
+ static void removeAvatarUrl(const QString &room_id, const QString &user_id);
+
+ static void insertDisplayName(const QString &room_id,
+ const QString &user_id,
+ const QString &display_name);
+ static void insertAvatarUrl(const QString &room_id,
+ const QString &user_id,
+ const QString &avatar_url);
+
+ //! Load saved data for the display names & avatars.
+ void populateMembers();
+ std::vector<std::string> joinedRooms();
+
+ QMap<QString, RoomInfo> roomInfo();
+
+ //! Calculate & return the name of the room.
+ QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
+ //! Retrieve the topic of the room if any.
+ QString getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
+ //! Retrieve the room avatar's url if any.
+ QString getRoomAvatarUrl(lmdb::txn &txn,
+ lmdb::dbi &statesdb,
+ lmdb::dbi &membersdb,
+ const QString &room_id);
+
+ void saveState(const mtx::responses::Sync &res);
bool isInitialized() const;
QString nextBatchToken() const;
- void states();
-
- using Invites = std::map<std::string, mtx::responses::InvitedRoom>;
- Invites invites();
- void setInvites(const Invites &invites);
void deleteData();
- void unmount() { isMounted_ = false; };
- void removeRoom(const QString &roomid);
- void removeInvite(const QString &roomid);
+ void removeInvite(const std::string &room_id);
+ void removeRoom(lmdb::txn &txn, const std::string &roomid);
+ void removeRoom(const std::string &roomid);
+ void removeRoom(const QString &roomid) { removeRoom(roomid.toStdString()); };
void setup();
bool isFormatValid();
@@ -88,24 +181,206 @@ public:
QByteArray image(const QString &url) const;
void saveImage(const QString &url, const QByteArray &data);
-signals:
- void statesLoaded(std::map<QString, RoomState> states);
+ std::vector<std::string> roomsWithStateUpdates(const mtx::responses::Sync &res);
+ std::map<QString, RoomInfo> getRoomInfo(const std::vector<std::string> &rooms);
+ std::map<QString, RoomInfo> roomUpdates(const mtx::responses::Sync &sync)
+ {
+ return getRoomInfo(roomsWithStateUpdates(sync));
+ }
+
+ QVector<SearchResult> getAutocompleteMatches(const std::string &room_id,
+ const std::string &query,
+ std::uint8_t max_items = 5);
private:
+ //! Save an invited room.
+ void saveInvite(lmdb::txn &txn,
+ lmdb::dbi &statesdb,
+ lmdb::dbi &membersdb,
+ const mtx::responses::InvitedRoom &room);
+
+ QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
+ QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
+ QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
+
+ //! Remove a room from the cache.
+ // void removeLeftRoom(lmdb::txn &txn, const std::string &room_id);
+ template<class T>
+ void saveStateEvents(lmdb::txn &txn,
+ const lmdb::dbi &statesdb,
+ const lmdb::dbi &membersdb,
+ const std::string &room_id,
+ const std::vector<T> &events)
+ {
+ for (const auto &e : events)
+ saveStateEvent(txn, statesdb, membersdb, room_id, e);
+ }
+
+ template<class T>
+ void saveStateEvent(lmdb::txn &txn,
+ const lmdb::dbi &statesdb,
+ const lmdb::dbi &membersdb,
+ const std::string &room_id,
+ const T &event)
+ {
+ using namespace mtx::events;
+ using namespace mtx::events::state;
+
+ if (mpark::holds_alternative<StateEvent<Member>>(event)) {
+ const auto e = mpark::get<StateEvent<Member>>(event);
+
+ switch (e.content.membership) {
+ //
+ // We only keep users with invite or join membership.
+ //
+ case Membership::Invite:
+ case Membership::Join: {
+ auto display_name = e.content.display_name.empty()
+ ? e.state_key
+ : e.content.display_name;
+
+ // Lightweight representation of a member.
+ MemberInfo tmp{display_name, e.content.avatar_url};
+
+ lmdb::dbi_put(txn,
+ membersdb,
+ lmdb::val(e.state_key),
+ lmdb::val(json(tmp).dump()));
+
+ insertDisplayName(QString::fromStdString(room_id),
+ QString::fromStdString(e.state_key),
+ QString::fromStdString(display_name));
+
+ insertAvatarUrl(QString::fromStdString(room_id),
+ QString::fromStdString(e.state_key),
+ QString::fromStdString(e.content.avatar_url));
+
+ break;
+ }
+ default: {
+ lmdb::dbi_del(
+ txn, membersdb, lmdb::val(e.state_key), lmdb::val(""));
+
+ removeDisplayName(QString::fromStdString(room_id),
+ QString::fromStdString(e.state_key));
+ removeAvatarUrl(QString::fromStdString(room_id),
+ QString::fromStdString(e.state_key));
+
+ break;
+ }
+ }
+
+ return;
+ }
+
+ if (!isStateEvent(event))
+ return;
+
+ mpark::visit(
+ [&txn, &statesdb](auto e) {
+ lmdb::dbi_put(
+ txn, statesdb, lmdb::val(to_string(e.type)), lmdb::val(json(e).dump()));
+ },
+ event);
+ }
+
+ template<class T>
+ bool isStateEvent(const T &e)
+ {
+ using namespace mtx::events;
+ using namespace mtx::events::state;
+
+ return mpark::holds_alternative<StateEvent<Aliases>>(e) ||
+ mpark::holds_alternative<StateEvent<state::Avatar>>(e) ||
+ mpark::holds_alternative<StateEvent<CanonicalAlias>>(e) ||
+ mpark::holds_alternative<StateEvent<Create>>(e) ||
+ mpark::holds_alternative<StateEvent<GuestAccess>>(e) ||
+ mpark::holds_alternative<StateEvent<HistoryVisibility>>(e) ||
+ mpark::holds_alternative<StateEvent<JoinRules>>(e) ||
+ mpark::holds_alternative<StateEvent<Name>>(e) ||
+ mpark::holds_alternative<StateEvent<PowerLevels>>(e) ||
+ mpark::holds_alternative<StateEvent<Topic>>(e);
+ }
+
+ template<class T>
+ bool containsStateUpdates(const T &e)
+ {
+ using namespace mtx::events;
+ using namespace mtx::events::state;
+
+ return mpark::holds_alternative<StateEvent<state::Avatar>>(e) ||
+ mpark::holds_alternative<StateEvent<CanonicalAlias>>(e) ||
+ mpark::holds_alternative<StateEvent<Name>>(e) ||
+ mpark::holds_alternative<StateEvent<Member>>(e) ||
+ mpark::holds_alternative<StateEvent<Topic>>(e);
+ }
+
+ bool containsStateUpdates(const mtx::events::collections::StrippedEvents &e)
+ {
+ using namespace mtx::events;
+ using namespace mtx::events::state;
+
+ return mpark::holds_alternative<StrippedEvent<state::Avatar>>(e) ||
+ mpark::holds_alternative<StrippedEvent<CanonicalAlias>>(e) ||
+ mpark::holds_alternative<StrippedEvent<Name>>(e) ||
+ mpark::holds_alternative<StrippedEvent<Member>>(e) ||
+ mpark::holds_alternative<StrippedEvent<Topic>>(e);
+ }
+
+ void saveInvites(lmdb::txn &txn,
+ const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
+
+ //! Remove any saved invites that are not found in the input.
+ void removeStaleInvites(lmdb::txn &txn, const std::map<std::string, bool> &curr);
+
+ //! Sends signals for the rooms that are removed.
+ void removeLeftRooms(lmdb::txn &txn,
+ const std::map<std::string, mtx::responses::LeftRoom> &rooms)
+ {
+ for (const auto &room : rooms)
+ removeRoom(txn, room.first);
+ }
+
+ lmdb::dbi getInviteStatesDb(lmdb::txn &txn, const std::string &room_id)
+ {
+ return lmdb::dbi::open(
+ txn, std::string(room_id + "/invite_state").c_str(), MDB_CREATE);
+ }
+
+ lmdb::dbi getInviteMembersDb(lmdb::txn &txn, const std::string &room_id)
+ {
+ return lmdb::dbi::open(
+ txn, std::string(room_id + "/invite_members").c_str(), MDB_CREATE);
+ }
+
+ lmdb::dbi getStatesDb(lmdb::txn &txn, const std::string &room_id)
+ {
+ return lmdb::dbi::open(txn, std::string(room_id + "/state").c_str(), MDB_CREATE);
+ }
+
+ lmdb::dbi getMembersDb(lmdb::txn &txn, const std::string &room_id)
+ {
+ return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);
+ }
+
+ QString getDisplayName(const mtx::events::StateEvent<mtx::events::state::Member> &event)
+ {
+ if (!event.content.display_name.empty())
+ return QString::fromStdString(event.content.display_name);
+
+ return QString::fromStdString(event.state_key);
+ }
+
+ void setNextBatchToken(lmdb::txn &txn, const std::string &token);
void setNextBatchToken(lmdb::txn &txn, const QString &token);
- void insertRoomState(lmdb::txn &txn,
- const QString &roomid,
- const QSharedPointer<RoomState> &state);
lmdb::env env_;
- lmdb::dbi stateDb_;
- lmdb::dbi roomDb_;
+ lmdb::dbi syncStateDb_;
+ lmdb::dbi roomsDb_;
lmdb::dbi invitesDb_;
- lmdb::dbi imagesDb_;
+ lmdb::dbi mediaDb_;
lmdb::dbi readReceiptsDb_;
- bool isMounted_;
-
- QString userId_;
+ QString localUserId_;
QString cacheDirectory_;
};
diff --git a/include/ChatPage.h b/include/ChatPage.h
index 25cd8615..a6789aea 100644
--- a/include/ChatPage.h
+++ b/include/ChatPage.h
@@ -24,16 +24,16 @@
#include <QTimer>
#include <QWidget>
+#include "Cache.h"
#include "CommunitiesList.h"
#include "Community.h"
+
#include <mtx.hpp>
-class Cache;
class MatrixClient;
class OverlayModal;
class QuickSwitcher;
class RoomList;
-class RoomSettings;
class RoomState;
class SideBarActions;
class Splitter;
@@ -52,6 +52,9 @@ constexpr int CONSENSUS_TIMEOUT = 1000;
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
+Q_DECLARE_METATYPE(mtx::responses::Rooms);
+Q_DECLARE_METATYPE(std::vector<std::string>);
+
class ChatPage : public QWidget
{
Q_OBJECT
@@ -88,6 +91,14 @@ signals:
void showLoginPage(const QString &msg);
void showUserSettingsPage();
void showOverlayProgressBar();
+ void startConsesusTimer();
+
+ void initializeRoomList(QMap<QString, RoomInfo>);
+ void initializeViews(const mtx::responses::Rooms &rooms);
+ void initializeEmptyViews(const std::vector<std::string> &rooms);
+ void syncUI(const mtx::responses::Rooms &rooms);
+ void continueSync(const QString &next_batch);
+ void syncRoomlist(const std::map<QString, RoomInfo> &updates);
private slots:
void showUnreadMessageNotification(int count);
@@ -98,9 +109,9 @@ private slots:
void syncCompleted(const mtx::responses::Sync &response);
void changeTopRoomInfo(const QString &room_id);
void logout();
- void addRoom(const QString &room_id);
void removeRoom(const QString &room_id);
- void removeInvite(const QString &room_id);
+ //! Handles initial sync failures.
+ void retryInitialSync(int status_code = -1);
private:
static ChatPage *instance_;
@@ -110,28 +121,11 @@ private:
using Membership = mtx::events::StateEvent<mtx::events::state::Member>;
using Memberships = std::map<std::string, Membership>;
- using JoinedRooms = std::map<std::string, mtx::responses::JoinedRoom>;
- using LeftRooms = std::map<std::string, mtx::responses::LeftRoom>;
- using InvitedRooms = std::map<std::string, mtx::responses::InvitedRoom>;
-
+ using LeftRooms = std::map<std::string, mtx::responses::LeftRoom>;
void removeLeftRooms(const LeftRooms &rooms);
- void updateJoinedRooms(const JoinedRooms &rooms);
- void trackInvites(const InvitedRooms &rooms)
- {
- for (const auto &invite : rooms)
- roomInvites_[QString::fromStdString(invite.first)] = true;
- }
-
- std::map<QString, QSharedPointer<RoomState>> generateMembershipDifference(
- const JoinedRooms &rooms,
- const RoomStates &states) const;
void updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids);
- using MemberEvent = mtx::events::StateEvent<mtx::events::state::Member>;
- void updateUserDisplayName(const MemberEvent &event);
- void updateUserAvatarUrl(const MemberEvent &event);
-
void loadStateFromCache();
void deleteConfigs();
void resetUI();
@@ -141,10 +135,6 @@ private:
template<class Collection>
Memberships getMemberships(const std::vector<Collection> &events) const;
- template<class Collection>
- void updateUserMetadata(const std::vector<Collection> &collection);
-
- void retryInitialSync(int status_code = -1);
//! Update the room with the new notification count.
void updateRoomNotificationCount(const QString &room_id, uint16_t notification_count);
@@ -186,8 +176,6 @@ private:
UserInfoWidget *user_info_widget_;
RoomStates roomStates_;
- std::map<QString, QSharedPointer<RoomSettings>> roomSettings_;
- std::map<QString, bool> roomInvites_;
std::map<QString, QSharedPointer<Community>> communities_;
@@ -212,22 +200,6 @@ private:
};
template<class Collection>
-void
-ChatPage::updateUserMetadata(const std::vector<Collection> &collection)
-{
- using Member = mtx::events::StateEvent<mtx::events::state::Member>;
-
- for (const auto &event : collection) {
- if (mpark::holds_alternative<Member>(event)) {
- auto member = mpark::get<Member>(event);
-
- updateUserAvatarUrl(member);
- updateUserDisplayName(member);
- }
- }
-}
-
-template<class Collection>
std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>>
ChatPage::getMemberships(const std::vector<Collection> &collection) const
{
diff --git a/include/MatrixClient.h b/include/MatrixClient.h
index 62ac2088..d16031d3 100644
--- a/include/MatrixClient.h
+++ b/include/MatrixClient.h
@@ -32,6 +32,8 @@ signals:
void avatarDownloaded(const QImage &img);
};
+Q_DECLARE_METATYPE(mtx::responses::Sync)
+
/*
* MatrixClient provides the high level API to communicate with
* a Matrix homeserver. All the responses are returned through signals.
diff --git a/include/RoomInfoListItem.h b/include/RoomInfoListItem.h
index 35214c30..d06a759e 100644
--- a/include/RoomInfoListItem.h
+++ b/include/RoomInfoListItem.h
@@ -24,11 +24,9 @@
#include <mtx/responses.hpp>
-#include "RoomState.h"
-
class Menu;
class RippleOverlay;
-class RoomSettings;
+struct RoomInfo;
struct DescInfo
{
@@ -70,24 +68,13 @@ class RoomInfoListItem : public QWidget
Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
public:
- RoomInfoListItem(QSharedPointer<RoomSettings> settings,
- QSharedPointer<RoomState> state,
- QString room_id,
- QWidget *parent = 0);
-
- RoomInfoListItem(QString room_id, mtx::responses::InvitedRoom room, QWidget *parent = 0);
+ RoomInfoListItem(QString room_id, RoomInfo info, QWidget *parent = 0);
void updateUnreadMessageCount(int count);
void clearUnreadMessageCount() { updateUnreadMessageCount(0); };
- void setState(QSharedPointer<RoomState> state)
- {
- state_ = state;
- update();
- }
QString roomId() { return roomId_; }
bool isPressed() const { return isPressed_; }
- QSharedPointer<RoomState> state() const { return state_; }
int unreadMessageCount() const { return unreadMsgCount_; }
void setAvatar(const QImage &avatar_image);
@@ -133,6 +120,15 @@ public:
void setBubbleFgColor(QColor &color) { bubbleFgColor_ = color; }
void setBubbleBgColor(QColor &color) { bubbleBgColor_ = color; }
+ void setRoomName(const QString &name) { roomName_ = name; }
+ void setRoomType(bool isInvite)
+ {
+ if (isInvite)
+ roomType_ = RoomType::Invited;
+ else
+ roomType_ = RoomType::Joined;
+ }
+
signals:
void clicked(const QString &room_id);
void leaveRoom(const QString &room_id);
@@ -150,15 +146,7 @@ protected:
private:
void init(QWidget *parent);
- QString roomName()
- {
- if (roomType_ == RoomType::Joined)
- return state_->getName();
-
- return roomName_;
- }
-
- QString notificationText();
+ QString roomName() { return roomName_; }
RippleOverlay *ripple_overlay_;
@@ -170,9 +158,6 @@ private:
RoomType roomType_ = RoomType::Joined;
- // State information for the joined rooms.
- QSharedPointer<RoomState> state_;
-
// State information for the invited rooms.
mtx::responses::InvitedRoom invitedRoom_;
@@ -184,11 +169,8 @@ private:
QPixmap roomAvatar_;
Menu *menu_;
- QAction *toggleNotifications_;
QAction *leaveRoom_;
- QSharedPointer<RoomSettings> roomSettings_;
-
bool isPressed_ = false;
int unreadMsgCount_ = 0;
diff --git a/include/RoomList.h b/include/RoomList.h
index bcac8094..f9cdc210 100644
--- a/include/RoomList.h
+++ b/include/RoomList.h
@@ -23,14 +23,13 @@
#include <QVBoxLayout>
#include <QWidget>
+#include "Cache.h"
#include <mtx.hpp>
class LeaveRoomDialog;
class MatrixClient;
-class Cache;
class OverlayModal;
class RoomInfoListItem;
-class RoomSettings;
class RoomState;
class Sync;
class UserSettings;
@@ -46,22 +45,18 @@ public:
QWidget *parent = 0);
void setCache(QSharedPointer<Cache> cache) { cache_ = cache; }
- void setInitialRooms(const std::map<QString, QSharedPointer<RoomSettings>> &settings,
- const std::map<QString, QSharedPointer<RoomState>> &states);
- void sync(const std::map<QString, QSharedPointer<RoomState>> &states,
- const std::map<QString, QSharedPointer<RoomSettings>> &settings);
- void syncInvites(const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
+ void initialize(const QMap<QString, RoomInfo> &info);
+ void sync(const std::map<QString, RoomInfo> &info);
- void clear();
+ void clear() { rooms_.clear(); };
void updateAvatar(const QString &room_id, const QString &url);
- void addRoom(const QSharedPointer<RoomSettings> &settings,
- const QSharedPointer<RoomState> &state,
- const QString &room_id);
- void addInvitedRoom(const QString &room_id, const mtx::responses::InvitedRoom &room);
+ void addRoom(const QString &room_id, const RoomInfo &info);
+ void addInvitedRoom(const QString &room_id, const RoomInfo &info);
void removeRoom(const QString &room_id, bool reset);
void setFilterRooms(bool filterRooms);
void setRoomFilter(std::vector<QString> room_ids);
+ void updateRoom(const QString &room_id, const RoomInfo &info);
signals:
void roomChanged(const QString &room_id);
diff --git a/include/SuggestionsPopup.hpp b/include/SuggestionsPopup.hpp
index dcbe52fa..64a86d7a 100644
--- a/include/SuggestionsPopup.hpp
+++ b/include/SuggestionsPopup.hpp
@@ -6,15 +6,7 @@
#include <QWidget>
class Avatar;
-
-struct SearchResult
-{
- QString user_id;
- QString display_name;
-};
-
-Q_DECLARE_METATYPE(SearchResult)
-Q_DECLARE_METATYPE(QVector<SearchResult>)
+struct SearchResult;
class PopupItem : public QWidget
{
diff --git a/include/TextInputWidget.h b/include/TextInputWidget.h
index 7a52ea77..1f122504 100644
--- a/include/TextInputWidget.h
+++ b/include/TextInputWidget.h
@@ -36,7 +36,7 @@
#include "emoji/PickButton.h"
-class RoomState;
+class Cache;
namespace dialogs {
class PreviewUploadOverlay;
@@ -131,12 +131,12 @@ public:
QColor borderColor() const { return borderColor_; }
void setBorderColor(QColor &color) { borderColor_ = color; }
+ void setCache(QSharedPointer<Cache> cache) { cache_ = cache; }
public slots:
void openFileSelection();
void hideUploadSpinner();
void focusLineEdit() { input_->setFocus(); }
- void setRoomState(QSharedPointer<RoomState> state) { currState_ = state; }
private slots:
void addSelectedEmoji(const QString &emoji);
@@ -172,8 +172,7 @@ private:
FlatButton *sendMessageBtn_;
emoji::PickButton *emojiBtn_;
- //! State of the current room.
- QSharedPointer<RoomState> currState_;
+ QSharedPointer<Cache> cache_;
QColor borderColor_;
};
diff --git a/include/Utils.h b/include/Utils.h
index cbecb4ac..5586a479 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -16,7 +16,7 @@ descriptiveTime(const QDateTime &then);
//! Generate a message description from the event to be displayed
//! in the RoomList.
DescInfo
-getMessageDescription(const TimelineEvent &event, const QString &localUser);
+getMessageDescription(const TimelineEvent &event, const QString &localUser, const QString &room_id);
//! Get the first character of a string, taking into account that
//! surrogate pairs might be in use.
diff --git a/include/dialogs/ReadReceipts.h b/include/dialogs/ReadReceipts.h
index 8f860b46..bd4e4fc5 100644
--- a/include/dialogs/ReadReceipts.h
+++ b/include/dialogs/ReadReceipts.h
@@ -16,7 +16,10 @@ class ReceiptItem : public QWidget
Q_OBJECT
public:
- ReceiptItem(QWidget *parent, const QString &user_id, uint64_t timestamp);
+ ReceiptItem(QWidget *parent,
+ const QString &user_id,
+ uint64_t timestamp,
+ const QString &room_id);
private:
QString dateFormat(const QDateTime &then) const;
diff --git a/include/timeline/TimelineItem.h b/include/timeline/TimelineItem.h
index b7a5623f..952fb661 100644
--- a/include/timeline/TimelineItem.h
+++ b/include/timeline/TimelineItem.h
@@ -26,9 +26,9 @@
#include <QStyleOption>
#include "AvatarProvider.h"
+#include "Cache.h"
#include "ChatPage.h"
#include "RoomInfoListItem.h"
-#include "TimelineViewManager.h"
#include "Utils.h"
class ImageItem;
@@ -43,12 +43,15 @@ class TimelineItem : public QWidget
public:
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent = 0);
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent = 0);
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent = 0);
// For local messages.
@@ -57,28 +60,49 @@ public:
const QString &userid,
QString body,
bool withSender,
+ const QString &room_id,
QWidget *parent = 0);
// m.image
- TimelineItem(ImageItem *item, const QString &userid, bool withSender, QWidget *parent = 0);
- TimelineItem(FileItem *item, const QString &userid, bool withSender, QWidget *parent = 0);
- TimelineItem(AudioItem *item, const QString &userid, bool withSender, QWidget *parent = 0);
- TimelineItem(VideoItem *item, const QString &userid, bool withSender, QWidget *parent = 0);
+ TimelineItem(ImageItem *item,
+ const QString &userid,
+ bool withSender,
+ const QString &room_id,
+ QWidget *parent = 0);
+ TimelineItem(FileItem *item,
+ const QString &userid,
+ bool withSender,
+ const QString &room_id,
+ QWidget *parent = 0);
+ TimelineItem(AudioItem *item,
+ const QString &userid,
+ bool withSender,
+ const QString &room_id,
+ QWidget *parent = 0);
+ TimelineItem(VideoItem *item,
+ const QString &userid,
+ bool withSender,
+ const QString &room_id,
+ QWidget *parent = 0);
TimelineItem(ImageItem *img,
const mtx::events::RoomEvent<mtx::events::msg::Image> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent);
TimelineItem(FileItem *file,
const mtx::events::RoomEvent<mtx::events::msg::File> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent);
TimelineItem(AudioItem *audio,
const mtx::events::RoomEvent<mtx::events::msg::Audio> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent);
TimelineItem(VideoItem *video,
const mtx::events::RoomEvent<mtx::events::msg::Video> &e,
bool with_sender,
+ const QString &room_id,
QWidget *parent);
void setUserAvatar(const QImage &pixmap);
@@ -86,7 +110,7 @@ public:
QString eventId() const { return event_id_; }
void setEventId(const QString &event_id) { event_id_ = event_id; }
void markReceived();
- void setRoomId(const QString &room_id) { room_id_ = room_id; }
+ void setRoomId(QString room_id) { room_id_ = room_id; }
void sendReadReceipt() const
{
if (!event_id_.isEmpty())
@@ -159,7 +183,7 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget,
const QString &msgDescription,
bool withSender)
{
- auto displayName = TimelineViewManager::displayName(userid);
+ auto displayName = Cache::displayName(room_id_, userid);
auto timestamp = QDateTime::currentDateTime();
descriptionMsg_ = {"You",
@@ -183,7 +207,7 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget,
messageLayout_->addLayout(headerLayout_, 1);
AvatarProvider::resolve(
- userid, this, [this](const QImage &img) { setUserAvatar(img); });
+ room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
} else {
setupSimpleLayout();
@@ -208,7 +232,7 @@ TimelineItem::setupWidgetLayout(Widget *widget,
const auto sender = QString::fromStdString(event.sender);
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
- auto displayName = TimelineViewManager::displayName(sender);
+ auto displayName = Cache::displayName(room_id_, sender);
QSettings settings;
descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName,
@@ -232,7 +256,7 @@ TimelineItem::setupWidgetLayout(Widget *widget,
messageLayout_->addLayout(headerLayout_, 1);
AvatarProvider::resolve(
- sender, this, [this](const QImage &img) { setUserAvatar(img); });
+ room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
} else {
setupSimpleLayout();
diff --git a/include/timeline/TimelineView.h b/include/timeline/TimelineView.h
index b38d6a7d..6f70dd1c 100644
--- a/include/timeline/TimelineView.h
+++ b/include/timeline/TimelineView.h
@@ -259,8 +259,7 @@ TimelineView::addUserMessage(const QString &url,
auto widget = new Widget(client_, url, trimmed, size, this);
TimelineItem *view_item =
- new TimelineItem(widget, local_user_, with_sender, scroll_widget_);
- view_item->setRoomId(room_id_);
+ new TimelineItem(widget, local_user_, with_sender, room_id_, scroll_widget_);
addTimelineItem(view_item);
@@ -280,8 +279,7 @@ template<class Event>
TimelineItem *
TimelineView::createTimelineItem(const Event &event, bool withSender)
{
- TimelineItem *item = new TimelineItem(event, withSender, scroll_widget_);
- item->setRoomId(room_id_);
+ TimelineItem *item = new TimelineItem(event, withSender, room_id_, scroll_widget_);
return item;
}
@@ -290,8 +288,7 @@ TimelineItem *
TimelineView::createTimelineItem(const Event &event, bool withSender)
{
auto eventWidget = new Widget(client_, event);
- auto item = new TimelineItem(eventWidget, event, withSender, scroll_widget_);
- item->setRoomId(room_id_);
+ auto item = new TimelineItem(eventWidget, event, withSender, room_id_, scroll_widget_);
return item;
}
diff --git a/include/timeline/TimelineViewManager.h b/include/timeline/TimelineViewManager.h
index c7bbd71a..4c994098 100644
--- a/include/timeline/TimelineViewManager.h
+++ b/include/timeline/TimelineViewManager.h
@@ -39,7 +39,7 @@ public:
// Initialize with timeline events.
void initialize(const mtx::responses::Rooms &rooms);
// Empty initialization.
- void initialize(const std::vector<QString> &rooms);
+ void initialize(const std::vector<std::string> &rooms);
void addRoom(const mtx::responses::JoinedRoom &room, const QString &room_id);
void addRoom(const QString &room_id);
@@ -51,9 +51,6 @@ public:
bool hasLoaded() const;
static QString chooseRandomColor();
- static QString displayName(const QString &userid);
-
- static std::map<QString, QString> DISPLAY_NAMES;
signals:
void clearRoomMessageCount(QString roomid);
|