Handle incoming invites

fixes #128
This commit is contained in:
Konstantinos Sideris 2017-12-19 22:36:12 +02:00
parent 101bf47443
commit f11044b5eb
12 changed files with 352 additions and 93 deletions

View file

@ -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_;

View file

@ -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;

View file

@ -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_;
}; };

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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}
{} {}
@ -89,6 +90,7 @@ Cache::setup()
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();
}
}

View file

@ -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)
{ {

View file

@ -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,50 +128,41 @@ 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_);
p.setPen(pen);
} else {
QPen pen(subtitleColor_);
p.setPen(pen);
}
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
p.setFont(font); p.setFont(font);
p.setPen(subtitlePen);
auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5; auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5;
@ -164,11 +184,12 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
// The limit is the space between the end of the username and the start of // The limit is the space between the end of the username and the start of
// the timestamp. // the timestamp.
int descriptionLimit = int descriptionLimit = std::max(
std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - nameWidth - 5); 0, width() - 3 * Padding - msgStampWidth - IconSize - nameWidth - 5);
auto description = auto description =
metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit); metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit);
p.drawText(QPoint(2 * Padding + IconSize + nameWidth, bottom_y), description); p.drawText(QPoint(2 * Padding + IconSize + nameWidth, bottom_y),
description);
// We either show the bubble or the last message timestamp. // We either show the bubble or the last message timestamp.
if (unreadMsgCount_ == 0) { if (unreadMsgCount_ == 0) {
@ -176,6 +197,32 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y), p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y),
lastMsgInfo_.timestamp); 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"));
}
} }
font.setBold(false); font.setBold(false);
@ -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);

View file

@ -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);
}