diff --git a/CMakeLists.txt b/CMakeLists.txt index 628a5db2..08d3cf68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ set(SRC_FILES src/TimelineViewManager.cc src/InputValidator.cc src/JoinRoomDialog.cc + src/LeaveRoomDialog.cc src/Login.cc src/LoginPage.cc src/LogoutDialog.cc @@ -208,6 +209,7 @@ qt5_wrap_cpp(MOC_HEADERS include/TimelineItem.h include/TimelineView.h include/TimelineViewManager.h + include/LeaveRoomDialog.h include/LoginPage.h include/LogoutDialog.h include/MainWindow.h diff --git a/include/ChatPage.h b/include/ChatPage.h index f628fc1b..8becc17f 100644 --- a/include/ChatPage.h +++ b/include/ChatPage.h @@ -61,8 +61,8 @@ private slots: void changeTopRoomInfo(const QString &room_id); void startSync(); void logout(); - void joinedRoom(const QString &room_id); - void leftRoom(const QString &room_id); + void addRoom(const QString &room_id); + void removeRoom(const QString &room_id); protected: void keyPressEvent(QKeyEvent *event) override; diff --git a/include/LeaveRoomDialog.h b/include/LeaveRoomDialog.h new file mode 100644 index 00000000..1639a578 --- /dev/null +++ b/include/LeaveRoomDialog.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "FlatButton.h" + +class LeaveRoomDialog : public QFrame +{ + Q_OBJECT +public: + explicit LeaveRoomDialog(QWidget *parent = nullptr); + +signals: + void closing(bool isLeaving); + +private: + FlatButton *confirmBtn_; + FlatButton *cancelBtn_; +}; diff --git a/include/RoomList.h b/include/RoomList.h index 2db0e650..c3671358 100644 --- a/include/RoomList.h +++ b/include/RoomList.h @@ -24,6 +24,7 @@ #include #include "JoinRoomDialog.h" +#include "LeaveRoomDialog.h" #include "MatrixClient.h" #include "OverlayModal.h" #include "RoomInfoListItem.h" @@ -59,6 +60,7 @@ public slots: void updateUnreadMessageCount(const QString &roomid, int count); void updateRoomDescription(const QString &roomid, const DescInfo &info); void closeJoinRoomDialog(bool isJoining, QString roomAlias); + void closeLeaveRoomDialog(bool leaving, const QString &room_id); private: void calculateUnreadMessageCount(); @@ -73,6 +75,9 @@ private: OverlayModal *joinRoomModal_; JoinRoomDialog *joinRoomDialog_; + OverlayModal *leaveRoomModal; + LeaveRoomDialog *leaveRoomDialog_; + QMap> rooms_; QSharedPointer client_; diff --git a/include/TopRoomBar.h b/include/TopRoomBar.h index 2397e47e..5d8b394e 100644 --- a/include/TopRoomBar.h +++ b/include/TopRoomBar.h @@ -29,7 +29,9 @@ #include "Avatar.h" #include "FlatButton.h" +#include "LeaveRoomDialog.h" #include "Menu.h" +#include "OverlayModal.h" #include "RoomSettings.h" static const QString URL_HTML = "\\1"; @@ -57,6 +59,9 @@ signals: protected: void paintEvent(QPaintEvent *event) override; +private slots: + void closeLeaveRoomDialog(bool leaving); + private: QHBoxLayout *topLayout_; QVBoxLayout *textLayout_; @@ -72,6 +77,9 @@ private: FlatButton *settingsBtn_; + OverlayModal *leaveRoomModal; + LeaveRoomDialog *leaveRoomDialog_; + Avatar *avatar_; int buttonSize_; diff --git a/src/ChatPage.cc b/src/ChatPage.cc index 7caa080c..9a1a2652 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc @@ -193,12 +193,12 @@ ChatPage::ChatPage(QSharedPointer client, QWidget *parent) SIGNAL(ownAvatarRetrieved(const QPixmap &)), this, SLOT(setOwnAvatar(const QPixmap &))); - connect(client_.data(), - SIGNAL(joinedRoom(const QString &)), - this, - SLOT(joinedRoom(const QString &))); connect( - client_.data(), SIGNAL(leftRoom(const QString &)), this, SLOT(leftRoom(const QString &))); + client_.data(), SIGNAL(addRoom(const QString &)), this, SLOT(addRoom(const QString &))); + connect(client_.data(), + SIGNAL(removeRoom(const QString &)), + this, + SLOT(removeRoom(const QString &))); AvatarProvider::init(client); } @@ -355,7 +355,7 @@ ChatPage::syncCompleted(const SyncResponse &response) for (auto it = leave.constBegin(); it != leave.constEnd(); it++) { if (state_manager_.contains(it.key())) { - leftRoom(it.key()); + removeRoom(it.key()); } } @@ -583,7 +583,7 @@ ChatPage::showQuickSwitcher() } void -ChatPage::joinedRoom(const QString &room_id) +ChatPage::addRoom(const QString &room_id) { if (!state_manager_.contains(room_id)) { RoomState room_state; @@ -600,7 +600,7 @@ ChatPage::joinedRoom(const QString &room_id) } void -ChatPage::leftRoom(const QString &room_id) +ChatPage::removeRoom(const QString &room_id) { state_manager_.remove(room_id); settingsManager_.remove(room_id); 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/LeaveRoomDialog.cc b/src/LeaveRoomDialog.cc new file mode 100644 index 00000000..f7669f0d --- /dev/null +++ b/src/LeaveRoomDialog.cc @@ -0,0 +1,44 @@ +#include +#include + +#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/RoomList.cc b/src/RoomList.cc index 2ceb8450..25f2fc2e 100644 --- a/src/RoomList.cc +++ b/src/RoomList.cc @@ -56,29 +56,10 @@ RoomList::RoomList(QSharedPointer client, QWidget *parent) scrollArea_->setWidget(scrollAreaContents_); topLayout_->addWidget(scrollArea_); - // joinRoomButton_ = new QPushButton("Join room", this); - // topLayout_->addWidget(joinRoomButton_); - connect(client_.data(), SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)), this, SLOT(updateRoomAvatar(const QString &, const QPixmap &))); - - /* Nonfunctional and disabled - * connect(joinRoomButton_, &QPushButton::clicked, this, [=]() { - joinRoomDialog_ = new JoinRoomDialog(this); - connect(joinRoomDialog_, - SIGNAL(closing(bool, QString)), - this, - SLOT(closeJoinRoomDialog(bool, QString))); - - joinRoomModal_ = new OverlayModal(MainWindow::instance(), joinRoomDialog_); - joinRoomModal_->setDuration(100); - joinRoomModal_->setColor(QColor(55, 55, 55, 170)); - - joinRoomModal_->fadeIn(); - }); - */ } RoomList::~RoomList() {} @@ -96,10 +77,23 @@ RoomList::addRoom(const QSharedPointer &settings, { RoomInfoListItem *room_item = new RoomInfoListItem(settings, state, room_id, scrollArea_); connect(room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom); - connect(room_item, &RoomInfoListItem::leaveRoom, client_.data(), &MatrixClient::leaveRoom); + connect(room_item, &RoomInfoListItem::leaveRoom, client_.data(), [=]() { + leaveRoomDialog_ = new LeaveRoomDialog(this); + connect(leaveRoomDialog_, &LeaveRoomDialog::closing, this, [=](bool leaving) { + closeLeaveRoomDialog(leaving, room_id); + }); + + leaveRoomModal = new OverlayModal(MainWindow::instance(), leaveRoomDialog_); + leaveRoomModal->setDuration(100); + leaveRoomModal->setColor(QColor(55, 55, 55, 170)); + + leaveRoomModal->fadeIn(); + }); rooms_.insert(room_id, QSharedPointer(room_item)); + client_->fetchRoomAvatar(room_id, state.getAvatar()); + contentsLayout_->insertWidget(0, room_item); } @@ -164,10 +158,19 @@ RoomList::setInitialRooms(const QMap> &set new RoomInfoListItem(settings[room_id], state, room_id, scrollArea_); connect( room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom); - connect(room_item, - &RoomInfoListItem::leaveRoom, - client_.data(), - &MatrixClient::leaveRoom); + connect(room_item, &RoomInfoListItem::leaveRoom, client_.data(), [=]() { + leaveRoomDialog_ = new LeaveRoomDialog(this); + connect(leaveRoomDialog_, + &LeaveRoomDialog::closing, + this, + [=](bool leaving) { closeLeaveRoomDialog(leaving, room_id); }); + + leaveRoomModal = new OverlayModal(MainWindow::instance(), leaveRoomDialog_); + leaveRoomModal->setDuration(100); + leaveRoomModal->setColor(QColor(55, 55, 55, 170)); + + leaveRoomModal->fadeIn(); + }); rooms_.insert(room_id, QSharedPointer(room_item)); @@ -191,7 +194,6 @@ RoomList::sync(const QMap &states) auto room_id = it.key(); auto state = it.value(); - // TODO: Add the new room to the list. if (!rooms_.contains(room_id)) { addRoom( QSharedPointer(new RoomSettings(room_id)), state, room_id); @@ -267,3 +269,13 @@ RoomList::closeJoinRoomDialog(bool isJoining, QString roomAlias) 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 6795a951..810e487d 100644 --- a/src/Sync.cc +++ b/src/Sync.cc @@ -82,7 +82,6 @@ Rooms::deserialize(const QJsonValue &data) QJsonObject object = data.toObject(); -<<<<<<< HEAD if (object.contains("join")) { if (!object.value("join").isObject()) throw DeserializationException("rooms/join must be a JSON object"); @@ -97,40 +96,7 @@ Rooms::deserialize(const QJsonValue &data) } catch (DeserializationException &e) { qWarning() << e.what(); qWarning() << "Skipping malformed object for room" << it.key(); - } -======= - if (!object.contains("join")) - throw DeserializationException("rooms/join is missing"); - - if (!object.contains("invite")) - throw DeserializationException("rooms/invite is missing"); - - if (!object.contains("leave")) - throw DeserializationException("rooms/leave is missing"); - - if (!object.value("join").isObject()) - throw DeserializationException("rooms/join must be a JSON object"); - - if (!object.value("invite").isObject()) - throw DeserializationException("rooms/invite must be a JSON object"); - - if (!object.value("leave").isObject()) - throw DeserializationException("rooms/leave must be a JSON object"); - - auto join = object.value("join").toObject(); - auto leave = object.value("leave").toObject(); - - for (auto it = join.constBegin(); it != join.constEnd(); it++) { - JoinedRoom tmp_room; - - try { - tmp_room.deserialize(it.value()); - join_.insert(it.key(), tmp_room); - } catch (DeserializationException &e) { - qWarning() << e.what(); - qWarning() << "Skipping malformed object for room" << it.key(); ->>>>>>> `make lint` - } + } } } if (object.contains("invite")) { @@ -238,18 +204,18 @@ LeftRoom::deserialize(const QJsonValue &data) QJsonObject object = data.toObject(); if (!object.contains("state")) - throw DeserializationException("join/state is missing"); + throw DeserializationException("leave/state is missing"); if (!object.contains("timeline")) - throw DeserializationException("join/timeline is missing"); + throw DeserializationException("leave/timeline is missing"); if (!object.value("state").isObject()) - throw DeserializationException("join/state should be an object"); + throw DeserializationException("leave/state should be an object"); QJsonObject state = object.value("state").toObject(); if (!state.contains("events")) - throw DeserializationException("join/state/events is missing"); + throw DeserializationException("leave/state/events is missing"); state_.deserialize(state.value("events")); timeline_.deserialize(object.value("timeline")); diff --git a/src/TopRoomBar.cc b/src/TopRoomBar.cc index 77f672e6..f8a7e600 100644 --- a/src/TopRoomBar.cc +++ b/src/TopRoomBar.cc @@ -18,6 +18,7 @@ #include #include "Config.h" +#include "MainWindow.h" #include "TopRoomBar.h" TopRoomBar::TopRoomBar(QWidget *parent) @@ -84,7 +85,17 @@ TopRoomBar::TopRoomBar(QWidget *parent) }); leaveRoom_ = new QAction(tr("Leave room"), this); - connect(leaveRoom_, &QAction::triggered, this, [=]() { emit leaveRoom(); }); + 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_); @@ -103,6 +114,16 @@ TopRoomBar::TopRoomBar(QWidget *parent) setLayout(topLayout_); } +void +TopRoomBar::closeLeaveRoomDialog(bool leaving) +{ + leaveRoomModal->fadeOut(); + + if (leaving) { + emit leaveRoom(); + } +} + void TopRoomBar::updateRoomAvatarFromName(const QString &name) { diff --git a/tests/message_events.cc b/tests/message_events.cc index dfff50ab..6af2b588 100644 --- a/tests/message_events.cc +++ b/tests/message_events.cc @@ -99,7 +99,10 @@ TEST(MessageEvent, File) TEST(MessageEvent, Image) { auto thumbinfo = QJsonObject{ - { "h", 11 }, { "w", 22 }, { "size", 212 }, { "mimetype", "img/jpeg" }, + { "h", 11 }, + { "w", 22 }, + { "size", 212 }, + { "mimetype", "img/jpeg" }, }; auto imginfo = QJsonObject{ @@ -239,49 +242,49 @@ TEST(MessageEvent, Video) TEST(MessageEvent, Types) { - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.audio" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Audio); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.emote" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Emote); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.file" } } }, { "type", "m.room.message" }, - }), - MessageEventType::File); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.image" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Image); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.location" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Location); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.notice" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Notice); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.text" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Text); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.video" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Video); - EXPECT_EQ( - extractMessageEventType(QJsonObject{ - { "content", QJsonObject{ { "msgtype", "m.random" } } }, { "type", "m.room.message" }, - }), - MessageEventType::Unknown); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.audio" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Audio); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.emote" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Emote); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.file" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::File); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.image" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Image); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.location" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Location); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.notice" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Notice); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.text" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Text); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.video" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Video); + EXPECT_EQ(extractMessageEventType(QJsonObject{ + { "content", QJsonObject{ { "msgtype", "m.random" } } }, + { "type", "m.room.message" }, + }), + MessageEventType::Unknown); }