mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 19:08:58 +03:00
parent
101bf47443
commit
f11044b5eb
12 changed files with 352 additions and 93 deletions
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <lmdb++.h>
|
#include <lmdb++.h>
|
||||||
|
#include <mtx/responses.hpp>
|
||||||
|
|
||||||
class RoomState;
|
class RoomState;
|
||||||
|
|
||||||
|
@ -33,10 +34,15 @@ public:
|
||||||
QString nextBatchToken() const;
|
QString nextBatchToken() const;
|
||||||
QMap<QString, RoomState> states();
|
QMap<QString, RoomState> states();
|
||||||
|
|
||||||
|
using Invites = std::map<std::string, mtx::responses::InvitedRoom>;
|
||||||
|
Invites invites();
|
||||||
|
void setInvites(const Invites &invites);
|
||||||
|
|
||||||
void deleteData();
|
void deleteData();
|
||||||
void unmount() { isMounted_ = false; };
|
void unmount() { isMounted_ = false; };
|
||||||
|
|
||||||
void removeRoom(const QString &roomid);
|
void removeRoom(const QString &roomid);
|
||||||
|
void removeInvite(const QString &roomid);
|
||||||
void setup();
|
void setup();
|
||||||
|
|
||||||
bool isFormatValid();
|
bool isFormatValid();
|
||||||
|
@ -49,6 +55,7 @@ private:
|
||||||
lmdb::env env_;
|
lmdb::env env_;
|
||||||
lmdb::dbi stateDb_;
|
lmdb::dbi stateDb_;
|
||||||
lmdb::dbi roomDb_;
|
lmdb::dbi roomDb_;
|
||||||
|
lmdb::dbi invitesDb_;
|
||||||
|
|
||||||
bool isMounted_;
|
bool isMounted_;
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ private slots:
|
||||||
void logout();
|
void logout();
|
||||||
void addRoom(const QString &room_id);
|
void addRoom(const QString &room_id);
|
||||||
void removeRoom(const QString &room_id);
|
void removeRoom(const QString &room_id);
|
||||||
|
void removeInvite(const QString &room_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using UserID = QString;
|
using UserID = QString;
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <mtx/responses.hpp>
|
||||||
|
|
||||||
#include "RoomState.h"
|
#include "RoomState.h"
|
||||||
|
|
||||||
class Menu;
|
class Menu;
|
||||||
|
@ -52,12 +54,17 @@ class RoomInfoListItem : public QWidget
|
||||||
Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
|
Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
|
||||||
setHighlightedSubtitleColor)
|
setHighlightedSubtitleColor)
|
||||||
|
|
||||||
|
Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor)
|
||||||
|
Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
||||||
RoomState state,
|
RoomState state,
|
||||||
QString room_id,
|
QString room_id,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
|
||||||
|
RoomInfoListItem(QString room_id, mtx::responses::InvitedRoom room, QWidget *parent = 0);
|
||||||
|
|
||||||
~RoomInfoListItem();
|
~RoomInfoListItem();
|
||||||
|
|
||||||
void updateUnreadMessageCount(int count);
|
void updateUnreadMessageCount(int count);
|
||||||
|
@ -71,35 +78,36 @@ public:
|
||||||
void setAvatar(const QImage &avatar_image);
|
void setAvatar(const QImage &avatar_image);
|
||||||
void setDescriptionMessage(const DescInfo &info);
|
void setDescriptionMessage(const DescInfo &info);
|
||||||
|
|
||||||
inline QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
|
QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
|
||||||
inline QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
|
QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
|
||||||
inline QColor backgroundColor() const { return backgroundColor_; }
|
QColor backgroundColor() const { return backgroundColor_; }
|
||||||
|
|
||||||
inline QColor highlightedTitleColor() const { return highlightedTitleColor_; }
|
QColor highlightedTitleColor() const { return highlightedTitleColor_; }
|
||||||
inline QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
|
QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
|
||||||
|
|
||||||
inline QColor titleColor() const { return titleColor_; }
|
QColor titleColor() const { return titleColor_; }
|
||||||
inline QColor subtitleColor() const { return subtitleColor_; }
|
QColor subtitleColor() const { return subtitleColor_; }
|
||||||
|
QColor btnColor() const { return btnColor_; }
|
||||||
|
QColor btnTextColor() const { return btnTextColor_; }
|
||||||
|
|
||||||
inline void setHighlightedBackgroundColor(QColor &color)
|
void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
|
||||||
{
|
void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
|
||||||
highlightedBackgroundColor_ = color;
|
void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
|
||||||
}
|
|
||||||
inline void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
|
|
||||||
inline void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
|
|
||||||
|
|
||||||
inline void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
|
void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
|
||||||
inline void setHighlightedSubtitleColor(QColor &color)
|
void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; }
|
||||||
{
|
|
||||||
highlightedSubtitleColor_ = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setTitleColor(QColor &color) { titleColor_ = color; }
|
void setTitleColor(QColor &color) { titleColor_ = color; }
|
||||||
inline void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
|
void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
|
||||||
|
|
||||||
|
void setBtnColor(QColor &color) { btnColor_ = color; }
|
||||||
|
void setBtnTextColor(QColor &color) { btnTextColor_ = color; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void clicked(const QString &room_id);
|
void clicked(const QString &room_id);
|
||||||
void leaveRoom(const QString &room_id);
|
void leaveRoom(const QString &room_id);
|
||||||
|
void acceptInvite(const QString &room_id);
|
||||||
|
void declineInvite(const QString &room_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setPressedState(bool state);
|
void setPressedState(bool state);
|
||||||
|
@ -111,15 +119,33 @@ protected:
|
||||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString notificationText();
|
void init(QWidget *parent);
|
||||||
|
QString roomName()
|
||||||
|
{
|
||||||
|
if (roomType_ == RoomType::Joined)
|
||||||
|
return state_.getName();
|
||||||
|
|
||||||
const int Padding = 7;
|
return roomName_;
|
||||||
const int IconSize = 48;
|
}
|
||||||
|
|
||||||
|
QString notificationText();
|
||||||
|
|
||||||
RippleOverlay *ripple_overlay_;
|
RippleOverlay *ripple_overlay_;
|
||||||
|
|
||||||
|
enum class RoomType
|
||||||
|
{
|
||||||
|
Joined,
|
||||||
|
Invited,
|
||||||
|
};
|
||||||
|
|
||||||
|
RoomType roomType_ = RoomType::Joined;
|
||||||
|
|
||||||
|
// State information for the joined rooms.
|
||||||
RoomState state_;
|
RoomState state_;
|
||||||
|
|
||||||
|
// State information for the invited rooms.
|
||||||
|
mtx::responses::InvitedRoom invitedRoom_;
|
||||||
|
|
||||||
QString roomId_;
|
QString roomId_;
|
||||||
QString roomName_;
|
QString roomName_;
|
||||||
|
|
||||||
|
@ -135,7 +161,6 @@ private:
|
||||||
|
|
||||||
bool isPressed_ = false;
|
bool isPressed_ = false;
|
||||||
|
|
||||||
int maxHeight_;
|
|
||||||
int unreadMsgCount_ = 0;
|
int unreadMsgCount_ = 0;
|
||||||
|
|
||||||
QColor highlightedBackgroundColor_;
|
QColor highlightedBackgroundColor_;
|
||||||
|
@ -147,4 +172,10 @@ private:
|
||||||
|
|
||||||
QColor titleColor_;
|
QColor titleColor_;
|
||||||
QColor subtitleColor_;
|
QColor subtitleColor_;
|
||||||
|
|
||||||
|
QColor btnColor_;
|
||||||
|
QColor btnTextColor_;
|
||||||
|
|
||||||
|
QRectF acceptBtnRegion_;
|
||||||
|
QRectF declineBtnRegion_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <mtx.hpp>
|
||||||
|
|
||||||
#include "dialogs/LeaveRoom.h"
|
#include "dialogs/LeaveRoom.h"
|
||||||
|
|
||||||
class LeaveRoomDialog;
|
class LeaveRoomDialog;
|
||||||
|
@ -47,17 +49,21 @@ public:
|
||||||
const QMap<QString, RoomState> &states);
|
const QMap<QString, RoomState> &states);
|
||||||
void sync(const QMap<QString, RoomState> &states,
|
void sync(const QMap<QString, RoomState> &states,
|
||||||
QMap<QString, QSharedPointer<RoomSettings>> &settings);
|
QMap<QString, QSharedPointer<RoomSettings>> &settings);
|
||||||
|
void syncInvites(const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void addRoom(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
|
void addRoom(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
|
||||||
const RoomState &state,
|
const RoomState &state,
|
||||||
const QString &room_id);
|
const QString &room_id);
|
||||||
|
void addInvitedRoom(const QString &room_id, const mtx::responses::InvitedRoom &room);
|
||||||
void removeRoom(const QString &room_id, bool reset);
|
void removeRoom(const QString &room_id, bool reset);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void roomChanged(const QString &room_id);
|
void roomChanged(const QString &room_id);
|
||||||
void totalUnreadMessageCountUpdated(int count);
|
void totalUnreadMessageCountUpdated(int count);
|
||||||
|
void acceptInvite(const QString &room_id);
|
||||||
|
void declineInvite(const QString &room_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
|
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ff5a9c887af1a8cffd13876abcf4c079a8525bd3
|
Subproject commit 582c6956c464e80f738c57ded239c3fb613f1c24
|
|
@ -49,6 +49,9 @@ RoomInfoListItem {
|
||||||
|
|
||||||
qproperty-highlightedTitleColor: #e4e5e8;
|
qproperty-highlightedTitleColor: #e4e5e8;
|
||||||
qproperty-highlightedSubtitleColor: #e4e5e8;
|
qproperty-highlightedSubtitleColor: #e4e5e8;
|
||||||
|
|
||||||
|
qproperty-btnColor: #414A59;
|
||||||
|
qproperty-btnTextColor: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadingIndicator {
|
LoadingIndicator {
|
||||||
|
|
|
@ -47,6 +47,9 @@ RoomInfoListItem {
|
||||||
|
|
||||||
qproperty-highlightedTitleColor: white;
|
qproperty-highlightedTitleColor: white;
|
||||||
qproperty-highlightedSubtitleColor: white;
|
qproperty-highlightedSubtitleColor: white;
|
||||||
|
|
||||||
|
qproperty-btnColor: #ccc;
|
||||||
|
qproperty-btnTextColor: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ChatPageLoadSpinner {
|
#ChatPageLoadSpinner {
|
||||||
|
|
|
@ -55,6 +55,9 @@ RoomInfoListItem {
|
||||||
|
|
||||||
qproperty-highlightedTitleColor: palette(light);
|
qproperty-highlightedTitleColor: palette(light);
|
||||||
qproperty-highlightedSubtitleColor: palette(light);
|
qproperty-highlightedSubtitleColor: palette(light);
|
||||||
|
|
||||||
|
qproperty-btnColor: palette(light);
|
||||||
|
qproperty-btnTextColor: palette(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadingIndicator {
|
LoadingIndicator {
|
||||||
|
|
95
src/Cache.cc
95
src/Cache.cc
|
@ -33,6 +33,7 @@ Cache::Cache(const QString &userId)
|
||||||
: env_{nullptr}
|
: env_{nullptr}
|
||||||
, stateDb_{0}
|
, stateDb_{0}
|
||||||
, roomDb_{0}
|
, roomDb_{0}
|
||||||
|
, invitesDb_{0}
|
||||||
, isMounted_{false}
|
, isMounted_{false}
|
||||||
, userId_{userId}
|
, userId_{userId}
|
||||||
{}
|
{}
|
||||||
|
@ -86,9 +87,10 @@ Cache::setup()
|
||||||
env_.open(statePath.toStdString().c_str());
|
env_.open(statePath.toStdString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
stateDb_ = lmdb::dbi::open(txn, "state", MDB_CREATE);
|
stateDb_ = lmdb::dbi::open(txn, "state", MDB_CREATE);
|
||||||
roomDb_ = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
|
roomDb_ = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
|
||||||
|
invitesDb_ = lmdb::dbi::open(txn, "invites", MDB_CREATE);
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
|
@ -174,6 +176,20 @@ Cache::removeRoom(const QString &roomid)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::removeInvite(const QString &room_id)
|
||||||
|
{
|
||||||
|
if (!isMounted_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto txn = lmdb::txn::begin(env_, nullptr, 0);
|
||||||
|
|
||||||
|
lmdb::dbi_del(
|
||||||
|
txn, invitesDb_, lmdb::val(room_id.toUtf8(), room_id.toUtf8().size()), nullptr);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
QMap<QString, RoomState>
|
QMap<QString, RoomState>
|
||||||
Cache::states()
|
Cache::states()
|
||||||
{
|
{
|
||||||
|
@ -310,3 +326,76 @@ Cache::setCurrentFormat()
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<std::string, mtx::responses::InvitedRoom>
|
||||||
|
Cache::invites()
|
||||||
|
{
|
||||||
|
std::map<std::string, mtx::responses::InvitedRoom> invites;
|
||||||
|
|
||||||
|
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||||
|
auto cursor = lmdb::cursor::open(txn, invitesDb_);
|
||||||
|
|
||||||
|
std::string room_id;
|
||||||
|
std::string payload;
|
||||||
|
|
||||||
|
mtx::responses::InvitedRoom state;
|
||||||
|
|
||||||
|
while (cursor.get(room_id, payload, MDB_NEXT)) {
|
||||||
|
state = nlohmann::json::parse(payload);
|
||||||
|
invites.emplace(room_id, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invites.size() > 0)
|
||||||
|
qDebug() << "Retrieved" << invites.size() << "invites";
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return invites;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::setInvites(const std::map<std::string, mtx::responses::InvitedRoom> &invites)
|
||||||
|
{
|
||||||
|
if (!isMounted_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using Aliases = mtx::events::StrippedEvent<mtx::events::state::Aliases>;
|
||||||
|
using Avatar = mtx::events::StrippedEvent<mtx::events::state::Avatar>;
|
||||||
|
using Member = mtx::events::StrippedEvent<mtx::events::state::Member>;
|
||||||
|
using Name = mtx::events::StrippedEvent<mtx::events::state::Name>;
|
||||||
|
using Topic = mtx::events::StrippedEvent<mtx::events::state::Topic>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
|
||||||
|
for (auto it = invites.cbegin(); it != invites.cend(); ++it) {
|
||||||
|
nlohmann::json j;
|
||||||
|
|
||||||
|
for (const auto &e : it->second.invite_state) {
|
||||||
|
if (mpark::holds_alternative<Name>(e)) {
|
||||||
|
j["invite_state"]["events"].push_back(mpark::get<Name>(e));
|
||||||
|
} else if (mpark::holds_alternative<Topic>(e)) {
|
||||||
|
j["invite_state"]["events"].push_back(mpark::get<Topic>(e));
|
||||||
|
} else if (mpark::holds_alternative<Avatar>(e)) {
|
||||||
|
j["invite_state"]["events"].push_back(
|
||||||
|
mpark::get<Avatar>(e));
|
||||||
|
} else if (mpark::holds_alternative<Aliases>(e)) {
|
||||||
|
j["invite_state"]["events"].push_back(
|
||||||
|
mpark::get<Aliases>(e));
|
||||||
|
} else if (mpark::holds_alternative<Member>(e)) {
|
||||||
|
j["invite_state"]["events"].push_back(
|
||||||
|
mpark::get<Member>(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lmdb::dbi_put(txn, invitesDb_, lmdb::val(it->first), lmdb::val(j.dump()));
|
||||||
|
}
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
} catch (const lmdb::error &e) {
|
||||||
|
qCritical() << "setInvitedRooms: " << e.what();
|
||||||
|
unmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -134,6 +134,9 @@ 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(room_list_, &RoomList::acceptInvite, client_.data(), &MatrixClient::joinRoom);
|
||||||
|
connect(room_list_, &RoomList::declineInvite, client_.data(), &MatrixClient::leaveRoom);
|
||||||
|
|
||||||
connect(view_manager_,
|
connect(view_manager_,
|
||||||
&TimelineViewManager::clearRoomMessageCount,
|
&TimelineViewManager::clearRoomMessageCount,
|
||||||
room_list_,
|
room_list_,
|
||||||
|
@ -266,8 +269,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
this,
|
this,
|
||||||
&ChatPage::updateOwnProfileInfo);
|
&ChatPage::updateOwnProfileInfo);
|
||||||
connect(client_.data(), &MatrixClient::ownAvatarRetrieved, this, &ChatPage::setOwnAvatar);
|
connect(client_.data(), &MatrixClient::ownAvatarRetrieved, this, &ChatPage::setOwnAvatar);
|
||||||
connect(client_.data(), &MatrixClient::joinedRoom, this, [=]() {
|
connect(client_.data(), &MatrixClient::joinedRoom, this, [=](const QString &room_id) {
|
||||||
emit showNotification("You joined the room.");
|
emit showNotification("You joined the room.");
|
||||||
|
removeInvite(room_id);
|
||||||
});
|
});
|
||||||
connect(client_.data(), &MatrixClient::invitedUser, this, [=](QString, QString user) {
|
connect(client_.data(), &MatrixClient::invitedUser, this, [=](QString, QString user) {
|
||||||
emit showNotification(QString("Invited user %1").arg(user));
|
emit showNotification(QString("Invited user %1").arg(user));
|
||||||
|
@ -400,8 +404,11 @@ ChatPage::syncCompleted(const mtx::responses::Sync &response)
|
||||||
|
|
||||||
auto stateDiff = generateMembershipDifference(response.rooms.join, state_manager_);
|
auto stateDiff = generateMembershipDifference(response.rooms.join, state_manager_);
|
||||||
QtConcurrent::run(cache_.data(), &Cache::setState, nextBatchToken, stateDiff);
|
QtConcurrent::run(cache_.data(), &Cache::setState, nextBatchToken, stateDiff);
|
||||||
|
QtConcurrent::run(cache_.data(), &Cache::setInvites, response.rooms.invite);
|
||||||
|
|
||||||
room_list_->sync(state_manager_, settingsManager_);
|
room_list_->sync(state_manager_, settingsManager_);
|
||||||
|
room_list_->syncInvites(response.rooms.invite);
|
||||||
|
|
||||||
view_manager_->sync(response.rooms);
|
view_manager_->sync(response.rooms);
|
||||||
|
|
||||||
client_->setNextBatchToken(nextBatchToken);
|
client_->setNextBatchToken(nextBatchToken);
|
||||||
|
@ -445,12 +452,14 @@ ChatPage::initialSyncCompleted(const mtx::responses::Sync &response)
|
||||||
&Cache::setState,
|
&Cache::setState,
|
||||||
QString::fromStdString(response.next_batch),
|
QString::fromStdString(response.next_batch),
|
||||||
state_manager_);
|
state_manager_);
|
||||||
|
QtConcurrent::run(cache_.data(), &Cache::setInvites, response.rooms.invite);
|
||||||
|
|
||||||
// Populate timelines with messages.
|
// Populate timelines with messages.
|
||||||
view_manager_->initialize(response.rooms);
|
view_manager_->initialize(response.rooms);
|
||||||
|
|
||||||
// Initialize room list.
|
// Initialize room list.
|
||||||
room_list_->setInitialRooms(settingsManager_, state_manager_);
|
room_list_->setInitialRooms(settingsManager_, state_manager_);
|
||||||
|
room_list_->syncInvites(response.rooms.invite);
|
||||||
|
|
||||||
client_->setNextBatchToken(QString::fromStdString(response.next_batch));
|
client_->setNextBatchToken(QString::fromStdString(response.next_batch));
|
||||||
client_->sync();
|
client_->sync();
|
||||||
|
@ -552,6 +561,7 @@ ChatPage::loadStateFromCache()
|
||||||
|
|
||||||
// Initialize room list from the restored state and settings.
|
// Initialize room list from the restored state and settings.
|
||||||
room_list_->setInitialRooms(settingsManager_, state_manager_);
|
room_list_->setInitialRooms(settingsManager_, state_manager_);
|
||||||
|
room_list_->syncInvites(cache_->invites());
|
||||||
|
|
||||||
// Check periodically if the timelines have been loaded.
|
// Check periodically if the timelines have been loaded.
|
||||||
consensusTimer_->start(CONSENSUS_TIMEOUT);
|
consensusTimer_->start(CONSENSUS_TIMEOUT);
|
||||||
|
@ -629,6 +639,7 @@ ChatPage::removeRoom(const QString &room_id)
|
||||||
settingsManager_.remove(room_id);
|
settingsManager_.remove(room_id);
|
||||||
try {
|
try {
|
||||||
cache_->removeRoom(room_id);
|
cache_->removeRoom(room_id);
|
||||||
|
cache_->removeInvite(room_id);
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
qCritical() << "The cache couldn't be updated: " << e.what();
|
qCritical() << "The cache couldn't be updated: " << e.what();
|
||||||
// TODO: Notify the user.
|
// TODO: Notify the user.
|
||||||
|
@ -638,6 +649,21 @@ ChatPage::removeRoom(const QString &room_id)
|
||||||
room_list_->removeRoom(room_id, room_id == current_room_);
|
room_list_->removeRoom(room_id, room_id == current_room_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ChatPage::removeInvite(const QString &room_id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
cache_->removeInvite(room_id);
|
||||||
|
} catch (const lmdb::error &e) {
|
||||||
|
qCritical() << "The cache couldn't be updated: " << e.what();
|
||||||
|
// TODO: Notify the user.
|
||||||
|
cache_->unmount();
|
||||||
|
cache_->deleteData();
|
||||||
|
}
|
||||||
|
|
||||||
|
room_list_->removeRoom(room_id, room_id == current_room_);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids)
|
ChatPage::updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
#include <variant.hpp>
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "Ripple.h"
|
#include "Ripple.h"
|
||||||
|
@ -26,6 +29,44 @@
|
||||||
#include "RoomSettings.h"
|
#include "RoomSettings.h"
|
||||||
#include "Theme.h"
|
#include "Theme.h"
|
||||||
|
|
||||||
|
constexpr int Padding = 7;
|
||||||
|
constexpr int IconSize = 48;
|
||||||
|
constexpr int MaxHeight = IconSize + 2 * Padding;
|
||||||
|
|
||||||
|
constexpr int InviteBtnX = IconSize + 2 * Padding;
|
||||||
|
constexpr int InviteBtnY = IconSize / 2 + Padding;
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomInfoListItem::init(QWidget *parent)
|
||||||
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
setMouseTracking(true);
|
||||||
|
setAttribute(Qt::WA_Hover);
|
||||||
|
|
||||||
|
setFixedHeight(MaxHeight);
|
||||||
|
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRect(0, 0, parent->width(), height());
|
||||||
|
|
||||||
|
ripple_overlay_ = new RippleOverlay(this);
|
||||||
|
ripple_overlay_->setClipPath(path);
|
||||||
|
ripple_overlay_->setClipping(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomInfoListItem::RoomInfoListItem(QString room_id,
|
||||||
|
mtx::responses::InvitedRoom room,
|
||||||
|
QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, roomType_{RoomType::Invited}
|
||||||
|
, invitedRoom_{std::move(room)}
|
||||||
|
, roomId_{std::move(room_id)}
|
||||||
|
{
|
||||||
|
init(parent);
|
||||||
|
|
||||||
|
roomAvatar_ = QString::fromStdString(invitedRoom_.avatar());
|
||||||
|
roomName_ = QString::fromStdString(invitedRoom_.name());
|
||||||
|
}
|
||||||
|
|
||||||
RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
||||||
RoomState state,
|
RoomState state,
|
||||||
QString room_id,
|
QString room_id,
|
||||||
|
@ -35,21 +76,9 @@ RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
||||||
, roomId_(room_id)
|
, roomId_(room_id)
|
||||||
, roomSettings_{settings}
|
, roomSettings_{settings}
|
||||||
, isPressed_(false)
|
, isPressed_(false)
|
||||||
, maxHeight_(IconSize + 2 * Padding)
|
|
||||||
, unreadMsgCount_(0)
|
, unreadMsgCount_(0)
|
||||||
{
|
{
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
init(parent);
|
||||||
setMouseTracking(true);
|
|
||||||
setAttribute(Qt::WA_Hover);
|
|
||||||
|
|
||||||
setFixedHeight(maxHeight_);
|
|
||||||
|
|
||||||
QPainterPath path;
|
|
||||||
path.addRect(0, 0, parent->width(), height());
|
|
||||||
|
|
||||||
ripple_overlay_ = new RippleOverlay(this);
|
|
||||||
ripple_overlay_->setClipPath(path);
|
|
||||||
ripple_overlay_->setClipping(true);
|
|
||||||
|
|
||||||
menu_ = new Menu(this);
|
menu_ = new Menu(this);
|
||||||
|
|
||||||
|
@ -99,82 +128,100 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
|
||||||
font.setPixelSize(conf::fontSize);
|
font.setPixelSize(conf::fontSize);
|
||||||
QFontMetrics metrics(font);
|
QFontMetrics metrics(font);
|
||||||
|
|
||||||
|
QPen titlePen(titleColor_);
|
||||||
|
QPen subtitlePen(subtitleColor_);
|
||||||
|
|
||||||
if (isPressed_) {
|
if (isPressed_) {
|
||||||
p.fillRect(rect(), highlightedBackgroundColor_);
|
p.fillRect(rect(), highlightedBackgroundColor_);
|
||||||
|
titlePen.setColor(highlightedTitleColor_);
|
||||||
|
subtitlePen.setColor(highlightedSubtitleColor_);
|
||||||
} else if (underMouse()) {
|
} else if (underMouse()) {
|
||||||
p.fillRect(rect(), hoverBackgroundColor_);
|
p.fillRect(rect(), hoverBackgroundColor_);
|
||||||
} else {
|
} else {
|
||||||
p.fillRect(rect(), backgroundColor_);
|
p.fillRect(rect(), backgroundColor_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// p.setPen(QColor("#333"));
|
|
||||||
|
|
||||||
QRect avatarRegion(Padding, Padding, IconSize, IconSize);
|
QRect avatarRegion(Padding, Padding, IconSize, IconSize);
|
||||||
|
|
||||||
// Description line with the default font.
|
// Description line with the default font.
|
||||||
int bottom_y = maxHeight_ - Padding - Padding / 3 - metrics.ascent() / 2;
|
int bottom_y = MaxHeight - Padding - Padding / 3 - metrics.ascent() / 2;
|
||||||
|
|
||||||
if (width() > ui::sidebar::SmallSize) {
|
if (width() > ui::sidebar::SmallSize) {
|
||||||
if (isPressed_) {
|
|
||||||
QPen pen(highlightedTitleColor_);
|
|
||||||
p.setPen(pen);
|
|
||||||
} else {
|
|
||||||
QPen pen(titleColor_);
|
|
||||||
p.setPen(pen);
|
|
||||||
}
|
|
||||||
font.setPixelSize(conf::roomlist::fonts::heading);
|
font.setPixelSize(conf::roomlist::fonts::heading);
|
||||||
p.setFont(font);
|
p.setFont(font);
|
||||||
|
p.setPen(titlePen);
|
||||||
|
|
||||||
// Name line.
|
// Name line.
|
||||||
QFontMetrics fontNameMetrics(font);
|
QFontMetrics fontNameMetrics(font);
|
||||||
int top_y = 2 * Padding + fontNameMetrics.ascent() / 2;
|
int top_y = 2 * Padding + fontNameMetrics.ascent() / 2;
|
||||||
|
|
||||||
auto name = metrics.elidedText(
|
auto name = metrics.elidedText(
|
||||||
state_.getName(), Qt::ElideRight, (width() - IconSize - 2 * Padding) * 0.8);
|
roomName(), Qt::ElideRight, (width() - IconSize - 2 * Padding) * 0.8);
|
||||||
p.drawText(QPoint(2 * Padding + IconSize, top_y), name);
|
p.drawText(QPoint(2 * Padding + IconSize, top_y), name);
|
||||||
|
|
||||||
if (isPressed_) {
|
if (roomType_ == RoomType::Joined) {
|
||||||
QPen pen(highlightedSubtitleColor_);
|
font.setPixelSize(conf::fontSize);
|
||||||
p.setPen(pen);
|
p.setFont(font);
|
||||||
} else {
|
p.setPen(subtitlePen);
|
||||||
QPen pen(subtitleColor_);
|
|
||||||
p.setPen(pen);
|
|
||||||
}
|
|
||||||
|
|
||||||
font.setPixelSize(conf::fontSize);
|
auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5;
|
||||||
p.setFont(font);
|
|
||||||
|
|
||||||
auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5;
|
// The limit is the space between the end of the avatar and the start of the
|
||||||
|
// timestamp.
|
||||||
|
int usernameLimit =
|
||||||
|
std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - 20);
|
||||||
|
auto userName =
|
||||||
|
metrics.elidedText(lastMsgInfo_.username, Qt::ElideRight, usernameLimit);
|
||||||
|
|
||||||
// The limit is the space between the end of the avatar and the start of the
|
|
||||||
// timestamp.
|
|
||||||
int usernameLimit =
|
|
||||||
std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - 20);
|
|
||||||
auto userName =
|
|
||||||
metrics.elidedText(lastMsgInfo_.username, Qt::ElideRight, usernameLimit);
|
|
||||||
|
|
||||||
font.setBold(true);
|
|
||||||
p.setFont(font);
|
|
||||||
p.drawText(QPoint(2 * Padding + IconSize, bottom_y), userName);
|
|
||||||
|
|
||||||
int nameWidth = QFontMetrics(font).width(userName);
|
|
||||||
|
|
||||||
font.setBold(false);
|
|
||||||
p.setFont(font);
|
|
||||||
|
|
||||||
// The limit is the space between the end of the username and the start of
|
|
||||||
// the timestamp.
|
|
||||||
int descriptionLimit =
|
|
||||||
std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - nameWidth - 5);
|
|
||||||
auto description =
|
|
||||||
metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit);
|
|
||||||
p.drawText(QPoint(2 * Padding + IconSize + nameWidth, bottom_y), description);
|
|
||||||
|
|
||||||
// We either show the bubble or the last message timestamp.
|
|
||||||
if (unreadMsgCount_ == 0) {
|
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y),
|
p.setFont(font);
|
||||||
lastMsgInfo_.timestamp);
|
p.drawText(QPoint(2 * Padding + IconSize, bottom_y), userName);
|
||||||
|
|
||||||
|
int nameWidth = QFontMetrics(font).width(userName);
|
||||||
|
|
||||||
|
font.setBold(false);
|
||||||
|
p.setFont(font);
|
||||||
|
|
||||||
|
// The limit is the space between the end of the username and the start of
|
||||||
|
// the timestamp.
|
||||||
|
int descriptionLimit = std::max(
|
||||||
|
0, width() - 3 * Padding - msgStampWidth - IconSize - nameWidth - 5);
|
||||||
|
auto description =
|
||||||
|
metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit);
|
||||||
|
p.drawText(QPoint(2 * Padding + IconSize + nameWidth, bottom_y),
|
||||||
|
description);
|
||||||
|
|
||||||
|
// We either show the bubble or the last message timestamp.
|
||||||
|
if (unreadMsgCount_ == 0) {
|
||||||
|
font.setBold(true);
|
||||||
|
p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y),
|
||||||
|
lastMsgInfo_.timestamp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int btnWidth = (width() - IconSize - 6 * Padding) / 2;
|
||||||
|
|
||||||
|
acceptBtnRegion_ = QRectF(InviteBtnX, InviteBtnY, btnWidth, 20);
|
||||||
|
declineBtnRegion_ =
|
||||||
|
QRectF(InviteBtnX + btnWidth + 2 * Padding, InviteBtnY, btnWidth, 20);
|
||||||
|
|
||||||
|
QPainterPath acceptPath;
|
||||||
|
acceptPath.addRoundedRect(acceptBtnRegion_, 10, 10);
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.fillPath(acceptPath, btnColor_);
|
||||||
|
p.drawPath(acceptPath);
|
||||||
|
|
||||||
|
QPainterPath declinePath;
|
||||||
|
declinePath.addRoundedRect(declineBtnRegion_, 10, 10);
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.fillPath(declinePath, btnColor_);
|
||||||
|
p.drawPath(declinePath);
|
||||||
|
|
||||||
|
p.setPen(QPen(btnTextColor_));
|
||||||
|
p.setFont(font);
|
||||||
|
p.drawText(acceptBtnRegion_, Qt::AlignCenter, tr("Accept"));
|
||||||
|
p.drawText(declineBtnRegion_, Qt::AlignCenter, tr("Decline"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,8 +243,7 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
|
||||||
p.setFont(font);
|
p.setFont(font);
|
||||||
p.setPen(QColor("#333"));
|
p.setPen(QColor("#333"));
|
||||||
p.setBrush(Qt::NoBrush);
|
p.setBrush(Qt::NoBrush);
|
||||||
p.drawText(
|
p.drawText(avatarRegion.translated(0, -1), Qt::AlignCenter, QChar(roomName()[0]));
|
||||||
avatarRegion.translated(0, -1), Qt::AlignCenter, QChar(state_.getName()[0]));
|
|
||||||
} else {
|
} else {
|
||||||
p.save();
|
p.save();
|
||||||
|
|
||||||
|
@ -289,6 +335,9 @@ RoomInfoListItem::contextMenuEvent(QContextMenuEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
|
|
||||||
|
if (roomType_ == RoomType::Invited)
|
||||||
|
return;
|
||||||
|
|
||||||
toggleNotifications_->setText(notificationText());
|
toggleNotifications_->setText(notificationText());
|
||||||
menu_->popup(event->globalPos());
|
menu_->popup(event->globalPos());
|
||||||
}
|
}
|
||||||
|
@ -301,6 +350,18 @@ RoomInfoListItem::mousePressEvent(QMouseEvent *event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (roomType_ == RoomType::Invited) {
|
||||||
|
const auto point = event->pos();
|
||||||
|
|
||||||
|
if (acceptBtnRegion_.contains(point))
|
||||||
|
emit acceptInvite(roomId_);
|
||||||
|
|
||||||
|
if (declineBtnRegion_.contains(point))
|
||||||
|
emit declineInvite(roomId_);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit clicked(roomId_);
|
emit clicked(roomId_);
|
||||||
|
|
||||||
setPressedState(true);
|
setPressedState(true);
|
||||||
|
|
|
@ -287,3 +287,32 @@ RoomList::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
|
||||||
|
RoomList::syncInvites(const std::map<std::string, mtx::responses::InvitedRoom> &rooms)
|
||||||
|
{
|
||||||
|
for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) {
|
||||||
|
const auto room_id = QString::fromStdString(it->first);
|
||||||
|
|
||||||
|
if (!rooms_.contains(room_id))
|
||||||
|
addInvitedRoom(room_id, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomList::addInvitedRoom(const QString &room_id, const mtx::responses::InvitedRoom &room)
|
||||||
|
{
|
||||||
|
auto room_item = new RoomInfoListItem(room_id, room, scrollArea_);
|
||||||
|
connect(room_item, &RoomInfoListItem::acceptInvite, this, &RoomList::acceptInvite);
|
||||||
|
connect(room_item, &RoomInfoListItem::declineInvite, this, &RoomList::declineInvite);
|
||||||
|
|
||||||
|
rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item));
|
||||||
|
|
||||||
|
auto avatarUrl = QString::fromStdString(room.avatar());
|
||||||
|
|
||||||
|
if (!avatarUrl.isEmpty())
|
||||||
|
client_->fetchRoomAvatar(room_id, avatarUrl);
|
||||||
|
|
||||||
|
int pos = contentsLayout_->count() - 1;
|
||||||
|
contentsLayout_->insertWidget(pos, room_item);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue