From b70f37194fd968950c920b1c39388154aa46cdc1 Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Wed, 10 Feb 2021 21:22:42 +0530 Subject: ui almost looks the same, midway between transition from old room settings to new room settings --- src/ui/RoomSettings.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/ui/RoomSettings.cpp (limited to 'src/ui/RoomSettings.cpp') diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp new file mode 100644 index 00000000..e8317024 --- /dev/null +++ b/src/ui/RoomSettings.cpp @@ -0,0 +1,33 @@ +#include "RoomSettings.h" + +#include +#include + +#include "Cache.h" +#include "Logging.h" + +RoomSettings::RoomSettings(QString roomid, QObject *parent) + : roomid_{std::move(roomid)} + , QObject(parent) +{ + retrieveRoomInfo(); +} + +QString +RoomSettings::roomName() const +{ + return QString(info_.name.c_str()); +} + +void +RoomSettings::retrieveRoomInfo() +{ + try { + usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString()); + info_ = cache::singleRoomInfo(roomid_.toStdString()); + //setAvatar(); + } catch (const lmdb::error &) { + nhlog::db()->warn("failed to retrieve room info from cache: {}", + roomid_.toStdString()); + } +} \ No newline at end of file -- cgit 1.5.1 From 7401bd13b272bbe9a0415c2e523f8ec0fa7f3e11 Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Thu, 11 Feb 2021 19:54:09 +0530 Subject: added notifications and encryption for the new roomsettings --- resources/qml/RoomSettings.qml | 58 +++++++- resources/qml/TimelineView.qml | 2 +- src/timeline/TimelineViewManager.cpp | 10 +- src/timeline/TimelineViewManager.h | 2 +- src/ui/RoomSettings.cpp | 257 ++++++++++++++++++++++++++++++++++- src/ui/RoomSettings.h | 29 ++++ 6 files changed, 352 insertions(+), 6 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index d6f3fe7b..4b03e08b 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -2,6 +2,7 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.2 import QtQuick.Window 2.3 +import QtQuick.Dialogs 1.2 import im.nheko 1.0 ApplicationWindow { @@ -17,7 +18,8 @@ ApplicationWindow { palette: colors color: colors.window title: roomSettings.roomName - modality: Qt.Modal + modality: Qt.WindowModal + flags: Qt.WindowStaysOnTopHint Shortcut { sequence: StandardKey.Cancel @@ -75,6 +77,10 @@ ApplicationWindow { ComboBox { model: [ "Muted", "Mentions only", "All messages" ] + currentIndex: roomSettings.notifications + onActivated: { + roomSettings.changeNotifications(index) + } } } @@ -85,7 +91,12 @@ ApplicationWindow { ComboBox { Layout.fillWidth: true + enabled: roomSettings.canChangeJoinRules model: [ "Anyone and guests", "Anyone", "Invited users" ] + currentIndex: roomSettings.accessJoinRules + onActivated: { + roomSettings.changeAccessRules(index) + } } } @@ -99,10 +110,46 @@ ApplicationWindow { } Switch { + id: encryptionSwitch + + checked: roomSettings.isEncryptionEnabled + onToggled: { + if(roomSettings.isEncryptionEnabled) { + checked=true; + return; + } + + confirmEncryptionDialog.open(); + } + } + + MessageDialog { + id: confirmEncryptionDialog + title: qsTr("End-to-End Encryption") + text: qsTr("Encryption is currently experimental and things might break unexpectedly.
+ Please take note that it can't be disabled afterwards.") + modality: Qt.WindowModal + icon: StandardIcon.Question + + onAccepted: { + if(roomSettings.isEncryptionEnabled) { + return; + } + + roomSettings.enableEncryption(); + } + + onRejected: { + encryptionSwitch.checked = false + } + + standardButtons: Dialog.Ok | Dialog.Cancel } } RowLayout { + visible: roomSettings.isEncryptionEnabled + MatrixText { text: "Respond to key requests" } @@ -112,6 +159,15 @@ ApplicationWindow { } Switch { + ToolTip.text: qsTr("Whether or not the client should respond automatically with the session keys + upon request. Use with caution, this is a temporary measure to test the + E2E implementation until device verification is completed.") + + checked: roomSettings.respondsToKeyRequests + + onToggled: { + roomSettings.changeKeyRequestsPreference(checked) + } } } diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 6b34f2ab..0c32effd 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -178,7 +178,7 @@ Page { target: TimelineManager onOpenRoomSettingsDialog: { var roomSettings = roomSettingsComponent.createObject(timelineRoot, { - "roomSettings": roomSettings + "roomSettings": settings }); roomSettings.show(); } diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 7c1922d7..4edc3369 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -126,6 +126,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par 0, "UserProfileModel", "UserProfile needs to be instantiated on the C++ side"); + qmlRegisterUncreatableType( + "im.nheko", + 1, + 0, + "RoomSettingsModel", + "Room Settings needs to be instantiated on the C++ side"); static auto self = this; qmlRegisterSingletonType( @@ -394,8 +400,8 @@ TimelineViewManager::openRoomSettings() { MainWindow::instance()->openRoomSettings(timeline_->roomId()); - RoomSettings *roomSettings = new RoomSettings(timeline_->roomId(), this); - emit openRoomSettingsDialog(roomSettings); + RoomSettings *settings = new RoomSettings(timeline_->roomId(), this); + emit openRoomSettingsDialog(settings); } void diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index dca133ce..10708033 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -89,7 +89,7 @@ signals: void showRoomList(); void narrowViewChanged(); void focusChanged(); - void openRoomSettingsDialog(RoomSettings *roomSettings); + void openRoomSettingsDialog(RoomSettings *settings); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids); diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index e8317024..785452d0 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -5,12 +5,65 @@ #include "Cache.h" #include "Logging.h" +#include "MatrixClient.h" +#include "Utils.h" + +using namespace mtx::events; RoomSettings::RoomSettings(QString roomid, QObject *parent) : roomid_{std::move(roomid)} , QObject(parent) { retrieveRoomInfo(); + + // get room setting notifications + http::client()->get_pushrules( + "global", + "override", + roomid_.toStdString(), + [this](const mtx::pushrules::PushRule &rule, mtx::http::RequestErr &err) { + if (err) { + if (err->status_code == boost::beast::http::status::not_found) + http::client()->get_pushrules( + "global", + "room", + roomid_.toStdString(), + [this](const mtx::pushrules::PushRule &rule, + mtx::http::RequestErr &err) { + if (err) { + notifications_ = 2; // all messages + emit notificationsChanged(); + return; + } + + if (rule.enabled) { + notifications_ = 1; // mentions only + emit notificationsChanged(); + } + }); + return; + } + + if (rule.enabled) { + notifications_ = 0; // muted + emit notificationsChanged(); + } else { + notifications_ = 2; // all messages + emit notificationsChanged(); + } + }); + + // access rules + if (info_.join_rule == state::JoinRule::Public) { + if (info_.guest_access) { + accessRules_ = 0; + } else { + accessRules_ = 1; + } + } else { + accessRules_ = 2; + } + emit accessJoinRulesChanged(); } QString @@ -25,9 +78,211 @@ RoomSettings::retrieveRoomInfo() try { usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString()); info_ = cache::singleRoomInfo(roomid_.toStdString()); - //setAvatar(); + // setAvatar(); } catch (const lmdb::error &) { nhlog::db()->warn("failed to retrieve room info from cache: {}", roomid_.toStdString()); } +} + +int +RoomSettings::notifications() +{ + return notifications_; +} + +int +RoomSettings::accessJoinRules() +{ + return accessRules_; +} + +bool +RoomSettings::respondsToKeyRequests() +{ + return usesEncryption_ && utils::respondsToKeyRequests(roomid_); +} + +void +RoomSettings::changeKeyRequestsPreference(bool isOn) +{ + utils::setKeyRequestsPreference(roomid_, isOn); + emit keyRequestsChanged(); +} + +void +RoomSettings::enableEncryption() +{ + if (usesEncryption_) + return; + + const auto room_id = roomid_.toStdString(); + http::client()->enable_encryption( + room_id, [room_id, this](const mtx::responses::EventId &, mtx::http::RequestErr err) { + if (err) { + int status_code = static_cast(err->status_code); + nhlog::net()->warn("failed to enable encryption in room ({}): {} {}", + room_id, + err->matrix_error.error, + status_code); + //emit enableEncryptionError( + // tr("Failed to enable encryption: %1") + // .arg(QString::fromStdString(err->matrix_error.error))); + usesEncryption_ = false; + emit encryptionChanged(); + return; + } + + nhlog::net()->info("enabled encryption on room ({})", room_id); + }); + + usesEncryption_ = true; + emit encryptionChanged(); +} + +bool +RoomSettings::canChangeJoinRules() const +{ + try { + return cache::hasEnoughPowerLevel({EventType::RoomJoinRules}, + roomid_.toStdString(), + utils::localUser().toStdString()); + } catch (const lmdb::error &e) { + nhlog::db()->warn("lmdb error: {}", e.what()); + } + + return false; +} + +bool +RoomSettings::isEncryptionEnabled() const +{ + return usesEncryption_; +} + +void +RoomSettings::changeNotifications(int currentIndex) +{ + notifications_ = currentIndex; + + std::string room_id = roomid_.toStdString(); + if (notifications_ == 0) { + // mute room + // delete old rule first, then add new rule + mtx::pushrules::PushRule rule; + rule.actions = {mtx::pushrules::actions::dont_notify{}}; + mtx::pushrules::PushCondition condition; + condition.kind = "event_match"; + condition.key = "room_id"; + condition.pattern = room_id; + rule.conditions = {condition}; + + http::client()->put_pushrules( + "global", "override", room_id, rule, [room_id](mtx::http::RequestErr &err) { + if (err) + nhlog::net()->error("failed to set pushrule for room {}: {} {}", + room_id, + static_cast(err->status_code), + err->matrix_error.error); + http::client()->delete_pushrules( + "global", "room", room_id, [room_id](mtx::http::RequestErr &) {}); + }); + } else if (notifications_ == 1) { + // mentions only + // delete old rule first, then add new rule + mtx::pushrules::PushRule rule; + rule.actions = {mtx::pushrules::actions::dont_notify{}}; + http::client()->put_pushrules( + "global", "room", room_id, rule, [room_id](mtx::http::RequestErr &err) { + if (err) + nhlog::net()->error("failed to set pushrule for room {}: {} {}", + room_id, + static_cast(err->status_code), + err->matrix_error.error); + http::client()->delete_pushrules( + "global", "override", room_id, [room_id](mtx::http::RequestErr &) {}); + }); + } else { + // all messages + http::client()->delete_pushrules( + "global", "override", room_id, [room_id](mtx::http::RequestErr &) { + http::client()->delete_pushrules( + "global", "room", room_id, [room_id](mtx::http::RequestErr &) {}); + }); + } +} + +void +RoomSettings::changeAccessRules(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 = state::JoinRule::Public; + break; + default: + event.join_rule = state::JoinRule::Invite; + } + + return event; + }(index); + + updateAccessRules(roomid_.toStdString(), join_rule, guest_access); +} + +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 signal that stops loading spinner and reset error label + }); + }); } \ No newline at end of file diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h index 98e64b74..098e27ba 100644 --- a/src/ui/RoomSettings.h +++ b/src/ui/RoomSettings.h @@ -3,23 +3,52 @@ #include #include +#include + #include "CacheStructs.h" class RoomSettings : public QObject { Q_OBJECT Q_PROPERTY(QString roomName READ roomName CONSTANT) + Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged) + Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged) + Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT) + Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged) + Q_PROPERTY(bool respondsToKeyRequests READ respondsToKeyRequests NOTIFY keyRequestsChanged) public: RoomSettings(QString roomid, QObject *parent = nullptr); QString roomName() const; + int notifications(); + int accessJoinRules(); + bool respondsToKeyRequests(); + //! Whether the user has enough power level to send m.room.join_rules events. + bool canChangeJoinRules() const; + bool isEncryptionEnabled() const; + + Q_INVOKABLE void changeNotifications(int currentIndex); + Q_INVOKABLE void changeAccessRules(int index); + Q_INVOKABLE void changeKeyRequestsPreference(bool isOn); + Q_INVOKABLE void enableEncryption(); + +signals: + void notificationsChanged(); + void accessJoinRulesChanged(); + void keyRequestsChanged(); + void encryptionChanged(); private: void retrieveRoomInfo(); + void updateAccessRules(const std::string &room_id, + const mtx::events::state::JoinRules &, + const mtx::events::state::GuestAccess &); private: QString roomid_; bool usesEncryption_ = false; RoomInfo info_; + int notifications_ = 0; + int accessRules_ = 0; }; \ No newline at end of file -- cgit 1.5.1 From 473b14ed0f8053348000db370451cfff3ce3ac13 Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Thu, 11 Feb 2021 21:23:33 +0530 Subject: added roomversion, roomid etc --- resources/qml/RoomSettings.qml | 9 ++++----- src/ui/RoomSettings.cpp | 18 ++++++++++++++++++ src/ui/RoomSettings.h | 6 ++++++ 3 files changed, 28 insertions(+), 5 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index 4b03e08b..ee824ba0 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -17,7 +17,6 @@ ApplicationWindow { minimumHeight: 420 palette: colors color: colors.window - title: roomSettings.roomName modality: Qt.WindowModal flags: Qt.WindowStaysOnTopHint @@ -46,13 +45,13 @@ ApplicationWindow { Layout.alignment: Qt.AlignHCenter MatrixText { - text: "room name" + text: roomSettings.roomName font.pixelSize: 24 Layout.alignment: Qt.AlignHCenter } MatrixText { - text: "1 member" + text: "%1 member(s)".arg(roomSettings.memberCount) Layout.alignment: Qt.AlignHCenter } } @@ -185,7 +184,7 @@ ApplicationWindow { } MatrixText { - text: "asdajdhasjkdhaskjdhasjdks" + text: roomSettings.roomId font.pixelSize: 12 } } @@ -200,7 +199,7 @@ ApplicationWindow { } MatrixText { - text: "6" + text: roomSettings.roomVersion font.pixelSize: 12 } } diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index 785452d0..49e48e40 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -72,6 +72,24 @@ RoomSettings::roomName() const return QString(info_.name.c_str()); } +QString +RoomSettings::roomId() const +{ + return roomid_; +} + +QString +RoomSettings::roomVersion() const +{ + return QString::fromStdString(info_.version); +} + +int +RoomSettings::memberCount() const +{ + return info_.member_count; +} + void RoomSettings::retrieveRoomInfo() { diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h index 098e27ba..f5cc043c 100644 --- a/src/ui/RoomSettings.h +++ b/src/ui/RoomSettings.h @@ -11,6 +11,9 @@ class RoomSettings : public QObject { Q_OBJECT Q_PROPERTY(QString roomName READ roomName CONSTANT) + Q_PROPERTY(QString roomId READ roomId CONSTANT) + Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT) + Q_PROPERTY(int memberCount READ memberCount CONSTANT) Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged) Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged) Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT) @@ -21,6 +24,9 @@ public: RoomSettings(QString roomid, QObject *parent = nullptr); QString roomName() const; + QString roomId() const; + QString roomVersion() const; + int memberCount() const; int notifications(); int accessJoinRules(); bool respondsToKeyRequests(); -- cgit 1.5.1 From a7d7d18e92ec30977009e0947179dbc58ccb9e26 Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Thu, 11 Feb 2021 23:39:11 +0530 Subject: shifted room avatar changing --- resources/qml/RoomSettings.qml | 47 ++++++++++- src/dialogs/RoomSettingsOld.cpp | 14 ++-- src/dialogs/RoomSettingsOld.h | 2 +- src/ui/RoomSettings.cpp | 167 +++++++++++++++++++++++++++++++++++++--- src/ui/RoomSettings.h | 35 ++++++++- 5 files changed, 242 insertions(+), 23 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index ee824ba0..5d2baba1 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -33,12 +33,53 @@ ApplicationWindow { spacing: 10 Avatar { - url: "" + url: roomSettings.roomAvatarUrl.replace("mxc://", "image://MxcImage/") height: 130 width: 130 - displayName: "" - userid: "" Layout.alignment: Qt.AlignHCenter + onClicked: { + if(roomSettings.canChangeAvatar) { + roomSettings.updateAvatar(); + } + } + } + + BusyIndicator { + Layout.alignment: Qt.AlignHCenter + running: roomSettings.isLoading + visible: roomSettings.isLoading + } + + Text { + id: errorText + text: "Error Text" + color: "red" + visible: opacity > 0 + opacity: 0 + Layout.alignment: Qt.AlignHCenter + } + + SequentialAnimation { + id: hideErrorAnimation + running: false + PauseAnimation { + duration: 4000 + } + NumberAnimation { + target: errorText + property: 'opacity' + to: 0 + duration: 1000 + } + } + + Connections{ + target: roomSettings + onDisplayError: { + errorText.text = errorMessage + errorText.opacity = 1 + hideErrorAnimation.restart() + } } ColumnLayout { diff --git a/src/dialogs/RoomSettingsOld.cpp b/src/dialogs/RoomSettingsOld.cpp index 7eb34c20..bc34715e 100644 --- a/src/dialogs/RoomSettingsOld.cpp +++ b/src/dialogs/RoomSettingsOld.cpp @@ -143,10 +143,10 @@ EditModal::applyClicked() } using namespace mtx::events; - auto proxy = std::make_shared(); - connect(proxy.get(), &ThreadProxy::topicEventSent, this, &EditModal::topicEventSent); - connect(proxy.get(), &ThreadProxy::nameEventSent, this, &EditModal::nameEventSent); - connect(proxy.get(), &ThreadProxy::error, this, &EditModal::error); + auto proxy = std::make_shared(); + connect(proxy.get(), &ThreadProxya::topicEventSent, this, &EditModal::topicEventSent); + connect(proxy.get(), &ThreadProxya::nameEventSent, this, &EditModal::nameEventSent); + connect(proxy.get(), &ThreadProxya::error, this, &EditModal::error); if (newName != initialName_ && !newName.isEmpty()) { state::Name body; @@ -810,9 +810,9 @@ RoomSettingsOld::updateAvatar() // Events emitted from the http callbacks (different threads) will // be queued back into the UI thread through this proxy object. - auto proxy = std::make_shared(); - connect(proxy.get(), &ThreadProxy::error, this, &RoomSettingsOld::displayErrorMessage); - connect(proxy.get(), &ThreadProxy::avatarChanged, this, &RoomSettingsOld::setAvatar); + auto proxy = std::make_shared(); + connect(proxy.get(), &ThreadProxya::error, this, &RoomSettingsOld::displayErrorMessage); + connect(proxy.get(), &ThreadProxya::avatarChanged, this, &RoomSettingsOld::setAvatar); const auto bin = file.peek(file.size()); const auto payload = std::string(bin.data(), bin.size()); diff --git a/src/dialogs/RoomSettingsOld.h b/src/dialogs/RoomSettingsOld.h index e517676a..ad8dd5bd 100644 --- a/src/dialogs/RoomSettingsOld.h +++ b/src/dialogs/RoomSettingsOld.h @@ -40,7 +40,7 @@ protected: /// Convenience class which connects events emmited from threads /// outside of main with the UI code. -class ThreadProxy : public QObject +class ThreadProxya : public QObject { Q_OBJECT diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index 49e48e40..3ff1d5d5 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -1,5 +1,9 @@ #include "RoomSettings.h" +#include +#include +#include +#include #include #include @@ -84,6 +88,18 @@ RoomSettings::roomVersion() const return QString::fromStdString(info_.version); } +bool +RoomSettings::isLoading() const +{ + return isLoading_; +} + +QString +RoomSettings::roomAvatarUrl() +{ + return QString::fromStdString(info_.avatar_url); +} + int RoomSettings::memberCount() const { @@ -96,7 +112,6 @@ RoomSettings::retrieveRoomInfo() try { usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString()); info_ = cache::singleRoomInfo(roomid_.toStdString()); - // setAvatar(); } catch (const lmdb::error &) { nhlog::db()->warn("failed to retrieve room info from cache: {}", roomid_.toStdString()); @@ -143,9 +158,9 @@ RoomSettings::enableEncryption() room_id, err->matrix_error.error, status_code); - //emit enableEncryptionError( - // tr("Failed to enable encryption: %1") - // .arg(QString::fromStdString(err->matrix_error.error))); + emit displayError( + tr("Failed to enable encryption: %1") + .arg(QString::fromStdString(err->matrix_error.error))); usesEncryption_ = false; emit encryptionChanged(); return; @@ -172,6 +187,33 @@ RoomSettings::canChangeJoinRules() const return false; } +bool +RoomSettings::canChangeNameAndTopic() const +{ + try { + return cache::hasEnoughPowerLevel({EventType::RoomName, EventType::RoomTopic}, + roomid_.toStdString(), + utils::localUser().toStdString()); + } catch (const lmdb::error &e) { + nhlog::db()->warn("lmdb error: {}", e.what()); + } + + return false; +} + +bool +RoomSettings::canChangeAvatar() const +{ + try { + return cache::hasEnoughPowerLevel( + {EventType::RoomAvatar}, roomid_.toStdString(), utils::localUser().toStdString()); + } catch (const lmdb::error &e) { + nhlog::db()->warn("lmdb error: {}", e.what()); + } + + return false; +} + bool RoomSettings::isEncryptionEnabled() const { @@ -269,8 +311,8 @@ RoomSettings::updateAccessRules(const std::string &room_id, const mtx::events::state::JoinRules &join_rule, const mtx::events::state::GuestAccess &guest_access) { - // startLoadingSpinner(); - // resetErrorLabel(); + isLoading_ = true; + emit loadingChanged(); http::client()->send_state_event( room_id, @@ -281,8 +323,9 @@ RoomSettings::updateAccessRules(const std::string &room_id, 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)); - + emit displayError(QString::fromStdString(err->matrix_error.error)); + isLoading_ = false; + emit loadingChanged(); return; } @@ -294,13 +337,115 @@ RoomSettings::updateAccessRules(const std::string &room_id, 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)); + emit displayError( + QString::fromStdString(err->matrix_error.error)); + } + + isLoading_ = false; + emit loadingChanged(); + }); + }); +} + +void +RoomSettings::stopLoading() +{ + isLoading_ = false; + emit loadingChanged(); +} + +void +RoomSettings::avatarChanged() +{ + retrieveRoomInfo(); + emit avatarUrlChanged(); +} + +void +RoomSettings::updateAvatar() +{ + const QString picturesFolder = + QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); + const QString fileName = QFileDialog::getOpenFileName( + nullptr, tr("Select an avatar"), picturesFolder, tr("All Files (*)")); + + if (fileName.isEmpty()) + return; + QMimeDatabase db; + QMimeType mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchContent); + + const auto format = mime.name().split("/")[0]; + + QFile file{fileName, this}; + if (format != "image") { + emit displayError(tr("The selected file is not an image")); + return; + } + + if (!file.open(QIODevice::ReadOnly)) { + emit displayError(tr("Error while reading file: %1").arg(file.errorString())); + return; + } + + isLoading_ = true; + emit loadingChanged(); + + // Events emitted from the http callbacks (different threads) will + // be queued back into the UI thread through this proxy object. + auto proxy = std::make_shared(); + connect(proxy.get(), &ThreadProxy::error, this, &RoomSettings::displayError); + connect(proxy.get(), &ThreadProxy::avatarChanged, this, &RoomSettings::avatarChanged); + connect(proxy.get(), &ThreadProxy::stopLoading, this, &RoomSettings::stopLoading); + + const auto bin = file.peek(file.size()); + const auto payload = std::string(bin.data(), bin.size()); + const auto dimensions = QImageReader(&file).size(); + + // First we need to create a new mxc URI + // (i.e upload media to the Matrix content repository) for the new avatar. + http::client()->upload( + payload, + mime.name().toStdString(), + QFileInfo(fileName).fileName().toStdString(), + [proxy = std::move(proxy), + dimensions, + payload, + mimetype = mime.name().toStdString(), + size = payload.size(), + room_id = roomid_.toStdString(), + content = std::move(bin)](const mtx::responses::ContentURI &res, + mtx::http::RequestErr err) { + if (err) { + emit proxy->stopLoading(); + emit proxy->error( + tr("Failed to upload image: %s") + .arg(QString::fromStdString(err->matrix_error.error))); + return; + } + + using namespace mtx::events; + state::Avatar avatar_event; + avatar_event.image_info.w = dimensions.width(); + avatar_event.image_info.h = dimensions.height(); + avatar_event.image_info.mimetype = mimetype; + avatar_event.image_info.size = size; + avatar_event.url = res.content_uri; + + http::client()->send_state_event( + room_id, + avatar_event, + [content = std::move(content), proxy = std::move(proxy)]( + const mtx::responses::EventId &, mtx::http::RequestErr err) { + if (err) { + emit proxy->error( + tr("Failed to upload image: %s") + .arg(QString::fromStdString(err->matrix_error.error))); return; } - // emit signal that stops loading spinner and reset error label + emit proxy->stopLoading(); + emit proxy->avatarChanged(); }); }); } \ No newline at end of file diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h index f5cc043c..09295a58 100644 --- a/src/ui/RoomSettings.h +++ b/src/ui/RoomSettings.h @@ -7,16 +7,34 @@ #include "CacheStructs.h" +/// Convenience class which connects events emmited from threads +/// outside of main with the UI code. +class ThreadProxy : public QObject +{ + Q_OBJECT + +signals: + void error(const QString &msg); + void avatarChanged(); + void nameEventSent(const QString &); + void topicEventSent(); + void stopLoading(); +}; + class RoomSettings : public QObject { - Q_OBJECT + Q_OBJECT Q_PROPERTY(QString roomName READ roomName CONSTANT) Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT) + Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged) Q_PROPERTY(int memberCount READ memberCount CONSTANT) Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged) Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged) + Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged) Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT) + Q_PROPERTY(bool canChangeNameAndTopic READ canChangeNameAndTopic CONSTANT) + Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT) Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged) Q_PROPERTY(bool respondsToKeyRequests READ respondsToKeyRequests NOTIFY keyRequestsChanged) @@ -26,24 +44,38 @@ public: QString roomName() const; QString roomId() const; QString roomVersion() const; + QString roomAvatarUrl(); int memberCount() const; int notifications(); int accessJoinRules(); bool respondsToKeyRequests(); + bool isLoading() const; //! Whether the user has enough power level to send m.room.join_rules events. bool canChangeJoinRules() const; + //! Whether the user has enough power level to send m.room.name & m.room.topic events. + bool canChangeNameAndTopic() const; + //! Whether the user has enough power level to send m.room.avatar event. + bool canChangeAvatar() const; bool isEncryptionEnabled() const; Q_INVOKABLE void changeNotifications(int currentIndex); Q_INVOKABLE void changeAccessRules(int index); Q_INVOKABLE void changeKeyRequestsPreference(bool isOn); Q_INVOKABLE void enableEncryption(); + Q_INVOKABLE void updateAvatar(); signals: void notificationsChanged(); void accessJoinRulesChanged(); void keyRequestsChanged(); void encryptionChanged(); + void avatarUrlChanged(); + void loadingChanged(); + void displayError(const QString &errorMessage); + +public slots: + void avatarChanged(); + void stopLoading(); private: void retrieveRoomInfo(); @@ -54,6 +86,7 @@ private: private: QString roomid_; bool usesEncryption_ = false; + bool isLoading_ = false; RoomInfo info_; int notifications_ = 0; int accessRules_ = 0; -- cgit 1.5.1 From f044e2d2a11150d026d5a523b518027154602d3a Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Thu, 11 Feb 2021 23:50:45 +0530 Subject: fix avatar update on timeline sync --- resources/qml/TimelineView.qml | 2 +- src/timeline/TimelineModel.cpp | 8 ++++++++ src/timeline/TimelineModel.h | 3 +++ src/timeline/TimelineViewManager.cpp | 4 +--- src/timeline/TimelineViewManager.h | 2 -- src/ui/RoomSettings.cpp | 2 -- src/ui/RoomSettings.h | 1 - 7 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 0c32effd..7a33f25f 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -175,7 +175,7 @@ Page { } Connections { - target: TimelineManager + target: TimelineManager.timeline onOpenRoomSettingsDialog: { var roomSettings = roomSettingsComponent.createObject(timelineRoot, { "roomSettings": settings diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 968ec3c7..29808fdd 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -807,6 +807,14 @@ TimelineModel::openUserProfile(QString userid, bool global) emit openProfile(userProfile); } +void +TimelineModel::openRoomSettings(QString roomid) +{ + RoomSettings *settings = new RoomSettings(roomid, this); + connect(this, &TimelineModel::roomAvatarUrlChanged, settings, &RoomSettings::avatarChanged); + openRoomSettingsDialog(settings); +} + void TimelineModel::replyAction(QString id) { diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 51b8049e..1a12a8c3 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -12,6 +12,7 @@ #include "EventStore.h" #include "InputBar.h" #include "ui/UserProfile.h" +#include "ui/RoomSettings.h" namespace mtx::http { using RequestErr = const std::optional &; @@ -213,6 +214,7 @@ public: Q_INVOKABLE void viewRawMessage(QString id) const; Q_INVOKABLE void viewDecryptedRawMessage(QString id) const; Q_INVOKABLE void openUserProfile(QString userid, bool global = false); + Q_INVOKABLE void openRoomSettings(QString roomid); Q_INVOKABLE void replyAction(QString id); Q_INVOKABLE void readReceiptsAction(QString id) const; Q_INVOKABLE void redactEvent(QString id); @@ -296,6 +298,7 @@ signals: void newCallEvent(const mtx::events::collections::TimelineEvents &event); void openProfile(UserProfile *profile); + void openRoomSettingsDialog(RoomSettings *settings); void newMessageToSend(mtx::events::collections::TimelineEvents event); void addPendingMessageToStore(mtx::events::collections::TimelineEvents event); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 4edc3369..99a2e388 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -399,9 +399,7 @@ void TimelineViewManager::openRoomSettings() { MainWindow::instance()->openRoomSettings(timeline_->roomId()); - - RoomSettings *settings = new RoomSettings(timeline_->roomId(), this); - emit openRoomSettingsDialog(settings); + timeline_->openRoomSettings(timeline_->roomId()); } void diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 10708033..a2d37342 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -19,7 +19,6 @@ #include "emoji/EmojiModel.h" #include "emoji/Provider.h" #include "dialogs/RoomSettingsOld.h" -#include "ui/RoomSettings.h" class MxcImageProvider; class BlurhashProvider; @@ -89,7 +88,6 @@ signals: void showRoomList(); void narrowViewChanged(); void focusChanged(); - void openRoomSettingsDialog(RoomSettings *settings); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids); diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index 3ff1d5d5..adf8d8a7 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -395,7 +395,6 @@ RoomSettings::updateAvatar() // be queued back into the UI thread through this proxy object. auto proxy = std::make_shared(); connect(proxy.get(), &ThreadProxy::error, this, &RoomSettings::displayError); - connect(proxy.get(), &ThreadProxy::avatarChanged, this, &RoomSettings::avatarChanged); connect(proxy.get(), &ThreadProxy::stopLoading, this, &RoomSettings::stopLoading); const auto bin = file.peek(file.size()); @@ -445,7 +444,6 @@ RoomSettings::updateAvatar() } emit proxy->stopLoading(); - emit proxy->avatarChanged(); }); }); } \ No newline at end of file diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h index 09295a58..d31b38f2 100644 --- a/src/ui/RoomSettings.h +++ b/src/ui/RoomSettings.h @@ -15,7 +15,6 @@ class ThreadProxy : public QObject signals: void error(const QString &msg); - void avatarChanged(); void nameEventSent(const QString &); void topicEventSent(); void stopLoading(); -- cgit 1.5.1 From 35aa0126ac80d99aaf7f61d6eeba6c7d9eca96bc Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Fri, 12 Feb 2021 12:48:12 +0530 Subject: added changing of name through edit modal, removed old roomsettings --- CMakeLists.txt | 2 - resources/qml/RoomSettings.qml | 9 +- resources/qml/TopBar.qml | 4 +- resources/qml/UserProfile.qml | 1 - src/MainWindow.cpp | 9 - src/MainWindow.h | 1 - src/dialogs/RoomSettingsOld.cpp | 865 ----------------------------------- src/dialogs/RoomSettingsOld.h | 150 ------ src/timeline/TimelineModel.cpp | 4 +- src/timeline/TimelineModel.h | 2 +- src/timeline/TimelineViewManager.cpp | 6 - src/timeline/TimelineViewManager.h | 2 - src/ui/RoomSettings.cpp | 164 +++++++ src/ui/RoomSettings.h | 41 +- 14 files changed, 214 insertions(+), 1046 deletions(-) delete mode 100644 src/dialogs/RoomSettingsOld.cpp delete mode 100644 src/dialogs/RoomSettingsOld.h (limited to 'src/ui/RoomSettings.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 505a59f1..3e41ebc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,7 +257,6 @@ set(SRC_FILES src/dialogs/PreviewUploadOverlay.cpp src/dialogs/ReCaptcha.cpp src/dialogs/ReadReceipts.cpp - src/dialogs/RoomSettingsOld.cpp # Emoji src/emoji/EmojiModel.cpp @@ -472,7 +471,6 @@ qt5_wrap_cpp(MOC_HEADERS src/dialogs/RawMessage.h src/dialogs/ReCaptcha.h src/dialogs/ReadReceipts.h - src/dialogs/RoomSettingsOld.h # Emoji src/emoji/EmojiModel.h diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index 5d2baba1..eabe68f5 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -12,13 +12,11 @@ ApplicationWindow { x: MainWindow.x + (MainWindow.width / 2) - (width / 2) y: MainWindow.y + (MainWindow.height / 2) - (height / 2) - height: 600 - width: 420 - minimumHeight: 420 + minimumWidth: 340 + minimumHeight: 600 palette: colors color: colors.window modality: Qt.WindowModal - flags: Qt.WindowStaysOnTopHint Shortcut { sequence: StandardKey.Cancel @@ -100,6 +98,8 @@ ApplicationWindow { ImageButton { Layout.alignment: Qt.AlignHCenter image: ":/icons/icons/ui/edit.png" + visible: roomSettings.canChangeNameAndTopic + onClicked: roomSettings.openEditModal() } MatrixText { @@ -248,6 +248,7 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "Ok" + onClicked: close() } } } \ No newline at end of file diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index 273ed8ab..c64eddd4 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -68,7 +68,7 @@ Rectangle { MouseArea { anchors.fill: parent - onClicked: TimelineManager.openRoomSettings() + onClicked: TimelineManager.timeline.openRoomSettings() } } @@ -114,7 +114,7 @@ Rectangle { MenuItem { text: qsTr("Settings") - onTriggered: TimelineManager.openRoomSettings() + onTriggered: TimelineManager.timeline.openRoomSettings() } } diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml index 37ae6de8..e8d41073 100644 --- a/resources/qml/UserProfile.qml +++ b/resources/qml/UserProfile.qml @@ -113,7 +113,6 @@ ApplicationWindow { } } } - } MatrixText { diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index b1635c94..ae532ef3 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -51,7 +51,6 @@ #include "dialogs/Logout.h" #include "dialogs/MemberList.h" #include "dialogs/ReadReceipts.h" -#include "dialogs/RoomSettingsOld.h" MainWindow *MainWindow::instance_ = nullptr; @@ -363,14 +362,6 @@ MainWindow::hasActiveUser() settings.contains(prefix + "auth/user_id"); } -void -MainWindow::openRoomSettings(const QString &room_id) -{ - auto dialog = new dialogs::RoomSettingsOld(room_id, this); - - showDialog(dialog); -} - void MainWindow::openMemberListDialog(const QString &room_id) { diff --git a/src/MainWindow.h b/src/MainWindow.h index b3983d72..5c2df8b6 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -78,7 +78,6 @@ public: std::function callback); void openJoinRoomDialog(std::function callback); void openLogoutDialog(); - void openRoomSettings(const QString &room_id); void openMemberListDialog(const QString &room_id); void openReadReceiptsDialog(const QString &event_id); diff --git a/src/dialogs/RoomSettingsOld.cpp b/src/dialogs/RoomSettingsOld.cpp deleted file mode 100644 index bc34715e..00000000 --- a/src/dialogs/RoomSettingsOld.cpp +++ /dev/null @@ -1,865 +0,0 @@ -#include "dialogs/RoomSettingsOld.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Cache.h" -#include "ChatPage.h" -#include "Config.h" -#include "Logging.h" -#include "MatrixClient.h" -#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/ToggleButton.h" - -using namespace dialogs; -using namespace mtx::events; - -constexpr int BUTTON_SIZE = 36; -constexpr int BUTTON_RADIUS = BUTTON_SIZE / 2; -constexpr int WIDGET_MARGIN = 20; -constexpr int TOP_WIDGET_MARGIN = 2 * WIDGET_MARGIN; -constexpr int WIDGET_SPACING = 15; -constexpr int TEXT_SPACING = 4; -constexpr int BUTTON_SPACING = 2 * TEXT_SPACING; - -bool -ClickableFilter::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == QEvent::MouseButtonRelease) { - emit clicked(); - return true; - } - - return QObject::eventFilter(obj, event); -} - -EditModal::EditModal(const QString &roomId, QWidget *parent) - : QWidget(parent) - , roomId_{roomId} -{ - setAutoFillBackground(true); - setAttribute(Qt::WA_DeleteOnClose, true); - setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); - setWindowModality(Qt::WindowModal); - - QFont largeFont; - largeFont.setPointSizeF(largeFont.pointSizeF() * 1.4); - setMinimumWidth(conf::window::minModalWidth); - setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - - auto layout = new QVBoxLayout(this); - - applyBtn_ = new QPushButton(tr("Apply"), this); - cancelBtn_ = new QPushButton(tr("Cancel"), this); - cancelBtn_->setDefault(true); - - auto btnLayout = new QHBoxLayout; - btnLayout->addStretch(1); - btnLayout->setSpacing(15); - btnLayout->addWidget(cancelBtn_); - btnLayout->addWidget(applyBtn_); - - nameInput_ = new TextField(this); - nameInput_->setLabel(tr("Name").toUpper()); - topicInput_ = new TextField(this); - topicInput_->setLabel(tr("Topic").toUpper()); - - errorField_ = new QLabel(this); - errorField_->setWordWrap(true); - errorField_->hide(); - - layout->addWidget(nameInput_); - layout->addWidget(topicInput_); - layout->addLayout(btnLayout, 1); - - auto labelLayout = new QHBoxLayout; - labelLayout->setAlignment(Qt::AlignHCenter); - labelLayout->addWidget(errorField_); - layout->addLayout(labelLayout); - - connect(applyBtn_, &QPushButton::clicked, this, &EditModal::applyClicked); - connect(cancelBtn_, &QPushButton::clicked, this, &EditModal::close); - - auto window = QApplication::activeWindow(); - auto center = window->frameGeometry().center(); - move(center.x() - (width() * 0.5), center.y() - (height() * 0.5)); -} - -void -EditModal::topicEventSent() -{ - errorField_->hide(); - close(); -} - -void -EditModal::nameEventSent(const QString &name) -{ - errorField_->hide(); - emit nameChanged(name); - close(); -} - -void -EditModal::error(const QString &msg) -{ - errorField_->setText(msg); - errorField_->show(); -} - -void -EditModal::applyClicked() -{ - // Check if the values are changed from the originals. - auto newName = nameInput_->text().trimmed(); - auto newTopic = topicInput_->text().trimmed(); - - errorField_->hide(); - - if (newName == initialName_ && newTopic == initialTopic_) { - close(); - return; - } - - using namespace mtx::events; - auto proxy = std::make_shared(); - connect(proxy.get(), &ThreadProxya::topicEventSent, this, &EditModal::topicEventSent); - connect(proxy.get(), &ThreadProxya::nameEventSent, this, &EditModal::nameEventSent); - connect(proxy.get(), &ThreadProxya::error, this, &EditModal::error); - - if (newName != initialName_ && !newName.isEmpty()) { - state::Name body; - body.name = newName.toStdString(); - - http::client()->send_state_event( - roomId_.toStdString(), - body, - [proxy, newName](const mtx::responses::EventId &, mtx::http::RequestErr err) { - if (err) { - emit proxy->error( - QString::fromStdString(err->matrix_error.error)); - return; - } - - emit proxy->nameEventSent(newName); - }); - } - - if (newTopic != initialTopic_ && !newTopic.isEmpty()) { - state::Topic body; - body.topic = newTopic.toStdString(); - - http::client()->send_state_event( - roomId_.toStdString(), - body, - [proxy](const mtx::responses::EventId &, mtx::http::RequestErr err) { - if (err) { - emit proxy->error( - QString::fromStdString(err->matrix_error.error)); - return; - } - - emit proxy->topicEventSent(); - }); - } -} - -void -EditModal::setFields(const QString &roomName, const QString &roomTopic) -{ - initialName_ = roomName; - initialTopic_ = roomTopic; - - nameInput_->setText(roomName); - topicInput_->setText(roomTopic); -} - -RoomSettingsOld::RoomSettingsOld(const QString &room_id, QWidget *parent) - : QFrame(parent) - , room_id_{std::move(room_id)} -{ - retrieveRoomInfo(); - - setAutoFillBackground(true); - setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); - setWindowModality(Qt::WindowModal); - setAttribute(Qt::WA_DeleteOnClose, true); - - QFont largeFont; - largeFont.setPointSizeF(largeFont.pointSizeF() * 1.5); - - setMinimumWidth(conf::window::minModalWidth); - setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); - - auto layout = new QVBoxLayout(this); - layout->setSpacing(WIDGET_SPACING); - layout->setContentsMargins(WIDGET_MARGIN, TOP_WIDGET_MARGIN, WIDGET_MARGIN, WIDGET_MARGIN); - - QFont font; - font.setWeight(QFont::Medium); - auto settingsLabel = new QLabel(tr("Settings").toUpper(), this); - settingsLabel->setFont(font); - - auto infoLabel = new QLabel(tr("Info").toUpper(), this); - infoLabel->setFont(font); - - QFont monospaceFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); - - auto roomIdLabel = new QLabel(room_id, this); - roomIdLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - roomIdLabel->setFont(monospaceFont); - - auto roomIdLayout = new QHBoxLayout; - roomIdLayout->setMargin(0); - roomIdLayout->addWidget(new QLabel(tr("Internal ID"), this), - Qt::AlignBottom | Qt::AlignLeft); - roomIdLayout->addWidget(roomIdLabel, 0, Qt::AlignBottom | Qt::AlignRight); - - auto roomVersionLabel = new QLabel(QString::fromStdString(info_.version), this); - roomVersionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - roomVersionLabel->setFont(monospaceFont); - - auto roomVersionLayout = new QHBoxLayout; - roomVersionLayout->setMargin(0); - roomVersionLayout->addWidget(new QLabel(tr("Room Version"), this), - Qt::AlignBottom | Qt::AlignLeft); - roomVersionLayout->addWidget(roomVersionLabel, 0, Qt::AlignBottom | Qt::AlignRight); - - auto notifLabel = new QLabel(tr("Notifications"), this); - notifCombo = new QComboBox(this); - notifCombo->addItem(tr( - "Muted")); //{"conditions":[{"kind":"event_match","key":"room_id","pattern":"!jxlRxnrZCsjpjDubDX:matrix.org"}],"actions":["dont_notify"]} - notifCombo->addItem(tr("Mentions only")); // {"actions":["dont_notify"]} - notifCombo->addItem(tr("All messages")); // delete rule - - connect(this, &RoomSettingsOld::notifChanged, notifCombo, &QComboBox::setCurrentIndex); - http::client()->get_pushrules( - "global", - "override", - room_id_.toStdString(), - [this](const mtx::pushrules::PushRule &rule, mtx::http::RequestErr &err) { - if (err) { - if (err->status_code == boost::beast::http::status::not_found) - http::client()->get_pushrules( - "global", - "room", - room_id_.toStdString(), - [this](const mtx::pushrules::PushRule &rule, - mtx::http::RequestErr &err) { - if (err) { - emit notifChanged(2); // all messages - return; - } - - if (rule.enabled) - emit notifChanged(1); // mentions only - }); - return; - } - - if (rule.enabled) - emit notifChanged(0); // muted - else - emit notifChanged(2); // all messages - }); - - connect(notifCombo, QOverload::of(&QComboBox::activated), [this](int index) { - std::string room_id = room_id_.toStdString(); - if (index == 0) { - // mute room - // delete old rule first, then add new rule - mtx::pushrules::PushRule rule; - rule.actions = {mtx::pushrules::actions::dont_notify{}}; - mtx::pushrules::PushCondition condition; - condition.kind = "event_match"; - condition.key = "room_id"; - condition.pattern = room_id; - rule.conditions = {condition}; - - http::client()->put_pushrules( - "global", - "override", - room_id, - rule, - [room_id](mtx::http::RequestErr &err) { - if (err) - nhlog::net()->error( - "failed to set pushrule for room {}: {} {}", - room_id, - static_cast(err->status_code), - err->matrix_error.error); - http::client()->delete_pushrules( - "global", "room", room_id, [room_id](mtx::http::RequestErr &) { - }); - }); - } else if (index == 1) { - // mentions only - // delete old rule first, then add new rule - mtx::pushrules::PushRule rule; - rule.actions = {mtx::pushrules::actions::dont_notify{}}; - http::client()->put_pushrules( - "global", "room", room_id, rule, [room_id](mtx::http::RequestErr &err) { - if (err) - nhlog::net()->error( - "failed to set pushrule for room {}: {} {}", - room_id, - static_cast(err->status_code), - err->matrix_error.error); - http::client()->delete_pushrules( - "global", - "override", - room_id, - [room_id](mtx::http::RequestErr &) {}); - }); - } else { - // all messages - http::client()->delete_pushrules( - "global", "override", room_id, [room_id](mtx::http::RequestErr &) { - http::client()->delete_pushrules( - "global", "room", room_id, [room_id](mtx::http::RequestErr &) { - }); - }); - } - }); - - auto notifOptionLayout_ = new QHBoxLayout; - notifOptionLayout_->setMargin(0); - notifOptionLayout_->addWidget(notifLabel, Qt::AlignBottom | Qt::AlignLeft); - notifOptionLayout_->addWidget(notifCombo, 0, Qt::AlignBottom | Qt::AlignRight); - - auto accessLabel = new QLabel(tr("Room access"), this); - accessCombo = new QComboBox(this); - accessCombo->addItem(tr("Anyone and guests")); - accessCombo->addItem(tr("Anyone")); - accessCombo->addItem(tr("Invited users")); - 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 = state::JoinRule::Public; - break; - default: - event.join_rule = state::JoinRule::Invite; - } - - return event; - }(index); - - updateAccessRules(room_id_.toStdString(), join_rule, guest_access); - }); - - if (info_.join_rule == state::JoinRule::Public) { - if (info_.guest_access) { - accessCombo->setCurrentIndex(0); - } else { - accessCombo->setCurrentIndex(1); - } - } else { - accessCombo->setCurrentIndex(2); - } - - auto accessOptionLayout = new QHBoxLayout(); - accessOptionLayout->setMargin(0); - accessOptionLayout->addWidget(accessLabel, Qt::AlignBottom | Qt::AlignLeft); - accessOptionLayout->addWidget(accessCombo, 0, Qt::AlignBottom | Qt::AlignRight); - - auto encryptionLabel = new QLabel(tr("Encryption"), this); - encryptionToggle_ = new Toggle(this); - - auto encryptionOptionLayout = new QHBoxLayout; - encryptionOptionLayout->setMargin(0); - encryptionOptionLayout->addWidget(encryptionLabel, Qt::AlignBottom | Qt::AlignLeft); - encryptionOptionLayout->addWidget(encryptionToggle_, 0, Qt::AlignBottom | Qt::AlignRight); - - auto keyRequestsLabel = new QLabel(tr("Respond to key requests"), this); - keyRequestsLabel->setToolTipDuration(6000); - keyRequestsLabel->setToolTip( - tr("Whether or not the client should respond automatically with the session keys\n" - " upon request. Use with caution, this is a temporary measure to test the\n" - " E2E implementation until device verification is completed.")); - keyRequestsToggle_ = new Toggle(this); - connect(keyRequestsToggle_, &Toggle::toggled, this, [this](bool isOn) { - utils::setKeyRequestsPreference(room_id_, isOn); - }); - - auto keyRequestsLayout = new QHBoxLayout; - keyRequestsLayout->setMargin(0); - keyRequestsLayout->setSpacing(0); - keyRequestsLayout->addWidget(keyRequestsLabel, Qt::AlignBottom | Qt::AlignLeft); - keyRequestsLayout->addWidget(keyRequestsToggle_, 0, Qt::AlignBottom | Qt::AlignRight); - - connect(encryptionToggle_, &Toggle::toggled, this, [this, keyRequestsLabel](bool isOn) { - if (!isOn || usesEncryption_) - return; - - QMessageBox msgBox; - msgBox.setIcon(QMessageBox::Question); - msgBox.setWindowTitle(tr("End-to-End Encryption")); - msgBox.setText(tr( - "Encryption is currently experimental and things might break unexpectedly.
" - "Please take note that it can't be disabled afterwards.")); - msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - msgBox.setDefaultButton(QMessageBox::Save); - int ret = msgBox.exec(); - - switch (ret) { - case QMessageBox::Ok: { - encryptionToggle_->setState(true); - encryptionToggle_->setEnabled(false); - enableEncryption(); - keyRequestsToggle_->show(); - keyRequestsLabel->show(); - break; - } - default: { - break; - } - } - }); - - // Disable encryption button. - if (usesEncryption_) { - encryptionToggle_->setState(true); - encryptionToggle_->setEnabled(false); - - keyRequestsToggle_->setState(utils::respondsToKeyRequests(room_id_)); - } else { - encryptionToggle_->setState(false); - - keyRequestsLabel->hide(); - keyRequestsToggle_->hide(); - } - - // Hide encryption option for public rooms. - if (!usesEncryption_ && (info_.join_rule == state::JoinRule::Public)) { - encryptionToggle_->hide(); - encryptionLabel->hide(); - - keyRequestsLabel->hide(); - keyRequestsToggle_->hide(); - } - - avatar_ = new Avatar(this, 128); - avatar_->setLetter(utils::firstChar(QString::fromStdString(info_.name))); - if (!info_.avatar_url.empty()) - avatar_->setImage(QString::fromStdString(info_.avatar_url)); - - if (canChangeAvatar(room_id_.toStdString(), utils::localUser().toStdString())) { - auto filter = new ClickableFilter(this); - avatar_->installEventFilter(filter); - avatar_->setCursor(Qt::PointingHandCursor); - connect(filter, &ClickableFilter::clicked, this, &RoomSettingsOld::updateAvatar); - } - - roomNameLabel_ = new QLabel(QString::fromStdString(info_.name), this); - roomNameLabel_->setFont(largeFont); - - auto membersLabel = new QLabel(tr("%n member(s)", "", (int)info_.member_count), this); - - auto textLayout = new QVBoxLayout; - textLayout->addWidget(roomNameLabel_); - textLayout->addWidget(membersLabel); - textLayout->setAlignment(roomNameLabel_, Qt::AlignCenter | Qt::AlignTop); - textLayout->setAlignment(membersLabel, Qt::AlignCenter | Qt::AlignTop); - textLayout->setSpacing(TEXT_SPACING); - textLayout->setMargin(0); - - 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); - - auto okBtn = new QPushButton("OK", this); - - auto buttonLayout = new QHBoxLayout(); - buttonLayout->setSpacing(15); - buttonLayout->addStretch(1); - buttonLayout->addWidget(okBtn); - - layout->addWidget(avatar_, Qt::AlignCenter | Qt::AlignTop); - layout->addLayout(textLayout); - layout->addLayout(btnLayout_); - layout->addWidget(settingsLabel, Qt::AlignLeft); - layout->addLayout(notifOptionLayout_); - layout->addLayout(accessOptionLayout); - layout->addLayout(encryptionOptionLayout); - layout->addLayout(keyRequestsLayout); - layout->addWidget(infoLabel, Qt::AlignLeft); - layout->addLayout(roomIdLayout); - layout->addLayout(roomVersionLayout); - layout->addWidget(errorLabel_); - layout->addLayout(buttonLayout); - layout->addLayout(spinnerLayout); - layout->addStretch(1); - - connect(this, &RoomSettingsOld::enableEncryptionError, this, [this](const QString &msg) { - encryptionToggle_->setState(false); - keyRequestsToggle_->setState(false); - keyRequestsToggle_->setEnabled(false); - keyRequestsToggle_->hide(); - - emit ChatPage::instance()->showNotification(msg); - }); - - connect(this, &RoomSettingsOld::showErrorMessage, this, [this](const QString &msg) { - if (!errorLabel_) - return; - - stopLoadingSpinner(); - - errorLabel_->show(); - errorLabel_->setText(msg); - }); - - connect(this, &RoomSettingsOld::accessRulesUpdated, this, [this]() { - stopLoadingSpinner(); - resetErrorLabel(); - }); - - auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this); - connect(closeShortcut, &QShortcut::activated, this, &RoomSettingsOld::close); - connect(okBtn, &QPushButton::clicked, this, &RoomSettingsOld::close); -} - -void -RoomSettingsOld::setupEditButton() -{ - btnLayout_ = new QHBoxLayout; - btnLayout_->setSpacing(BUTTON_SPACING); - btnLayout_->setMargin(0); - - if (!canChangeNameAndTopic(room_id_.toStdString(), utils::localUser().toStdString())) - return; - - QIcon editIcon; - editIcon.addFile(":/icons/icons/ui/edit.png"); - editFieldsBtn_ = new FlatButton(this); - editFieldsBtn_->setFixedSize(BUTTON_SIZE, BUTTON_SIZE); - editFieldsBtn_->setCornerRadius(BUTTON_RADIUS); - editFieldsBtn_->setIcon(editIcon); - editFieldsBtn_->setIcon(editIcon); - editFieldsBtn_->setIconSize(QSize(BUTTON_RADIUS, BUTTON_RADIUS)); - - connect(editFieldsBtn_, &QPushButton::clicked, this, [this]() { - retrieveRoomInfo(); - - auto modal = new EditModal(room_id_, this); - modal->setFields(QString::fromStdString(info_.name), - QString::fromStdString(info_.topic)); - modal->raise(); - modal->show(); - connect(modal, &EditModal::nameChanged, this, [this](const QString &newName) { - if (roomNameLabel_) - roomNameLabel_->setText(newName); - }); - }); - - btnLayout_->addStretch(1); - btnLayout_->addWidget(editFieldsBtn_); - btnLayout_->addStretch(1); -} - -void -RoomSettingsOld::retrieveRoomInfo() -{ - try { - usesEncryption_ = cache::isRoomEncrypted(room_id_.toStdString()); - info_ = cache::singleRoomInfo(room_id_.toStdString()); - setAvatar(); - } catch (const lmdb::error &) { - nhlog::db()->warn("failed to retrieve room info from cache: {}", - room_id_.toStdString()); - } -} - -void -RoomSettingsOld::enableEncryption() -{ - const auto room_id = room_id_.toStdString(); - http::client()->enable_encryption( - room_id, [room_id, this](const mtx::responses::EventId &, mtx::http::RequestErr err) { - if (err) { - int status_code = static_cast(err->status_code); - nhlog::net()->warn("failed to enable encryption in room ({}): {} {}", - room_id, - err->matrix_error.error, - status_code); - emit enableEncryptionError( - tr("Failed to enable encryption: %1") - .arg(QString::fromStdString(err->matrix_error.error))); - return; - } - - nhlog::net()->info("enabled encryption on room ({})", room_id); - }); -} - -void -RoomSettingsOld::showEvent(QShowEvent *event) -{ - resetErrorLabel(); - stopLoadingSpinner(); - - QWidget::showEvent(event); -} - -bool -RoomSettingsOld::canChangeJoinRules(const std::string &room_id, const std::string &user_id) const -{ - try { - return cache::hasEnoughPowerLevel({EventType::RoomJoinRules}, room_id, user_id); - } catch (const lmdb::error &e) { - nhlog::db()->warn("lmdb error: {}", e.what()); - } - - return false; -} - -bool -RoomSettingsOld::canChangeNameAndTopic(const std::string &room_id, const std::string &user_id) const -{ - try { - return cache::hasEnoughPowerLevel( - {EventType::RoomName, EventType::RoomTopic}, room_id, user_id); - } catch (const lmdb::error &e) { - nhlog::db()->warn("lmdb error: {}", e.what()); - } - - return false; -} - -bool -RoomSettingsOld::canChangeAvatar(const std::string &room_id, const std::string &user_id) const -{ - try { - return cache::hasEnoughPowerLevel({EventType::RoomAvatar}, room_id, user_id); - } catch (const lmdb::error &e) { - nhlog::db()->warn("lmdb error: {}", e.what()); - } - - return false; -} - -void -RoomSettingsOld::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 -RoomSettingsOld::stopLoadingSpinner() -{ - if (spinner_) { - spinner_->stop(); - spinner_->hide(); - } -} - -void -RoomSettingsOld::startLoadingSpinner() -{ - if (spinner_) { - spinner_->start(); - spinner_->show(); - } -} - -void -RoomSettingsOld::displayErrorMessage(const QString &msg) -{ - stopLoadingSpinner(); - - errorLabel_->show(); - errorLabel_->setText(msg); -} - -void -RoomSettingsOld::setAvatar() -{ - stopLoadingSpinner(); - - if (avatar_) - avatar_->setImage(QString::fromStdString(info_.avatar_url)); -} - -void -RoomSettingsOld::resetErrorLabel() -{ - if (errorLabel_) { - errorLabel_->hide(); - errorLabel_->clear(); - } -} - -void -RoomSettingsOld::updateAvatar() -{ - const QString picturesFolder = - QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); - const QString fileName = QFileDialog::getOpenFileName( - this, tr("Select an avatar"), picturesFolder, tr("All Files (*)")); - - if (fileName.isEmpty()) - return; - - QMimeDatabase db; - QMimeType mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchContent); - - const auto format = mime.name().split("/")[0]; - - QFile file{fileName, this}; - if (format != "image") { - displayErrorMessage(tr("The selected file is not an image")); - return; - } - - if (!file.open(QIODevice::ReadOnly)) { - displayErrorMessage(tr("Error while reading file: %1").arg(file.errorString())); - return; - } - - if (spinner_) { - startLoadingSpinner(); - resetErrorLabel(); - } - - // Events emitted from the http callbacks (different threads) will - // be queued back into the UI thread through this proxy object. - auto proxy = std::make_shared(); - connect(proxy.get(), &ThreadProxya::error, this, &RoomSettingsOld::displayErrorMessage); - connect(proxy.get(), &ThreadProxya::avatarChanged, this, &RoomSettingsOld::setAvatar); - - const auto bin = file.peek(file.size()); - const auto payload = std::string(bin.data(), bin.size()); - const auto dimensions = QImageReader(&file).size(); - - // First we need to create a new mxc URI - // (i.e upload media to the Matrix content repository) for the new avatar. - http::client()->upload( - payload, - mime.name().toStdString(), - QFileInfo(fileName).fileName().toStdString(), - [proxy = std::move(proxy), - dimensions, - payload, - mimetype = mime.name().toStdString(), - size = payload.size(), - room_id = room_id_.toStdString(), - content = std::move(bin)](const mtx::responses::ContentURI &res, - mtx::http::RequestErr err) { - if (err) { - emit proxy->error( - tr("Failed to upload image: %s") - .arg(QString::fromStdString(err->matrix_error.error))); - return; - } - - using namespace mtx::events; - state::Avatar avatar_event; - avatar_event.image_info.w = dimensions.width(); - avatar_event.image_info.h = dimensions.height(); - avatar_event.image_info.mimetype = mimetype; - avatar_event.image_info.size = size; - avatar_event.url = res.content_uri; - - http::client()->send_state_event( - room_id, - avatar_event, - [content = std::move(content), proxy = std::move(proxy)]( - const mtx::responses::EventId &, mtx::http::RequestErr err) { - if (err) { - emit proxy->error( - tr("Failed to upload image: %s") - .arg(QString::fromStdString(err->matrix_error.error))); - return; - } - - emit proxy->avatarChanged(); - }); - }); -} diff --git a/src/dialogs/RoomSettingsOld.h b/src/dialogs/RoomSettingsOld.h deleted file mode 100644 index ad8dd5bd..00000000 --- a/src/dialogs/RoomSettingsOld.h +++ /dev/null @@ -1,150 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "CacheStructs.h" - -class Avatar; -class FlatButton; -class QPushButton; -class QComboBox; -class QHBoxLayout; -class QShowEvent; -class LoadingIndicator; -class QLayout; -class QPixmap; -class TextField; -class TextField; -class Toggle; -class QLabel; -class QEvent; - -class ClickableFilter : public QObject -{ - Q_OBJECT - -public: - explicit ClickableFilter(QWidget *parent) - : QObject(parent) - {} - -signals: - void clicked(); - -protected: - bool eventFilter(QObject *obj, QEvent *event) override; -}; - -/// Convenience class which connects events emmited from threads -/// outside of main with the UI code. -class ThreadProxya : public QObject -{ - Q_OBJECT - -signals: - void error(const QString &msg); - void avatarChanged(); - void nameEventSent(const QString &); - void topicEventSent(); -}; - -class EditModal : public QWidget -{ - Q_OBJECT - -public: - EditModal(const QString &roomId, QWidget *parent = nullptr); - - void setFields(const QString &roomName, const QString &roomTopic); - -signals: - void nameChanged(const QString &roomName); - -private slots: - void topicEventSent(); - void nameEventSent(const QString &name); - void error(const QString &msg); - - void applyClicked(); - -private: - QString roomId_; - QString initialName_; - QString initialTopic_; - - QLabel *errorField_; - - TextField *nameInput_; - TextField *topicInput_; - - QPushButton *applyBtn_; - QPushButton *cancelBtn_; -}; - -namespace dialogs { - -class RoomSettingsOld : public QFrame -{ - Q_OBJECT -public: - RoomSettingsOld(const QString &room_id, QWidget *parent = nullptr); - -signals: - void enableEncryptionError(const QString &msg); - void showErrorMessage(const QString &msg); - void accessRulesUpdated(); - void notifChanged(int index); - -protected: - void showEvent(QShowEvent *event) override; - -private slots: - //! The file dialog opens so the user can select and upload a new room avatar. - void updateAvatar(); - -private: - //! 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; - //! Whether the user has enough power level to send m.room.avatar event. - bool canChangeAvatar(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 displayErrorMessage(const QString &msg); - - void setAvatar(); - void setupEditButton(); - //! Retrieve the current room information from cache. - void retrieveRoomInfo(); - void enableEncryption(); - - Avatar *avatar_ = nullptr; - - bool usesEncryption_ = false; - QHBoxLayout *btnLayout_; - - FlatButton *editFieldsBtn_ = nullptr; - - RoomInfo info_; - QString room_id_; - QImage avatarImg_; - - QLabel *roomNameLabel_ = nullptr; - QLabel *errorLabel_ = nullptr; - LoadingIndicator *spinner_ = nullptr; - - QComboBox *notifCombo = nullptr; - QComboBox *accessCombo = nullptr; - Toggle *encryptionToggle_ = nullptr; - Toggle *keyRequestsToggle_ = nullptr; -}; - -} // dialogs diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 29808fdd..efeba146 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -808,9 +808,9 @@ TimelineModel::openUserProfile(QString userid, bool global) } void -TimelineModel::openRoomSettings(QString roomid) +TimelineModel::openRoomSettings() { - RoomSettings *settings = new RoomSettings(roomid, this); + RoomSettings *settings = new RoomSettings(roomId(), this); connect(this, &TimelineModel::roomAvatarUrlChanged, settings, &RoomSettings::avatarChanged); openRoomSettingsDialog(settings); } diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 1a12a8c3..29207318 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -214,7 +214,7 @@ public: Q_INVOKABLE void viewRawMessage(QString id) const; Q_INVOKABLE void viewDecryptedRawMessage(QString id) const; Q_INVOKABLE void openUserProfile(QString userid, bool global = false); - Q_INVOKABLE void openRoomSettings(QString roomid); + Q_INVOKABLE void openRoomSettings(); Q_INVOKABLE void replyAction(QString id); Q_INVOKABLE void readReceiptsAction(QString id) const; Q_INVOKABLE void redactEvent(QString id); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 99a2e388..0ed680f8 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -395,12 +395,6 @@ TimelineViewManager::openLeaveRoomDialog() const { MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId()); } -void -TimelineViewManager::openRoomSettings() -{ - MainWindow::instance()->openRoomSettings(timeline_->roomId()); - timeline_->openRoomSettings(timeline_->roomId()); -} void TimelineViewManager::verifyUser(QString userid) diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index a2d37342..3e58bb43 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -18,7 +18,6 @@ #include "WebRTCSession.h" #include "emoji/EmojiModel.h" #include "emoji/Provider.h" -#include "dialogs/RoomSettingsOld.h" class MxcImageProvider; class BlurhashProvider; @@ -70,7 +69,6 @@ public: Q_INVOKABLE void openInviteUsersDialog(); Q_INVOKABLE void openMemberListDialog() const; Q_INVOKABLE void openLeaveRoomDialog() const; - Q_INVOKABLE void openRoomSettings(); Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow); void verifyUser(QString userid); diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index adf8d8a7..c7f388d4 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -4,16 +4,165 @@ #include #include #include +#include +#include +#include #include #include #include "Cache.h" #include "Logging.h" +#include "Config.h" #include "MatrixClient.h" +#include "ui/TextField.h" #include "Utils.h" using namespace mtx::events; +EditModal::EditModal(const QString &roomId, QWidget *parent) + : QWidget(parent) + , roomId_{roomId} +{ + setAutoFillBackground(true); + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); + setWindowModality(Qt::WindowModal); + + QFont largeFont; + largeFont.setPointSizeF(largeFont.pointSizeF() * 1.4); + setMinimumWidth(conf::window::minModalWidth); + setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + + auto layout = new QVBoxLayout(this); + + applyBtn_ = new QPushButton(tr("Apply"), this); + cancelBtn_ = new QPushButton(tr("Cancel"), this); + cancelBtn_->setDefault(true); + + auto btnLayout = new QHBoxLayout; + btnLayout->addStretch(1); + btnLayout->setSpacing(15); + btnLayout->addWidget(cancelBtn_); + btnLayout->addWidget(applyBtn_); + + nameInput_ = new TextField(this); + nameInput_->setLabel(tr("Name").toUpper()); + topicInput_ = new TextField(this); + topicInput_->setLabel(tr("Topic").toUpper()); + + errorField_ = new QLabel(this); + errorField_->setWordWrap(true); + errorField_->hide(); + + layout->addWidget(nameInput_); + layout->addWidget(topicInput_); + layout->addLayout(btnLayout, 1); + + auto labelLayout = new QHBoxLayout; + labelLayout->setAlignment(Qt::AlignHCenter); + labelLayout->addWidget(errorField_); + layout->addLayout(labelLayout); + + connect(applyBtn_, &QPushButton::clicked, this, &EditModal::applyClicked); + connect(cancelBtn_, &QPushButton::clicked, this, &EditModal::close); + + auto window = QApplication::activeWindow(); + + if (window != nullptr) { + auto center = window->frameGeometry().center(); + move(center.x() - (width() * 0.5), center.y() - (height() * 0.5)); + } +} + +void +EditModal::topicEventSent() +{ + errorField_->hide(); + close(); +} + +void +EditModal::nameEventSent(const QString &name) +{ + errorField_->hide(); + emit nameChanged(name); + close(); +} + +void +EditModal::error(const QString &msg) +{ + errorField_->setText(msg); + errorField_->show(); +} + +void +EditModal::applyClicked() +{ + // Check if the values are changed from the originals. + auto newName = nameInput_->text().trimmed(); + auto newTopic = topicInput_->text().trimmed(); + + errorField_->hide(); + + if (newName == initialName_ && newTopic == initialTopic_) { + close(); + return; + } + + using namespace mtx::events; + auto proxy = std::make_shared(); + connect(proxy.get(), &ThreadProxy::topicEventSent, this, &EditModal::topicEventSent); + connect(proxy.get(), &ThreadProxy::nameEventSent, this, &EditModal::nameEventSent); + connect(proxy.get(), &ThreadProxy::error, this, &EditModal::error); + + if (newName != initialName_ && !newName.isEmpty()) { + state::Name body; + body.name = newName.toStdString(); + + http::client()->send_state_event( + roomId_.toStdString(), + body, + [proxy, newName](const mtx::responses::EventId &, mtx::http::RequestErr err) { + if (err) { + emit proxy->error( + QString::fromStdString(err->matrix_error.error)); + return; + } + + emit proxy->nameEventSent(newName); + }); + } + + if (newTopic != initialTopic_ && !newTopic.isEmpty()) { + state::Topic body; + body.topic = newTopic.toStdString(); + + http::client()->send_state_event( + roomId_.toStdString(), + body, + [proxy](const mtx::responses::EventId &, mtx::http::RequestErr err) { + if (err) { + emit proxy->error( + QString::fromStdString(err->matrix_error.error)); + return; + } + + emit proxy->topicEventSent(); + }); + } +} + +void +EditModal::setFields(const QString &roomName, const QString &roomTopic) +{ + initialName_ = roomName; + initialTopic_ = roomTopic; + + nameInput_->setText(roomName); + topicInput_->setText(roomTopic); +} + RoomSettings::RoomSettings(QString roomid, QObject *parent) : roomid_{std::move(roomid)} , QObject(parent) @@ -220,6 +369,21 @@ RoomSettings::isEncryptionEnabled() const return usesEncryption_; } +void +RoomSettings::openEditModal() +{ + retrieveRoomInfo(); + + auto modal = new EditModal(roomid_); + modal->setFields(QString::fromStdString(info_.name), QString::fromStdString(info_.topic)); + modal->raise(); + modal->show(); + connect(modal, &EditModal::nameChanged, this, [this](const QString &newName) { + info_.name = newName.toStdString(); + emit roomNameChanged(); + }); +} + void RoomSettings::changeNotifications(int currentIndex) { diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h index d31b38f2..0d0b13f6 100644 --- a/src/ui/RoomSettings.h +++ b/src/ui/RoomSettings.h @@ -1,12 +1,16 @@ #pragma once +#include #include +#include #include #include #include "CacheStructs.h" +class TextField; + /// Convenience class which connects events emmited from threads /// outside of main with the UI code. class ThreadProxy : public QObject @@ -20,10 +24,43 @@ signals: void stopLoading(); }; +class EditModal : public QWidget +{ + Q_OBJECT + +public: + EditModal(const QString &roomId, QWidget *parent = nullptr); + + void setFields(const QString &roomName, const QString &roomTopic); + +signals: + void nameChanged(const QString &roomName); + +private slots: + void topicEventSent(); + void nameEventSent(const QString &name); + void error(const QString &msg); + + void applyClicked(); + +private: + QString roomId_; + QString initialName_; + QString initialTopic_; + + QLabel *errorField_; + + TextField *nameInput_; + TextField *topicInput_; + + QPushButton *applyBtn_; + QPushButton *cancelBtn_; +}; + class RoomSettings : public QObject { Q_OBJECT - Q_PROPERTY(QString roomName READ roomName CONSTANT) + Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT) Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged) @@ -62,6 +99,7 @@ public: Q_INVOKABLE void changeKeyRequestsPreference(bool isOn); Q_INVOKABLE void enableEncryption(); Q_INVOKABLE void updateAvatar(); + Q_INVOKABLE void openEditModal(); signals: void notificationsChanged(); @@ -69,6 +107,7 @@ signals: void keyRequestsChanged(); void encryptionChanged(); void avatarUrlChanged(); + void roomNameChanged(); void loadingChanged(); void displayError(const QString &errorMessage); -- cgit 1.5.1 From f3596aed554feb848b3f3d09239e5cacf2155024 Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Sat, 13 Feb 2021 19:08:52 +0530 Subject: added room topic --- resources/qml/RoomSettings.qml | 37 +++++++++++++++++++++++++++++++++---- resources/qml/TopBar.qml | 2 +- src/ui/RoomSettings.cpp | 20 ++++++++++++++++---- src/ui/RoomSettings.h | 32 ++++++++++++++++++-------------- 4 files changed, 68 insertions(+), 23 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index eabe68f5..2f6f1866 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -12,8 +12,8 @@ ApplicationWindow { x: MainWindow.x + (MainWindow.width / 2) - (width / 2) y: MainWindow.y + (MainWindow.height / 2) - (height / 2) - minimumWidth: 340 - minimumHeight: 600 + minimumWidth: 400 + minimumHeight: 650 palette: colors color: colors.window modality: Qt.WindowModal @@ -24,9 +24,12 @@ ApplicationWindow { } ColumnLayout { - id: contentLayout + id: contentLayout1 - anchors.fill: parent + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: undefined anchors.margins: 10 spacing: 10 @@ -101,6 +104,32 @@ ApplicationWindow { visible: roomSettings.canChangeNameAndTopic onClicked: roomSettings.openEditModal() } + } + + ScrollView { + id: topicScroll + anchors.left: parent.left + anchors.right: parent.right + anchors.top: contentLayout1.bottom + anchors.bottom: undefined + anchors.margins: 10 + height: 100 + + TextArea { + text: roomSettings.roomTopic + background: null + } + } + + ColumnLayout { + id: contentLayout2 + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: topicScroll.bottom + anchors.bottom: parent.bottom + anchors.margins: 10 + spacing: 10 MatrixText { text: "SETTINGS" diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index c64eddd4..967aa11e 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -15,7 +15,7 @@ Rectangle { MouseArea { anchors.fill: parent - onClicked: TimelineManager.openRoomSettings() + onClicked: TimelineManager.timeline.openRoomSettings() } GridLayout { diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index c7f388d4..d2b5a630 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -75,9 +75,10 @@ EditModal::EditModal(const QString &roomId, QWidget *parent) } void -EditModal::topicEventSent() +EditModal::topicEventSent(const QString &topic) { errorField_->hide(); + emit topicChanged(topic); close(); } @@ -141,14 +142,14 @@ EditModal::applyClicked() http::client()->send_state_event( roomId_.toStdString(), body, - [proxy](const mtx::responses::EventId &, mtx::http::RequestErr err) { + [proxy, newTopic](const mtx::responses::EventId &, mtx::http::RequestErr err) { if (err) { emit proxy->error( QString::fromStdString(err->matrix_error.error)); return; } - emit proxy->topicEventSent(); + emit proxy->topicEventSent(newTopic); }); } } @@ -222,7 +223,13 @@ RoomSettings::RoomSettings(QString roomid, QObject *parent) QString RoomSettings::roomName() const { - return QString(info_.name.c_str()); + return QString::fromStdString(info_.name); +} + +QString +RoomSettings::roomTopic() const +{ + return QString::fromStdString(info_.topic); } QString @@ -382,6 +389,11 @@ RoomSettings::openEditModal() info_.name = newName.toStdString(); emit roomNameChanged(); }); + + connect(modal, &EditModal::topicChanged, this, [this](const QString &newTopic) { + info_.topic = newTopic.toStdString(); + emit roomTopicChanged(); + }); } void diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h index 0d0b13f6..25c6e588 100644 --- a/src/ui/RoomSettings.h +++ b/src/ui/RoomSettings.h @@ -20,7 +20,7 @@ class ThreadProxy : public QObject signals: void error(const QString &msg); void nameEventSent(const QString &); - void topicEventSent(); + void topicEventSent(const QString &); void stopLoading(); }; @@ -35,9 +35,10 @@ public: signals: void nameChanged(const QString &roomName); + void topicChanged(const QString &topic); private slots: - void topicEventSent(); + void topicEventSent(const QString &topic); void nameEventSent(const QString &name); void error(const QString &msg); @@ -60,25 +61,27 @@ private: class RoomSettings : public QObject { Q_OBJECT - Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT) + Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) + Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged) Q_PROPERTY(int memberCount READ memberCount CONSTANT) Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged) Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged) Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged) + Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT) Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT) Q_PROPERTY(bool canChangeNameAndTopic READ canChangeNameAndTopic CONSTANT) - Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT) Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged) Q_PROPERTY(bool respondsToKeyRequests READ respondsToKeyRequests NOTIFY keyRequestsChanged) public: RoomSettings(QString roomid, QObject *parent = nullptr); - QString roomName() const; QString roomId() const; + QString roomName() const; + QString roomTopic() const; QString roomVersion() const; QString roomAvatarUrl(); int memberCount() const; @@ -94,26 +97,27 @@ public: bool canChangeAvatar() const; bool isEncryptionEnabled() const; - Q_INVOKABLE void changeNotifications(int currentIndex); - Q_INVOKABLE void changeAccessRules(int index); - Q_INVOKABLE void changeKeyRequestsPreference(bool isOn); Q_INVOKABLE void enableEncryption(); Q_INVOKABLE void updateAvatar(); Q_INVOKABLE void openEditModal(); + Q_INVOKABLE void changeAccessRules(int index); + Q_INVOKABLE void changeNotifications(int currentIndex); + Q_INVOKABLE void changeKeyRequestsPreference(bool isOn); signals: + void loadingChanged(); + void roomNameChanged(); + void roomTopicChanged(); + void avatarUrlChanged(); + void encryptionChanged(); + void keyRequestsChanged(); void notificationsChanged(); void accessJoinRulesChanged(); - void keyRequestsChanged(); - void encryptionChanged(); - void avatarUrlChanged(); - void roomNameChanged(); - void loadingChanged(); void displayError(const QString &errorMessage); public slots: - void avatarChanged(); void stopLoading(); + void avatarChanged(); private: void retrieveRoomInfo(); -- cgit 1.5.1 From 1a406f79e6c7f673172c07da30ab958e980d919c Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Sat, 13 Feb 2021 23:59:42 +0530 Subject: replaced with togglebutton using qtquickcontrols2 --- resources/qml/ToggleButton.qml | 36 +++++++++++++++++++++++------------- src/MainWindow.h | 1 - src/timeline/TimelineModel.h | 2 +- src/ui/RoomSettings.cpp | 8 ++++---- 4 files changed, 28 insertions(+), 19 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/ToggleButton.qml b/resources/qml/ToggleButton.qml index cf67c48c..01aef4c6 100644 --- a/resources/qml/ToggleButton.qml +++ b/resources/qml/ToggleButton.qml @@ -1,22 +1,32 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.12 +import QtQuick.Controls 2.12 import im.nheko 1.0 Switch { - style: SwitchStyle { - handle: Rectangle { - width: 20 - height: 20 - radius: 90 - color: "whitesmoke" + id: toggleButton + + indicator: Item { + implicitWidth: 48 + implicitHeight: 26 + + Rectangle { + height: parent.height/2 + radius: height/2 + width: parent.width - height + x: radius + y: parent.height / 2 - height / 2 + color: toggleButton.checked ? "skyblue" : "grey" + border.color: "#cccccc" } - groove: Rectangle { - implicitWidth: 40 - implicitHeight: 20 - radius: 90 - color: checked ? "skyblue" : "grey" + Rectangle { + x: toggleButton.checked ? parent.width - width : 0 + width: parent.height + height: width + radius: width/2 + color: toggleButton.down ? "whitesmoke" : "whitesmoke" + border.color: "#999999" } } } \ No newline at end of file diff --git a/src/MainWindow.h b/src/MainWindow.h index 5c2df8b6..4a8ea642 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -54,7 +54,6 @@ class LeaveRoom; class Logout; class MemberList; class ReCaptcha; -class RoomSettingsOld; } class MainWindow : public QMainWindow diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 29207318..df067fd4 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -11,8 +11,8 @@ #include "CacheCryptoStructs.h" #include "EventStore.h" #include "InputBar.h" -#include "ui/UserProfile.h" #include "ui/RoomSettings.h" +#include "ui/UserProfile.h" namespace mtx::http { using RequestErr = const std::optional &; diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index d2b5a630..b166332c 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -1,21 +1,21 @@ #include "RoomSettings.h" +#include #include +#include #include #include #include -#include #include -#include #include #include #include "Cache.h" -#include "Logging.h" #include "Config.h" +#include "Logging.h" #include "MatrixClient.h" -#include "ui/TextField.h" #include "Utils.h" +#include "ui/TextField.h" using namespace mtx::events; -- cgit 1.5.1 From b5e351ab025fe751cd230371714cdee24125bfc4 Mon Sep 17 00:00:00 2001 From: Jedi18 Date: Sun, 14 Feb 2021 11:26:10 +0530 Subject: Replace rowlayouts with gridlayout and fix room settings initializer list --- resources/qml/RoomSettings.qml | 61 +++++++++++++++++------------------------- src/ui/RoomSettings.cpp | 4 +-- 2 files changed, 27 insertions(+), 38 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index b3602a6a..eebecebb 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -12,7 +12,7 @@ ApplicationWindow { x: MainWindow.x + (MainWindow.width / 2) - (width / 2) y: MainWindow.y + (MainWindow.height / 2) - (height / 2) - minimumWidth: 400 + minimumWidth: 420 minimumHeight: 650 palette: colors color: colors.window @@ -113,56 +113,55 @@ ApplicationWindow { wrapMode: TextEdit.WordWrap readOnly: true background: null + horizontalAlignment: TextEdit.AlignHCenter + selectByMouse: true } } - MatrixText { - text: "SETTINGS" - } + GridLayout { + columns: 2 - RowLayout { MatrixText { - text: "Notifications" + text: "SETTINGS" } Item { Layout.fillWidth: true } + MatrixText { + text: "Notifications" + Layout.fillWidth: true + } + ComboBox { model: [ "Muted", "Mentions only", "All messages" ] currentIndex: roomSettings.notifications onActivated: { roomSettings.changeNotifications(index) } + Layout.fillWidth: true } - } - RowLayout { MatrixText { text: "Room access" + Layout.fillWidth: true } ComboBox { - Layout.fillWidth: true enabled: roomSettings.canChangeJoinRules model: [ "Anyone and guests", "Anyone", "Invited users" ] currentIndex: roomSettings.accessJoinRules onActivated: { roomSettings.changeAccessRules(index) } + Layout.fillWidth: true } - } - RowLayout { MatrixText { text: "Encryption" } - Item { - Layout.fillWidth: true - } - ToggleButton { id: encryptionToggle @@ -175,6 +174,7 @@ ApplicationWindow { confirmEncryptionDialog.open(); } + Layout.alignment: Qt.AlignRight } MessageDialog { @@ -199,20 +199,14 @@ ApplicationWindow { standardButtons: Dialog.Ok | Dialog.Cancel } - } - - RowLayout { - visible: roomSettings.isEncryptionEnabled MatrixText { + visible: roomSettings.isEncryptionEnabled text: "Respond to key requests" } - Item { - Layout.fillWidth: true - } - ToggleButton { + visible: roomSettings.isEncryptionEnabled ToolTip.text: qsTr("Whether or not the client should respond automatically with the session keys upon request. Use with caution, this is a temporary measure to test the E2E implementation until device verification is completed.") @@ -222,40 +216,35 @@ ApplicationWindow { onClicked: { roomSettings.changeKeyRequestsPreference(checked) } + Layout.alignment: Qt.AlignRight } - } - - MatrixText { - text: "INFO" - } - RowLayout { MatrixText { - text: "Internal ID" + text: "INFO" } Item { Layout.fillWidth: true } + MatrixText { + text: "Internal ID" + } + MatrixText { text: roomSettings.roomId font.pixelSize: 12 + Layout.alignment: Qt.AlignRight } - } - RowLayout { MatrixText { text: "Room Version" } - Item { - Layout.fillWidth: true - } - MatrixText { text: roomSettings.roomVersion font.pixelSize: 12 + Layout.alignment: Qt.AlignRight } } diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index b166332c..aa6f60a0 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -165,8 +165,8 @@ EditModal::setFields(const QString &roomName, const QString &roomTopic) } RoomSettings::RoomSettings(QString roomid, QObject *parent) - : roomid_{std::move(roomid)} - , QObject(parent) + : QObject(parent) + , roomid_{std::move(roomid)} { retrieveRoomInfo(); -- cgit 1.5.1 From af9b66dd3ece30e3870acc19e3e34cc70a9eaf68 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Mon, 22 Feb 2021 21:35:11 +0100 Subject: Linkify topic in room settings and use non-deprecated MessageDialog --- README.md | 4 ++-- resources/qml/RoomSettings.qml | 24 +++++++++++++++--------- src/ui/RoomSettings.cpp | 4 ++-- 3 files changed, 19 insertions(+), 13 deletions(-) (limited to 'src/ui/RoomSettings.cpp') diff --git a/README.md b/README.md index 4f8aa111..15d4f416 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ sudo emerge -a ">=dev-qt/qtgui-5.10.0" media-libs/fontconfig dev-libs/qtkeychain ```bash # Build requirements + qml modules needed at runtime (you may not need all of them, but the following seem to work according to reports): -sudo apt install g++ cmake zlib1g-dev libssl-dev qt{base,declarative,tools,multimedia,quickcontrols2-}5-dev libqt5svg5-dev libboost-system-dev libboost-thread-dev libboost-iostreams-dev libolm-dev liblmdb++-dev libcmark-dev nlohmann-json3-dev libspdlog-dev libgtest-dev qml-module-qt{gstreamer,multimedia,quick-extras,-labs-settings,graphicaleffects,quick-controls2} qt5keychain-dev +sudo apt install g++ cmake zlib1g-dev libssl-dev qt{base,declarative,tools,multimedia,quickcontrols2-}5-dev libqt5svg5-dev libboost-system-dev libboost-thread-dev libboost-iostreams-dev libolm-dev liblmdb++-dev libcmark-dev nlohmann-json3-dev libspdlog-dev libgtest-dev qml-module-qt{gstreamer,multimedia,quick-extras,-labs-settings,-labs-platform,graphicaleffects,quick-controls2} qt5keychain-dev ``` This will install all dependencies, except for tweeny (use bundled tweeny) and mtxclient (needs to be build separately). @@ -204,7 +204,7 @@ and mtxclient (needs to be build separately). sudo apt install cmake gcc make automake liblmdb-dev \ qt5-default libssl-dev libqt5multimedia5-plugins libqt5multimediagsttools5 libqt5multimediaquick5 libqt5svg5-dev \ qml-module-qtgstreamer qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools qtdeclarative5-dev \ - qml-module-qtgraphicaleffects qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts \ + qml-module-qtgraphicaleffects qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qt-labs-platform\ qt5keychain-dev ``` diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index b37dab76..58e34a8f 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -1,6 +1,6 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 -import QtQuick.Dialogs 1.2 +import Qt.labs.platform 1.1 as Platform import QtQuick.Layouts 1.2 import QtQuick.Window 2.3 import im.nheko 1.0 @@ -110,18 +110,25 @@ ApplicationWindow { ScrollView { Layout.maximumHeight: 75 - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true + width: parent.width TextArea { - text: roomSettings.roomTopic - wrapMode: TextEdit.WordWrap + text: TimelineManager.escapeEmoji(roomSettings.roomTopic) + wrapMode: TextEdit.WordWrap + textFormat: TextEdit.RichText readOnly: true background: null selectByMouse: true color: colors.text - horizontalAlignment: TextEdit.AlignHCenter + horizontalAlignment: TextEdit.AlignHCenter + + onLinkActivated: TimelineManager.openLink(link); + + CursorShape { + anchors.fill: parent + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } } } @@ -186,14 +193,13 @@ ApplicationWindow { Layout.alignment: Qt.AlignRight } - MessageDialog { + Platform.MessageDialog { id: confirmEncryptionDialog title: qsTr("End-to-End Encryption") text: qsTr("Encryption is currently experimental and things might break unexpectedly.
Please take note that it can't be disabled afterwards.") modality: Qt.WindowModal - icon: StandardIcon.Question onAccepted: { if (roomSettings.isEncryptionEnabled) return ; @@ -203,7 +209,7 @@ ApplicationWindow { onRejected: { encryptionToggle.checked = false; } - standardButtons: Dialog.Ok | Dialog.Cancel + buttons: Dialog.Ok | Dialog.Cancel } MatrixText { diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp index aa6f60a0..a264c78b 100644 --- a/src/ui/RoomSettings.cpp +++ b/src/ui/RoomSettings.cpp @@ -229,7 +229,7 @@ RoomSettings::roomName() const QString RoomSettings::roomTopic() const { - return QString::fromStdString(info_.topic); + return utils::linkifyMessage(QString::fromStdString(info_.topic).toHtmlEscaped()); } QString @@ -622,4 +622,4 @@ RoomSettings::updateAvatar() emit proxy->stopLoading(); }); }); -} \ No newline at end of file +} -- cgit 1.5.1