summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMax Sandholm <max@sandholm.org>2017-10-01 19:49:36 +0300
committermujx <mujx@users.noreply.github.com>2017-10-01 19:49:36 +0300
commit7ad45d8d6448c60b4c81c80fa8d6d81afd6e4a02 (patch)
tree821124200c7dac85128790115d527791c1fc4945 /src
parentMore badges (diff)
downloadnheko-7ad45d8d6448c60b4c81c80fa8d6d81afd6e4a02.tar.xz
React to externally left and joined rooms, and add "leave room" button in room menu (#75)
* Initial "join room" feature.
* React correctly to remotely joined rooms.
* Leaving rooms implemented both locally using the room menu
   in nheko, and reacting properly when leaving a room remotely 
   from another client.
Diffstat (limited to 'src')
-rw-r--r--src/Cache.cc10
-rw-r--r--src/ChatPage.cc83
-rw-r--r--src/EmojiPanel.cc13
-rw-r--r--src/InputValidator.cc4
-rw-r--r--src/JoinRoomDialog.cc49
-rw-r--r--src/LeaveRoomDialog.cc44
-rw-r--r--src/MatrixClient.cc78
-rw-r--r--src/RoomInfoListItem.cc5
-rw-r--r--src/RoomList.cc74
-rw-r--r--src/Sync.cc41
-rw-r--r--src/TimelineViewManager.cc56
-rw-r--r--src/TopRoomBar.cc25
12 files changed, 442 insertions, 40 deletions
diff --git a/src/Cache.cc b/src/Cache.cc

index bda81316..5ed77086 100644 --- a/src/Cache.cc +++ b/src/Cache.cc
@@ -153,6 +153,16 @@ Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &s } } +void +Cache::removeRoom(const QString &roomid) +{ + auto txn = lmdb::txn::begin(env_, nullptr, 0); + + lmdb::dbi_del(txn, roomDb_, lmdb::val(roomid.toUtf8(), roomid.toUtf8().size()), nullptr); + + txn.commit(); +} + QMap<QString, RoomState> Cache::states() { diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index 3d3a3876..a6a80e9d 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc
@@ -114,6 +114,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent) connect(user_info_widget_, SIGNAL(logout()), client_.data(), SLOT(logout())); connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout())); + connect( + top_bar_, &TopRoomBar::leaveRoom, this, [=]() { client_->leaveRoom(current_room_); }); + connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo); connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit); connect( @@ -190,6 +193,14 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent) SIGNAL(ownAvatarRetrieved(const QPixmap &)), this, SLOT(setOwnAvatar(const QPixmap &))); + connect(client_.data(), + SIGNAL(joinedRoom(const QString &)), + this, + SLOT(addRoom(const QString &))); + connect(client_.data(), + SIGNAL(leftRoom(const QString &)), + this, + SLOT(removeRoom(const QString &))); AvatarProvider::init(client); } @@ -293,8 +304,9 @@ ChatPage::syncCompleted(const SyncResponse &response) RoomState room_state; // Merge the new updates for rooms that we are tracking. - if (state_manager_.contains(it.key())) + if (state_manager_.contains(it.key())) { room_state = state_manager_[it.key()]; + } room_state.updateFromEvents(it.value().state().events()); room_state.updateFromEvents(it.value().timeline().events()); @@ -307,13 +319,48 @@ ChatPage::syncCompleted(const SyncResponse &response) oldState.update(room_state); state_manager_.insert(it.key(), oldState); } else { - qWarning() << "New rooms cannot be added after initial sync, yet."; + RoomState room_state; + + // Build the current state from the timeline and state events. + room_state.updateFromEvents(it.value().state().events()); + room_state.updateFromEvents(it.value().timeline().events()); + + // Remove redundant memberships. + room_state.removeLeaveMemberships(); + + // Resolve room name and avatar. e.g in case of one-to-one chats. + room_state.resolveName(); + room_state.resolveAvatar(); + + updateDisplayNames(room_state); + + state_manager_.insert(it.key(), room_state); + settingsManager_.insert( + it.key(), QSharedPointer<RoomSettings>(new RoomSettings(it.key()))); + + for (const auto membership : room_state.memberships) { + auto uid = membership.sender(); + auto url = membership.content().avatarUrl(); + + if (!url.toString().isEmpty()) + AvatarProvider::setAvatarUrl(uid, url); + } + + view_manager_->addRoom(it.value(), it.key()); } if (it.key() == current_room_) changeTopRoomInfo(it.key()); } + auto leave = response.rooms().leave(); + + for (auto it = leave.constBegin(); it != leave.constEnd(); it++) { + if (state_manager_.contains(it.key())) { + removeRoom(it.key()); + } + } + try { cache_->setState(response.nextBatch(), state_manager_); } catch (const lmdb::error &e) { @@ -537,6 +584,38 @@ ChatPage::showQuickSwitcher() quickSwitcherModal_->fadeIn(); } +void +ChatPage::addRoom(const QString &room_id) +{ + if (!state_manager_.contains(room_id)) { + RoomState room_state; + + state_manager_.insert(room_id, room_state); + settingsManager_.insert(room_id, + QSharedPointer<RoomSettings>(new RoomSettings(room_id))); + + room_list_->addRoom(settingsManager_[room_id], state_manager_[room_id], room_id); + + this->changeTopRoomInfo(room_id); + room_list_->highlightSelectedRoom(room_id); + } +} + +void +ChatPage::removeRoom(const QString &room_id) +{ + state_manager_.remove(room_id); + settingsManager_.remove(room_id); + try { + cache_->removeRoom(room_id); + } catch (const lmdb::error &e) { + qCritical() << "The cache couldn't be updated: " << e.what(); + // TODO: Notify the user. + cache_->unmount(); + } + room_list_->removeRoom(room_id, room_id == current_room_); +} + ChatPage::~ChatPage() { sync_timer_->stop(); diff --git a/src/EmojiPanel.cc b/src/EmojiPanel.cc
index c272a478..2730ddb5 100644 --- a/src/EmojiPanel.cc +++ b/src/EmojiPanel.cc
@@ -34,12 +34,13 @@ EmojiPanel::EmojiPanel(QWidget *parent) , animationDuration_{ 100 } , categoryIconSize_{ 20 } { - setStyleSheet( - "QWidget {background: #fff; color: #e8e8e8; border: none;}" - "QScrollBar:vertical { background-color: #fff; width: 8px; margin: 0px 2px 0 2px; }" - "QScrollBar::handle:vertical { background-color: #d6dde3; min-height: 20px; }" - "QScrollBar::add-line:vertical { border: none; background: none; }" - "QScrollBar::sub-line:vertical { border: none; background: none; }"); + setStyleSheet("QWidget {background: #fff; color: #e8e8e8; border: none;}" + "QScrollBar:vertical { background-color: #fff; width: 8px; margin: 0px " + "2px 0 2px; }" + "QScrollBar::handle:vertical { background-color: #d6dde3; min-height: " + "20px; }" + "QScrollBar::add-line:vertical { border: none; background: none; }" + "QScrollBar::sub-line:vertical { border: none; background: none; }"); setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_ShowWithoutActivating, true); diff --git a/src/InputValidator.cc b/src/InputValidator.cc
index 6e343c71..5fd92783 100644 --- a/src/InputValidator.cc +++ b/src/InputValidator.cc
@@ -20,8 +20,8 @@ const QRegExp MXID_REGEX("@[A-Za-z0-9._%+-]+:[A-Za-z0-9.-]{1,126}\\.[A-Za-z]{1,63}"); const QRegExp LOCALPART_REGEX("[A-za-z0-9._%+-]{3,}"); const QRegExp PASSWORD_REGEX(".{8,}"); -const QRegExp DOMAIN_REGEX( - "(?!\\-)(?:[a-zA-Z\\d\\-]{0,62}[a-zA-Z\\d]\\.){1,126}(?!\\d+)[a-zA-Z\\d]{1,63}"); +const QRegExp DOMAIN_REGEX("(?!\\-)(?:[a-zA-Z\\d\\-]{0,62}[a-zA-Z\\d]\\.){1," + "126}(?!\\d+)[a-zA-Z\\d]{1,63}"); QRegExpValidator InputValidator::Id(MXID_REGEX); QRegExpValidator InputValidator::Localpart(LOCALPART_REGEX); diff --git a/src/JoinRoomDialog.cc b/src/JoinRoomDialog.cc new file mode 100644
index 00000000..c3ee289e --- /dev/null +++ b/src/JoinRoomDialog.cc
@@ -0,0 +1,49 @@ +#include <QLabel> +#include <QVBoxLayout> + +#include "Config.h" +#include "JoinRoomDialog.h" +#include "Theme.h" + +JoinRoomDialog::JoinRoomDialog(QWidget *parent) + : QFrame(parent) +{ + setMaximumSize(400, 400); + setStyleSheet("background-color: #fff"); + + auto layout = new QVBoxLayout(this); + layout->setSpacing(30); + layout->setMargin(20); + + auto buttonLayout = new QHBoxLayout(); + buttonLayout->setSpacing(0); + buttonLayout->setMargin(0); + + confirmBtn_ = new FlatButton("JOIN", this); + confirmBtn_->setFontSize(conf::btn::fontSize); + + cancelBtn_ = new FlatButton(tr("CANCEL"), this); + cancelBtn_->setFontSize(conf::btn::fontSize); + + buttonLayout->addStretch(1); + buttonLayout->addWidget(confirmBtn_); + buttonLayout->addWidget(cancelBtn_); + + QFont font; + font.setPixelSize(conf::headerFontSize); + + auto label = new QLabel(tr("Room alias to join:"), this); + label->setFont(font); + label->setStyleSheet("color: #333333"); + + roomAliasEdit_ = new QLineEdit(this); + + layout->addWidget(label); + layout->addWidget(roomAliasEdit_); + layout->addLayout(buttonLayout); + + connect(confirmBtn_, &QPushButton::clicked, [=]() { + emit closing(true, roomAliasEdit_->text()); + }); + connect(cancelBtn_, &QPushButton::clicked, [=]() { emit closing(false, nullptr); }); +} diff --git a/src/LeaveRoomDialog.cc b/src/LeaveRoomDialog.cc new file mode 100644
index 00000000..f7669f0d --- /dev/null +++ b/src/LeaveRoomDialog.cc
@@ -0,0 +1,44 @@ +#include <QLabel> +#include <QVBoxLayout> + +#include "Config.h" +#include "LeaveRoomDialog.h" +#include "Theme.h" + +LeaveRoomDialog::LeaveRoomDialog(QWidget *parent) + : QFrame(parent) +{ + setMaximumSize(400, 400); + setStyleSheet("background-color: #fff"); + + auto layout = new QVBoxLayout(this); + layout->setSpacing(30); + layout->setMargin(20); + + auto buttonLayout = new QHBoxLayout(); + buttonLayout->setSpacing(0); + buttonLayout->setMargin(0); + + confirmBtn_ = new FlatButton("LEAVE", this); + confirmBtn_->setFontSize(conf::btn::fontSize); + + cancelBtn_ = new FlatButton(tr("CANCEL"), this); + cancelBtn_->setFontSize(conf::btn::fontSize); + + buttonLayout->addStretch(1); + buttonLayout->addWidget(confirmBtn_); + buttonLayout->addWidget(cancelBtn_); + + QFont font; + font.setPixelSize(conf::headerFontSize); + + auto label = new QLabel(tr("Are you sure you want to leave?"), this); + label->setFont(font); + label->setStyleSheet("color: #333333"); + + layout->addWidget(label); + layout->addLayout(buttonLayout); + + connect(confirmBtn_, &QPushButton::clicked, [=]() { emit closing(true); }); + connect(cancelBtn_, &QPushButton::clicked, [=]() { emit closing(false); }); +} diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index 981a30c2..bd43efd8 100644 --- a/src/MatrixClient.cc +++ b/src/MatrixClient.cc
@@ -463,6 +463,40 @@ MatrixClient::onMessagesResponse(QNetworkReply *reply) } void +MatrixClient::onJoinRoomResponse(QNetworkReply *reply) +{ + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (status == 0 || status >= 400) { + qWarning() << reply->errorString(); + return; + } + + auto data = reply->readAll(); + QJsonDocument response = QJsonDocument::fromJson(data); + QString room_id = response.object()["room_id"].toString(); + emit joinedRoom(room_id); +} + +void +MatrixClient::onLeaveRoomResponse(QNetworkReply *reply) +{ + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (status == 0 || status >= 400) { + qWarning() << reply->errorString(); + return; + } + + QString room_id = reply->property("room_id").toString(); + emit leftRoom(room_id); +} + +void MatrixClient::onResponse(QNetworkReply *reply) { switch (static_cast<Endpoint>(reply->property("endpoint").toInt())) { @@ -508,6 +542,12 @@ MatrixClient::onResponse(QNetworkReply *reply) case Endpoint::Messages: onMessagesResponse(reply); break; + case Endpoint::JoinRoom: + onJoinRoomResponse(reply); + break; + case Endpoint::LeaveRoom: + onLeaveRoomResponse(reply); + break; default: break; } @@ -571,7 +611,8 @@ void MatrixClient::sync() noexcept { QJsonObject filter{ { "room", - QJsonObject{ { "ephemeral", QJsonObject{ { "limit", 0 } } } } }, + QJsonObject{ { "include_leave", true }, + { "ephemeral", QJsonObject{ { "limit", 0 } } } } }, { "presence", QJsonObject{ { "limit", 0 } } } }; QUrlQuery query; @@ -842,3 +883,38 @@ MatrixClient::uploadImage(const QString &roomid, const QString &filename) reply->setProperty("room_id", roomid); reply->setProperty("filename", filename); } + +void +MatrixClient::joinRoom(const QString &roomIdOrAlias) +{ + QUrlQuery query; + query.addQueryItem("access_token", token_); + + QUrl endpoint(server_); + endpoint.setPath(clientApiUrl_ + QString("/join/%1").arg(roomIdOrAlias)); + endpoint.setQuery(query); + + QNetworkRequest request(endpoint); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + + QNetworkReply *reply = post(request, "{}"); + reply->setProperty("endpoint", static_cast<int>(Endpoint::JoinRoom)); +} + +void +MatrixClient::leaveRoom(const QString &roomId) +{ + QUrlQuery query; + query.addQueryItem("access_token", token_); + + QUrl endpoint(server_); + endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/leave").arg(roomId)); + endpoint.setQuery(query); + + QNetworkRequest request(endpoint); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + + QNetworkReply *reply = post(request, "{}"); + reply->setProperty("room_id", roomId); + reply->setProperty("endpoint", static_cast<int>(Endpoint::LeaveRoom)); +} diff --git a/src/RoomInfoListItem.cc b/src/RoomInfoListItem.cc
index 533fc267..cd15d839 100644 --- a/src/RoomInfoListItem.cc +++ b/src/RoomInfoListItem.cc
@@ -53,12 +53,15 @@ RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings, menu_ = new Menu(this); toggleNotifications_ = new QAction(notificationText(), this); - connect(toggleNotifications_, &QAction::triggered, this, [=]() { roomSettings_->toggleNotifications(); }); + leaveRoom_ = new QAction(tr("Leave room"), this); + connect(leaveRoom_, &QAction::triggered, this, [=]() { emit leaveRoom(room_id); }); + menu_->addAction(toggleNotifications_); + menu_->addAction(leaveRoom_); } QString diff --git a/src/RoomList.cc b/src/RoomList.cc
index 5c67d98f..9dc7e1c2 100644 --- a/src/RoomList.cc +++ b/src/RoomList.cc
@@ -19,6 +19,7 @@ #include <QJsonArray> #include <QRegularExpression> +#include "MainWindow.h" #include "RoomInfoListItem.h" #include "RoomList.h" #include "Sync.h" @@ -70,6 +71,36 @@ RoomList::clear() } void +RoomList::addRoom(const QSharedPointer<RoomSettings> &settings, + const RoomState &state, + const QString &room_id) +{ + RoomInfoListItem *room_item = new RoomInfoListItem(settings, state, room_id, scrollArea_); + connect(room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom); + connect(room_item, &RoomInfoListItem::leaveRoom, this, &RoomList::openLeaveRoomDialog); + + rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item)); + + client_->fetchRoomAvatar(room_id, state.getAvatar()); + + contentsLayout_->insertWidget(0, room_item); +} + +void +RoomList::removeRoom(const QString &room_id, bool reset) +{ + rooms_.remove(room_id); + + if (rooms_.isEmpty() || !reset) + return; + + auto first_room = rooms_.first(); + first_room->setPressedState(true); + + emit roomChanged(rooms_.firstKey()); +} + +void RoomList::updateUnreadMessageCount(const QString &roomid, int count) { if (!rooms_.contains(roomid)) { @@ -116,6 +147,7 @@ RoomList::setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &set new RoomInfoListItem(settings[room_id], state, room_id, scrollArea_); connect( room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom); + connect(room_item, &RoomInfoListItem::leaveRoom, this, &RoomList::openLeaveRoomDialog); rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item)); @@ -133,15 +165,31 @@ RoomList::setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &set } void +RoomList::openLeaveRoomDialog(const QString &room_id) +{ + leaveRoomDialog_ = new LeaveRoomDialog(this); + connect(leaveRoomDialog_, + &LeaveRoomDialog::closing, this, + [=](bool leaving) { closeLeaveRoomDialog(leaving, room_id); }); + + leaveRoomModal = new OverlayModal(MainWindow::instance(), leaveRoomDialog_); + leaveRoomModal->setDuration(0); + leaveRoomModal->setColor(QColor(55, 55, 55, 170)); + + leaveRoomModal->fadeIn(); +} + +void RoomList::sync(const QMap<QString, RoomState> &states) { for (auto it = states.constBegin(); it != states.constEnd(); it++) { auto room_id = it.key(); auto state = it.value(); - // TODO: Add the new room to the list. - if (!rooms_.contains(room_id)) - continue; + if (!rooms_.contains(room_id)) { + addRoom( + QSharedPointer<RoomSettings>(new RoomSettings(room_id)), state, room_id); + } auto room = rooms_[room_id]; @@ -203,3 +251,23 @@ RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info) rooms_.value(roomid)->setDescriptionMessage(info); } + +void +RoomList::closeJoinRoomDialog(bool isJoining, QString roomAlias) +{ + joinRoomModal_->fadeOut(); + + if (isJoining) { + client_->joinRoom(roomAlias); + } +} + +void +RoomList::closeLeaveRoomDialog(bool leaving, const QString &room_id) +{ + leaveRoomModal->fadeOut(); + + if (leaving) { + client_->leaveRoom(room_id); + } +} diff --git a/src/Sync.cc b/src/Sync.cc
index 58c423d1..90314352 100644 --- a/src/Sync.cc +++ b/src/Sync.cc
@@ -90,7 +90,6 @@ Rooms::deserialize(const QJsonValue &data) for (auto it = join.constBegin(); it != join.constEnd(); it++) { JoinedRoom tmp_room; - try { tmp_room.deserialize(it.value()); join_.insert(it.key(), tmp_room); @@ -112,7 +111,19 @@ Rooms::deserialize(const QJsonValue &data) if (!object.value("leave").isObject()) { throw DeserializationException("rooms/leave must be a JSON object"); } - // TODO: Implement leave handling + auto leave = object.value("leave").toObject(); + + for (auto it = leave.constBegin(); it != leave.constEnd(); it++) { + LeftRoom tmp_room; + + try { + tmp_room.deserialize(it.value()); + leave_.insert(it.key(), tmp_room); + } catch (DeserializationException &e) { + qWarning() << e.what(); + qWarning() << "Skipping malformed object for room" << it.key(); + } + } } } @@ -185,6 +196,32 @@ JoinedRoom::deserialize(const QJsonValue &data) } void +LeftRoom::deserialize(const QJsonValue &data) +{ + if (!data.isObject()) + throw DeserializationException("LeftRoom is not a JSON object"); + + QJsonObject object = data.toObject(); + + if (!object.contains("state")) + throw DeserializationException("leave/state is missing"); + + if (!object.contains("timeline")) + throw DeserializationException("leave/timeline is missing"); + + if (!object.value("state").isObject()) + throw DeserializationException("leave/state should be an object"); + + QJsonObject state = object.value("state").toObject(); + + if (!state.contains("events")) + throw DeserializationException("leave/state/events is missing"); + + state_.deserialize(state.value("events")); + timeline_.deserialize(object.value("timeline")); +} + +void Event::deserialize(const QJsonValue &data) { if (!data.isObject()) diff --git a/src/TimelineViewManager.cc b/src/TimelineViewManager.cc
index a4d616c3..1969ae5b 100644 --- a/src/TimelineViewManager.cc +++ b/src/TimelineViewManager.cc
@@ -101,19 +101,7 @@ void TimelineViewManager::initialize(const Rooms &rooms) { for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { - auto roomid = it.key(); - - // Create a history view with the room events. - TimelineView *view = new TimelineView(it.value().timeline(), client_, it.key()); - views_.insert(it.key(), QSharedPointer<TimelineView>(view)); - - connect(view, - &TimelineView::updateLastTimelineMessage, - this, - &TimelineViewManager::updateRoomsLastMessage); - - // Add the view in the widget stack. - addWidget(view); + addRoom(it.value(), it.key()); } } @@ -121,18 +109,40 @@ void TimelineViewManager::initialize(const QList<QString> &rooms) { for (const auto &roomid : rooms) { - // Create a history view without any events. - TimelineView *view = new TimelineView(client_, roomid); - views_.insert(roomid, QSharedPointer<TimelineView>(view)); + addRoom(roomid); + } +} + +void +TimelineViewManager::addRoom(const JoinedRoom &room, const QString &room_id) +{ + // Create a history view with the room events. + TimelineView *view = new TimelineView(room.timeline(), client_, room_id); + views_.insert(room_id, QSharedPointer<TimelineView>(view)); - connect(view, - &TimelineView::updateLastTimelineMessage, - this, - &TimelineViewManager::updateRoomsLastMessage); + connect(view, + &TimelineView::updateLastTimelineMessage, + this, + &TimelineViewManager::updateRoomsLastMessage); - // Add the view in the widget stack. - addWidget(view); - } + // Add the view in the widget stack. + addWidget(view); +} + +void +TimelineViewManager::addRoom(const QString &room_id) +{ + // Create a history view without any events. + TimelineView *view = new TimelineView(client_, room_id); + views_.insert(room_id, QSharedPointer<TimelineView>(view)); + + connect(view, + &TimelineView::updateLastTimelineMessage, + this, + &TimelineViewManager::updateRoomsLastMessage); + + // Add the view in the widget stack. + addWidget(view); } void diff --git a/src/TopRoomBar.cc b/src/TopRoomBar.cc
index 1805f063..f8a7e600 100644 --- a/src/TopRoomBar.cc +++ b/src/TopRoomBar.cc
@@ -18,6 +18,7 @@ #include <QStyleOption> #include "Config.h" +#include "MainWindow.h" #include "TopRoomBar.h" TopRoomBar::TopRoomBar(QWidget *parent) @@ -83,7 +84,21 @@ TopRoomBar::TopRoomBar(QWidget *parent) roomSettings_->toggleNotifications(); }); + leaveRoom_ = new QAction(tr("Leave room"), this); + connect(leaveRoom_, &QAction::triggered, this, [=]() { + leaveRoomDialog_ = new LeaveRoomDialog(this); + connect( + leaveRoomDialog_, SIGNAL(closing(bool)), this, SLOT(closeLeaveRoomDialog(bool))); + + leaveRoomModal = new OverlayModal(MainWindow::instance(), leaveRoomDialog_); + leaveRoomModal->setDuration(100); + leaveRoomModal->setColor(QColor(55, 55, 55, 170)); + + leaveRoomModal->fadeIn(); + }); + menu_->addAction(toggleNotifications_); + menu_->addAction(leaveRoom_); connect(settingsBtn_, &QPushButton::clicked, this, [=]() { if (roomSettings_->isNotificationsEnabled()) @@ -100,6 +115,16 @@ TopRoomBar::TopRoomBar(QWidget *parent) } void +TopRoomBar::closeLeaveRoomDialog(bool leaving) +{ + leaveRoomModal->fadeOut(); + + if (leaving) { + emit leaveRoom(); + } +} + +void TopRoomBar::updateRoomAvatarFromName(const QString &name) { QChar letter = '?';