diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp index 8b450d7e..df4eaeee 100644 --- a/src/dialogs/RoomSettings.cpp +++ b/src/dialogs/RoomSettings.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ #include "Utils.h" #include "ui/Avatar.h" #include "ui/FlatButton.h" +#include "ui/LoadingIndicator.h" #include "ui/Painter.h" #include "ui/TextField.h" #include "ui/Theme.h" @@ -207,7 +209,39 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent) accessCombo->addItem(tr("Anyone and guests")); accessCombo->addItem(tr("Anyone")); accessCombo->addItem(tr("Invited users")); - accessCombo->setDisabled(true); + accessCombo->setDisabled( + !canChangeJoinRules(room_id_.toStdString(), utils::localUser().toStdString())); + connect(accessCombo, QOverload::of(&QComboBox::activated), [this](int index) { + using namespace mtx::events::state; + + auto guest_access = [](int index) -> state::GuestAccess { + state::GuestAccess event; + + if (index == 0) + event.guest_access = state::AccessState::CanJoin; + else + event.guest_access = state::AccessState::Forbidden; + + return event; + }(index); + + auto join_rule = [](int index) -> state::JoinRules { + state::JoinRules event; + + switch (index) { + case 0: + case 1: + event.join_rule = JoinRule::Public; + break; + default: + event.join_rule = JoinRule::Invite; + } + + return event; + }(index); + + updateAccessRules(room_id_.toStdString(), join_rule, guest_access); + }); if (info_.join_rule == JoinRule::Public) { if (info_.guest_access) { @@ -321,6 +355,20 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent) setupEditButton(); + errorLabel_ = new QLabel(this); + errorLabel_->setAlignment(Qt::AlignCenter); + errorLabel_->hide(); + + spinner_ = new LoadingIndicator(this); + spinner_->setFixedHeight(30); + spinner_->setFixedWidth(30); + spinner_->hide(); + auto spinnerLayout = new QVBoxLayout; + spinnerLayout->addWidget(spinner_); + spinnerLayout->setAlignment(Qt::AlignCenter); + spinnerLayout->setMargin(0); + spinnerLayout->setSpacing(0); + layout->addWidget(avatar_, Qt::AlignCenter | Qt::AlignTop); layout->addLayout(textLayout); layout->addLayout(btnLayout_); @@ -329,6 +377,8 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent) layout->addLayout(accessOptionLayout); layout->addLayout(encryptionOptionLayout); layout->addLayout(keyRequestsLayout); + layout->addWidget(errorLabel_); + layout->addLayout(spinnerLayout); layout->addStretch(1); connect(this, &RoomSettings::enableEncryptionError, this, [this](const QString &msg) { @@ -337,6 +387,21 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent) emit ChatPage::instance()->showNotification(msg); }); + + connect(this, &RoomSettings::showErrorMessage, this, [this](const QString &msg) { + if (!errorLabel_) + return; + + stopLoadingSpinner(); + + errorLabel_->show(); + errorLabel_->setText(msg); + }); + + connect(this, &RoomSettings::accessRulesUpdated, this, [this]() { + stopLoadingSpinner(); + resetErrorLabel(); + }); } void @@ -346,16 +411,7 @@ RoomSettings::setupEditButton() btnLayout_->setSpacing(BUTTON_SPACING); btnLayout_->setMargin(0); - try { - auto userId = utils::localUser().toStdString(); - - hasEditRights_ = cache::client()->hasEnoughPowerLevel( - {EventType::RoomName, EventType::RoomTopic}, room_id_.toStdString(), userId); - } catch (const lmdb::error &e) { - nhlog::db()->warn("lmdb error: {}", e.what()); - } - - if (!hasEditRights_) + if (!canChangeNameAndTopic(room_id_.toStdString(), utils::localUser().toStdString())) return; QIcon editIcon; @@ -397,30 +453,6 @@ RoomSettings::retrieveRoomInfo() } } -void -RoomSettings::saveSettings() -{ - // TODO: Save access changes to the room - if (accessCombo->currentIndex() < 2) { - if (info_.join_rule != JoinRule::Public) { - // Make join_rule Public - } - if (accessCombo->currentIndex() == 0) { - if (!info_.guest_access) { - // Make guest_access CanJoin - } - } - } else { - if (info_.join_rule != JoinRule::Invite) { - // Make join_rule invite - } - if (info_.guest_access) { - // Make guest_access forbidden - } - } - closing(); -} - void RoomSettings::enableEncryption() { @@ -443,6 +475,15 @@ RoomSettings::enableEncryption() }); } +void +RoomSettings::showEvent(QShowEvent *event) +{ + resetErrorLabel(); + stopLoadingSpinner(); + + QWidget::showEvent(event); +} + void RoomSettings::paintEvent(QPaintEvent *) { @@ -451,3 +492,97 @@ RoomSettings::paintEvent(QPaintEvent *) QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } + +bool +RoomSettings::canChangeJoinRules(const std::string &room_id, const std::string &user_id) const +{ + try { + return cache::client()->hasEnoughPowerLevel( + {EventType::RoomJoinRules}, room_id, user_id); + } catch (const lmdb::error &e) { + nhlog::db()->warn("lmdb error: {}", e.what()); + } + + return false; +} + +bool +RoomSettings::canChangeNameAndTopic(const std::string &room_id, const std::string &user_id) const +{ + try { + return cache::client()->hasEnoughPowerLevel( + {EventType::RoomName, EventType::RoomTopic}, room_id, user_id); + } catch (const lmdb::error &e) { + nhlog::db()->warn("lmdb error: {}", e.what()); + } + + return false; +} + +void +RoomSettings::updateAccessRules(const std::string &room_id, + const mtx::events::state::JoinRules &join_rule, + const mtx::events::state::GuestAccess &guest_access) +{ + startLoadingSpinner(); + resetErrorLabel(); + + http::client()->send_state_event( + room_id, + join_rule, + [this, room_id, guest_access](const mtx::responses::EventId &, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("failed to send m.room.join_rule: {} {}", + static_cast(err->status_code), + err->matrix_error.error); + emit showErrorMessage(QString::fromStdString(err->matrix_error.error)); + + return; + } + + http::client()->send_state_event( + room_id, + guest_access, + [this](const mtx::responses::EventId &, mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("failed to send m.room.guest_access: {} {}", + static_cast(err->status_code), + err->matrix_error.error); + emit showErrorMessage( + QString::fromStdString(err->matrix_error.error)); + + return; + } + + emit accessRulesUpdated(); + }); + }); +} + +void +RoomSettings::stopLoadingSpinner() +{ + if (spinner_) { + spinner_->stop(); + spinner_->hide(); + } +} + +void +RoomSettings::startLoadingSpinner() +{ + if (spinner_) { + spinner_->start(); + spinner_->show(); + } +} + +void +RoomSettings::resetErrorLabel() +{ + if (errorLabel_) { + errorLabel_->hide(); + errorLabel_->clear(); + } +} diff --git a/src/dialogs/RoomSettings.h b/src/dialogs/RoomSettings.h index 321ea551..192e922f 100644 --- a/src/dialogs/RoomSettings.h +++ b/src/dialogs/RoomSettings.h @@ -9,6 +9,8 @@ class Avatar; class FlatButton; class QComboBox; class QHBoxLayout; +class QShowEvent; +class LoadingIndicator; class QLabel; class QLabel; class QLayout; @@ -60,15 +62,24 @@ public: signals: void closing(); void enableEncryptionError(const QString &msg); + void showErrorMessage(const QString &msg); + void accessRulesUpdated(); protected: void paintEvent(QPaintEvent *event) override; - -private slots: - void saveSettings(); + void showEvent(QShowEvent *event) override; private: - static constexpr int AvatarSize = 64; + //! Whether the user has enough power level to send m.room.join_rules events. + bool canChangeJoinRules(const std::string &room_id, const std::string &user_id) const; + //! Whether the user has enough power level to send m.room.name & m.room.topic events. + bool canChangeNameAndTopic(const std::string &room_id, const std::string &user_id) const; + void updateAccessRules(const std::string &room_id, + const mtx::events::state::JoinRules &, + const mtx::events::state::GuestAccess &); + void stopLoadingSpinner(); + void startLoadingSpinner(); + void resetErrorLabel(); void setAvatar(const QImage &img) { avatarImg_ = img; } void setupEditButton(); @@ -78,8 +89,6 @@ private: Avatar *avatar_; - //! Whether the user would be able to change the name or the topic of the room. - bool hasEditRights_ = true; bool usesEncryption_ = false; QHBoxLayout *btnLayout_; @@ -89,6 +98,9 @@ private: QString room_id_; QImage avatarImg_; + QLabel *errorLabel_; + LoadingIndicator *spinner_; + QComboBox *accessCombo; Toggle *encryptionToggle_; Toggle *keyRequestsToggle_;