summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/Cache.h7
-rw-r--r--include/ChatPage.h1
-rw-r--r--include/RoomInfoListItem.h79
-rw-r--r--include/RoomList.h6
m---------libs/matrix-structs0
-rw-r--r--resources/styles/nheko-dark.qss3
-rw-r--r--resources/styles/nheko.qss3
-rw-r--r--resources/styles/system.qss3
-rw-r--r--src/Cache.cc95
-rw-r--r--src/ChatPage.cc28
-rw-r--r--src/RoomInfoListItem.cc179
-rw-r--r--src/RoomList.cc29
12 files changed, 346 insertions, 87 deletions
diff --git a/include/Cache.h b/include/Cache.h
index 031c8b16..c141a42a 100644
--- a/include/Cache.h
+++ b/include/Cache.h
@@ -19,6 +19,7 @@
#include <QDir>
#include <lmdb++.h>
+#include <mtx/responses.hpp>
class RoomState;
@@ -33,10 +34,15 @@ public:
QString nextBatchToken() const;
QMap<QString, RoomState> 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 setup();
bool isFormatValid();
@@ -49,6 +55,7 @@ private:
lmdb::env env_;
lmdb::dbi stateDb_;
lmdb::dbi roomDb_;
+ lmdb::dbi invitesDb_;
bool isMounted_;
diff --git a/include/ChatPage.h b/include/ChatPage.h
index 94c54f0b..14d44ff3 100644
--- a/include/ChatPage.h
+++ b/include/ChatPage.h
@@ -78,6 +78,7 @@ private slots:
void logout();
void addRoom(const QString &room_id);
void removeRoom(const QString &room_id);
+ void removeInvite(const QString &room_id);
private:
using UserID = QString;
diff --git a/include/RoomInfoListItem.h b/include/RoomInfoListItem.h
index acb1ab84..d4e4f983 100644
--- a/include/RoomInfoListItem.h
+++ b/include/RoomInfoListItem.h
@@ -21,6 +21,8 @@
#include <QSharedPointer>
#include <QWidget>
+#include <mtx/responses.hpp>
+
#include "RoomState.h"
class Menu;
@@ -52,12 +54,17 @@ class RoomInfoListItem : public QWidget
Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
setHighlightedSubtitleColor)
+ Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor)
+ Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
+
public:
RoomInfoListItem(QSharedPointer<RoomSettings> settings,
RoomState state,
QString room_id,
QWidget *parent = 0);
+ RoomInfoListItem(QString room_id, mtx::responses::InvitedRoom room, QWidget *parent = 0);
+
~RoomInfoListItem();
void updateUnreadMessageCount(int count);
@@ -71,35 +78,36 @@ public:
void setAvatar(const QImage &avatar_image);
void setDescriptionMessage(const DescInfo &info);
- inline QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
- inline QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
- inline QColor backgroundColor() const { return backgroundColor_; }
+ QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
+ QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
+ QColor backgroundColor() const { return backgroundColor_; }
- inline QColor highlightedTitleColor() const { return highlightedTitleColor_; }
- inline QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
+ QColor highlightedTitleColor() const { return highlightedTitleColor_; }
+ QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
- inline QColor titleColor() const { return titleColor_; }
- inline QColor subtitleColor() const { return subtitleColor_; }
+ QColor titleColor() const { return titleColor_; }
+ QColor subtitleColor() const { return subtitleColor_; }
+ QColor btnColor() const { return btnColor_; }
+ QColor btnTextColor() const { return btnTextColor_; }
- inline void setHighlightedBackgroundColor(QColor &color)
- {
- highlightedBackgroundColor_ = color;
- }
- inline void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
- inline void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
+ void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
+ void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
+ void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
- inline void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
- inline void setHighlightedSubtitleColor(QColor &color)
- {
- highlightedSubtitleColor_ = color;
- }
+ void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
+ void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; }
+
+ void setTitleColor(QColor &color) { titleColor_ = color; }
+ void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
- inline void setTitleColor(QColor &color) { titleColor_ = color; }
- inline void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
+ void setBtnColor(QColor &color) { btnColor_ = color; }
+ void setBtnTextColor(QColor &color) { btnTextColor_ = color; }
signals:
void clicked(const QString &room_id);
void leaveRoom(const QString &room_id);
+ void acceptInvite(const QString &room_id);
+ void declineInvite(const QString &room_id);
public slots:
void setPressedState(bool state);
@@ -111,15 +119,33 @@ protected:
void contextMenuEvent(QContextMenuEvent *event) override;
private:
- QString notificationText();
+ void init(QWidget *parent);
+ QString roomName()
+ {
+ if (roomType_ == RoomType::Joined)
+ return state_.getName();
- const int Padding = 7;
- const int IconSize = 48;
+ return roomName_;
+ }
+
+ QString notificationText();
RippleOverlay *ripple_overlay_;
+ enum class RoomType
+ {
+ Joined,
+ Invited,
+ };
+
+ RoomType roomType_ = RoomType::Joined;
+
+ // State information for the joined rooms.
RoomState state_;
+ // State information for the invited rooms.
+ mtx::responses::InvitedRoom invitedRoom_;
+
QString roomId_;
QString roomName_;
@@ -135,7 +161,6 @@ private:
bool isPressed_ = false;
- int maxHeight_;
int unreadMsgCount_ = 0;
QColor highlightedBackgroundColor_;
@@ -147,4 +172,10 @@ private:
QColor titleColor_;
QColor subtitleColor_;
+
+ QColor btnColor_;
+ QColor btnTextColor_;
+
+ QRectF acceptBtnRegion_;
+ QRectF declineBtnRegion_;
};
diff --git a/include/RoomList.h b/include/RoomList.h
index f75f7ba4..8487df10 100644
--- a/include/RoomList.h
+++ b/include/RoomList.h
@@ -24,6 +24,8 @@
#include <QVBoxLayout>
#include <QWidget>
+#include <mtx.hpp>
+
#include "dialogs/LeaveRoom.h"
class LeaveRoomDialog;
@@ -47,17 +49,21 @@ public:
const QMap<QString, RoomState> &states);
void sync(const QMap<QString, RoomState> &states,
QMap<QString, QSharedPointer<RoomSettings>> &settings);
+ void syncInvites(const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
void clear();
void addRoom(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
const RoomState &state,
const QString &room_id);
+ void addInvitedRoom(const QString &room_id, const mtx::responses::InvitedRoom &room);
void removeRoom(const QString &room_id, bool reset);
signals:
void roomChanged(const QString &room_id);
void totalUnreadMessageCountUpdated(int count);
+ void acceptInvite(const QString &room_id);
+ void declineInvite(const QString &room_id);
public slots:
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
diff --git a/libs/matrix-structs b/libs/matrix-structs
-Subproject ff5a9c887af1a8cffd13876abcf4c079a8525bd
+Subproject 582c6956c464e80f738c57ded239c3fb613f1c2
diff --git a/resources/styles/nheko-dark.qss b/resources/styles/nheko-dark.qss
index 0fd519ea..a730a6e0 100644
--- a/resources/styles/nheko-dark.qss
+++ b/resources/styles/nheko-dark.qss
@@ -49,6 +49,9 @@ RoomInfoListItem {
qproperty-highlightedTitleColor: #e4e5e8;
qproperty-highlightedSubtitleColor: #e4e5e8;
+
+ qproperty-btnColor: #414A59;
+ qproperty-btnTextColor: white;
}
LoadingIndicator {
diff --git a/resources/styles/nheko.qss b/resources/styles/nheko.qss
index c55b64fb..3e740e2a 100644
--- a/resources/styles/nheko.qss
+++ b/resources/styles/nheko.qss
@@ -47,6 +47,9 @@ RoomInfoListItem {
qproperty-highlightedTitleColor: white;
qproperty-highlightedSubtitleColor: white;
+
+ qproperty-btnColor: #ccc;
+ qproperty-btnTextColor: #333;
}
#ChatPageLoadSpinner {
diff --git a/resources/styles/system.qss b/resources/styles/system.qss
index e6dab15e..afb2ad26 100644
--- a/resources/styles/system.qss
+++ b/resources/styles/system.qss
@@ -55,6 +55,9 @@ RoomInfoListItem {
qproperty-highlightedTitleColor: palette(light);
qproperty-highlightedSubtitleColor: palette(light);
+
+ qproperty-btnColor: palette(light);
+ qproperty-btnTextColor: palette(text);
}
LoadingIndicator {
diff --git a/src/Cache.cc b/src/Cache.cc
index 7d044e8f..4e2f32a9 100644
--- a/src/Cache.cc
+++ b/src/Cache.cc
@@ -33,6 +33,7 @@ Cache::Cache(const QString &userId)
: env_{nullptr}
, stateDb_{0}
, roomDb_{0}
+ , invitesDb_{0}
, isMounted_{false}
, userId_{userId}
{}
@@ -86,9 +87,10 @@ Cache::setup()
env_.open(statePath.toStdString().c_str());
}
- auto txn = lmdb::txn::begin(env_);
- stateDb_ = lmdb::dbi::open(txn, "state", MDB_CREATE);
- roomDb_ = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
+ auto txn = lmdb::txn::begin(env_);
+ stateDb_ = lmdb::dbi::open(txn, "state", MDB_CREATE);
+ roomDb_ = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
+ invitesDb_ = lmdb::dbi::open(txn, "invites", MDB_CREATE);
txn.commit();
@@ -174,6 +176,20 @@ Cache::removeRoom(const QString &roomid)
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>
Cache::states()
{
@@ -310,3 +326,76 @@ Cache::setCurrentFormat()
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();
+ }
+}
diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index 5788c697..a5b36d81 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -134,6 +134,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
connect(
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_,
&TimelineViewManager::clearRoomMessageCount,
room_list_,
@@ -266,8 +269,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
this,
&ChatPage::updateOwnProfileInfo);
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.");
+ removeInvite(room_id);
});
connect(client_.data(), &MatrixClient::invitedUser, this, [=](QString, QString 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_);
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_->syncInvites(response.rooms.invite);
+
view_manager_->sync(response.rooms);
client_->setNextBatchToken(nextBatchToken);
@@ -445,12 +452,14 @@ ChatPage::initialSyncCompleted(const mtx::responses::Sync &response)
&Cache::setState,
QString::fromStdString(response.next_batch),
state_manager_);
+ QtConcurrent::run(cache_.data(), &Cache::setInvites, response.rooms.invite);
// Populate timelines with messages.
view_manager_->initialize(response.rooms);
// Initialize room list.
room_list_->setInitialRooms(settingsManager_, state_manager_);
+ room_list_->syncInvites(response.rooms.invite);
client_->setNextBatchToken(QString::fromStdString(response.next_batch));
client_->sync();
@@ -552,6 +561,7 @@ ChatPage::loadStateFromCache()
// Initialize room list from the restored state and settings.
room_list_->setInitialRooms(settingsManager_, state_manager_);
+ room_list_->syncInvites(cache_->invites());
// Check periodically if the timelines have been loaded.
consensusTimer_->start(CONSENSUS_TIMEOUT);
@@ -629,6 +639,7 @@ ChatPage::removeRoom(const QString &room_id)
settingsManager_.remove(room_id);
try {
cache_->removeRoom(room_id);
+ cache_->removeInvite(room_id);
} catch (const lmdb::error &e) {
qCritical() << "The cache couldn't be updated: " << e.what();
// TODO: Notify the user.
@@ -639,6 +650,21 @@ ChatPage::removeRoom(const QString &room_id)
}
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
ChatPage::updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids)
{
QStringList users;
diff --git a/src/RoomInfoListItem.cc b/src/RoomInfoListItem.cc
index 875bb506..fa567243 100644
--- a/src/RoomInfoListItem.cc
+++ b/src/RoomInfoListItem.cc
@@ -15,9 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <QDebug>
#include <QMouseEvent>
#include <QPainter>
+#include <variant.hpp>
+
#include "Config.h"
#include "Menu.h"
#include "Ripple.h"
@@ -26,23 +29,21 @@
#include "RoomSettings.h"
#include "Theme.h"
-RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
- RoomState state,
- QString room_id,
- QWidget *parent)
- : QWidget(parent)
- , state_(state)
- , roomId_(room_id)
- , roomSettings_{settings}
- , isPressed_(false)
- , maxHeight_(IconSize + 2 * Padding)
- , unreadMsgCount_(0)
+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_);
+ setFixedHeight(MaxHeight);
QPainterPath path;
path.addRect(0, 0, parent->width(), height());
@@ -50,6 +51,34 @@ RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
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,
+ RoomState state,
+ QString room_id,
+ QWidget *parent)
+ : QWidget(parent)
+ , state_(state)
+ , roomId_(room_id)
+ , roomSettings_{settings}
+ , isPressed_(false)
+ , unreadMsgCount_(0)
+{
+ init(parent);
menu_ = new Menu(this);
@@ -99,82 +128,100 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
font.setPixelSize(conf::fontSize);
QFontMetrics metrics(font);
+ QPen titlePen(titleColor_);
+ QPen subtitlePen(subtitleColor_);
+
if (isPressed_) {
p.fillRect(rect(), highlightedBackgroundColor_);
+ titlePen.setColor(highlightedTitleColor_);
+ subtitlePen.setColor(highlightedSubtitleColor_);
} else if (underMouse()) {
p.fillRect(rect(), hoverBackgroundColor_);
} else {
p.fillRect(rect(), backgroundColor_);
}
- // p.setPen(QColor("#333"));
-
QRect avatarRegion(Padding, Padding, IconSize, IconSize);
// 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 (isPressed_) {
- QPen pen(highlightedTitleColor_);
- p.setPen(pen);
- } else {
- QPen pen(titleColor_);
- p.setPen(pen);
- }
font.setPixelSize(conf::roomlist::fonts::heading);
p.setFont(font);
+ p.setPen(titlePen);
// Name line.
QFontMetrics fontNameMetrics(font);
int top_y = 2 * Padding + fontNameMetrics.ascent() / 2;
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);
- if (isPressed_) {
- QPen pen(highlightedSubtitleColor_);
- p.setPen(pen);
- } else {
- QPen pen(subtitleColor_);
- p.setPen(pen);
- }
+ if (roomType_ == RoomType::Joined) {
+ font.setPixelSize(conf::fontSize);
+ p.setFont(font);
+ p.setPen(subtitlePen);
- font.setPixelSize(conf::fontSize);
- p.setFont(font);
+ auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5;
- 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);
+ p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y),
+ lastMsgInfo_.timestamp);
+ }
+ } else {
+ int btnWidth = (width() - IconSize - 6 * Padding) / 2;
- font.setBold(true);
- p.setFont(font);
- p.drawText(QPoint(2 * Padding + IconSize, bottom_y), userName);
+ acceptBtnRegion_ = QRectF(InviteBtnX, InviteBtnY, btnWidth, 20);
+ declineBtnRegion_ =
+ QRectF(InviteBtnX + btnWidth + 2 * Padding, InviteBtnY, btnWidth, 20);
- int nameWidth = QFontMetrics(font).width(userName);
+ QPainterPath acceptPath;
+ acceptPath.addRoundedRect(acceptBtnRegion_, 10, 10);
- font.setBold(false);
- p.setFont(font);
+ p.setPen(Qt::NoPen);
+ p.fillPath(acceptPath, btnColor_);
+ p.drawPath(acceptPath);
- // 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);
+ QPainterPath declinePath;
+ declinePath.addRoundedRect(declineBtnRegion_, 10, 10);
- // 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);
+ 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.setPen(QColor("#333"));
p.setBrush(Qt::NoBrush);
- p.drawText(
- avatarRegion.translated(0, -1), Qt::AlignCenter, QChar(state_.getName()[0]));
+ p.drawText(avatarRegion.translated(0, -1), Qt::AlignCenter, QChar(roomName()[0]));
} else {
p.save();
@@ -289,6 +335,9 @@ RoomInfoListItem::contextMenuEvent(QContextMenuEvent *event)
{
Q_UNUSED(event);
+ if (roomType_ == RoomType::Invited)
+ return;
+
toggleNotifications_->setText(notificationText());
menu_->popup(event->globalPos());
}
@@ -301,6 +350,18 @@ RoomInfoListItem::mousePressEvent(QMouseEvent *event)
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_);
setPressedState(true);
diff --git a/src/RoomList.cc b/src/RoomList.cc
index a892e406..1e639838 100644
--- a/src/RoomList.cc
+++ b/src/RoomList.cc
@@ -287,3 +287,32 @@ RoomList::paintEvent(QPaintEvent *)
QPainter 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);
+}