diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp
index 2d124e1e..31ae863e 100644
--- a/src/ui/RoomSettings.cpp
+++ b/src/ui/RoomSettings.cpp
@@ -27,6 +27,7 @@ RoomSettings::RoomSettings(QString roomid, QObject *parent)
: QObject(parent)
, roomid_{std::move(roomid)}
{
+ connect(this, &RoomSettings::accessJoinRulesChanged, &RoomSettings::allowedRoomsChanged);
retrieveRoomInfo();
// get room setting notifications
@@ -66,22 +67,15 @@ RoomSettings::RoomSettings(QString roomid, QObject *parent)
});
// access rules
- if (info_.join_rule == state::JoinRule::Public) {
- if (info_.guest_access) {
- accessRules_ = 0;
- } else {
- accessRules_ = 1;
- }
- } else if (info_.join_rule == state::JoinRule::Invite) {
- accessRules_ = 2;
- } else if (info_.join_rule == state::JoinRule::Knock) {
- accessRules_ = 3;
- } else if (info_.join_rule == state::JoinRule::Restricted) {
- accessRules_ = 4;
- } else if (info_.join_rule == state::JoinRule::KnockRestricted) {
- accessRules_ = 5;
- }
+ this->accessRules_ = cache::client()
+ ->getStateEvent<mtx::events::state::JoinRules>(roomid_.toStdString())
+ .value_or(mtx::events::StateEvent<mtx::events::state::JoinRules>{})
+ .content;
+ using mtx::events::state::AccessState;
+ guestRules_ = info_.guest_access ? AccessState::CanJoin : AccessState::Forbidden;
emit accessJoinRulesChanged();
+
+ this->allowedRoomsModel = new RoomSettingsAllowedRoomsModel(this);
}
QString
@@ -158,10 +152,49 @@ RoomSettings::notifications()
return notifications_;
}
-int
-RoomSettings::accessJoinRules()
+bool
+RoomSettings::privateAccess() const
+{
+ return accessRules_.join_rule != mtx::events::state::JoinRule::Public;
+}
+
+bool
+RoomSettings::guestAccess() const
{
- return accessRules_;
+ return guestRules_ == mtx::events::state::AccessState::CanJoin;
+}
+bool
+RoomSettings::knockingEnabled() const
+{
+ return accessRules_.join_rule == mtx::events::state::JoinRule::Knock ||
+ accessRules_.join_rule == mtx::events::state::JoinRule::KnockRestricted;
+}
+bool
+RoomSettings::restrictedEnabled() const
+{
+ return accessRules_.join_rule == mtx::events::state::JoinRule::Restricted ||
+ accessRules_.join_rule == mtx::events::state::JoinRule::KnockRestricted;
+}
+
+QStringList
+RoomSettings::allowedRooms() const
+{
+ QStringList rooms;
+ rooms.reserve(accessRules_.allow.size());
+ for (const auto &e : accessRules_.allow) {
+ if (e.type == mtx::events::state::JoinAllowanceType::RoomMembership)
+ rooms.push_back(QString::fromStdString(e.room_id));
+ }
+ return rooms;
+}
+void
+RoomSettings::setAllowedRooms(QStringList rooms)
+{
+ accessRules_.allow.clear();
+ for (const auto &e : rooms) {
+ accessRules_.allow.push_back(
+ {mtx::events::state::JoinAllowanceType::RoomMembership, e.toStdString()});
+ }
}
void
@@ -254,24 +287,48 @@ RoomSettings::isEncryptionEnabled() const
bool
RoomSettings::supportsKnocking() const
{
- return info_.version != "" && info_.version != "1" && info_.version != "2" &&
- info_.version != "3" && info_.version != "4" && info_.version != "5" &&
- info_.version != "6";
+ const static std::set<std::string_view> unsupported{
+ "",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ };
+ return !unsupported.count(info_.version);
}
bool
RoomSettings::supportsRestricted() const
{
- return info_.version != "" && info_.version != "1" && info_.version != "2" &&
- info_.version != "3" && info_.version != "4" && info_.version != "5" &&
- info_.version != "6" && info_.version != "7";
+ const static std::set<std::string_view> unsupported{
+ "",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ };
+ return !unsupported.count(info_.version);
}
bool
RoomSettings::supportsKnockRestricted() const
{
- return info_.version != "" && info_.version != "1" && info_.version != "2" &&
- info_.version != "3" && info_.version != "4" && info_.version != "5" &&
- info_.version != "6" && info_.version != "7" && info_.version != "8" &&
- info_.version != "9";
+ const static std::set<std::string_view> unsupported{
+ "",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ };
+ return !unsupported.count(info_.version);
}
void
@@ -327,47 +384,41 @@ RoomSettings::changeNotifications(int currentIndex)
}
void
-RoomSettings::changeAccessRules(int index)
+RoomSettings::changeAccessRules(bool private_,
+ bool guestsAllowed,
+ bool knockingAllowed,
+ bool restrictedAllowed)
{
using namespace mtx::events::state;
- auto guest_access = [](int index) -> state::GuestAccess {
+ auto guest_access = [guestsAllowed]() -> state::GuestAccess {
state::GuestAccess event;
- if (index == 0)
+ if (guestsAllowed)
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;
+ auto join_rule = [this, private_, knockingAllowed, restrictedAllowed]() -> state::JoinRules {
+ state::JoinRules event = this->accessRules_;
- switch (index) {
- case 0:
- case 1:
+ if (!private_) {
event.join_rule = state::JoinRule::Public;
- break;
- case 2:
- event.join_rule = state::JoinRule::Invite;
- break;
- case 3:
+ } else if (knockingAllowed && restrictedAllowed && supportsKnockRestricted()) {
+ event.join_rule = state::JoinRule::KnockRestricted;
+ } else if (knockingAllowed && supportsKnocking()) {
event.join_rule = state::JoinRule::Knock;
- break;
- case 4:
+ } else if (restrictedAllowed && supportsRestricted()) {
event.join_rule = state::JoinRule::Restricted;
- break;
- case 5:
- event.join_rule = state::JoinRule::KnockRestricted;
- break;
- default:
+ } else {
event.join_rule = state::JoinRule::Invite;
}
return event;
- }(index);
+ }();
updateAccessRules(roomid_.toStdString(), join_rule, guest_access);
}
@@ -445,13 +496,16 @@ RoomSettings::updateAccessRules(const std::string &room_id,
const mtx::events::state::JoinRules &join_rule,
const mtx::events::state::GuestAccess &guest_access)
{
- isLoading_ = true;
+ isLoading_ = true;
+ allowedRoomsModified_ = false;
emit loadingChanged();
+ emit allowedRoomsModifiedChanged();
http::client()->send_state_event(
room_id,
join_rule,
- [this, room_id, guest_access](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ [this, room_id, guest_access, join_rule](const mtx::responses::EventId &,
+ mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to send m.room.join_rule: {} {}",
static_cast<int>(err->status_code),
@@ -465,7 +519,7 @@ RoomSettings::updateAccessRules(const std::string &room_id,
http::client()->send_state_event(
room_id,
guest_access,
- [this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ [this, join_rule](const mtx::responses::EventId &, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to send m.room.guest_access: {} {}",
static_cast<int>(err->status_code),
@@ -475,6 +529,9 @@ RoomSettings::updateAccessRules(const std::string &room_id,
isLoading_ = false;
emit loadingChanged();
+
+ this->accessRules_ = join_rule;
+ emit accessJoinRulesChanged();
});
});
}
@@ -576,3 +633,101 @@ RoomSettings::updateAvatar()
});
});
}
+
+RoomSettingsAllowedRoomsModel::RoomSettingsAllowedRoomsModel(RoomSettings *parent)
+ : QAbstractListModel(parent)
+ , settings(parent)
+{
+ this->allowedRoomIds = settings->allowedRooms();
+
+ auto prIds = cache::client()->getParentRoomIds(settings->roomId().toStdString());
+ for (const auto &prId : prIds) {
+ this->parentSpaces.insert(QString::fromStdString(prId));
+ }
+
+ this->listedRoomIds = QStringList(parentSpaces.begin(), parentSpaces.end());
+
+ for (const auto &e : this->allowedRoomIds) {
+ if (!this->parentSpaces.count(e))
+ this->listedRoomIds.push_back(e);
+ }
+}
+
+QHash<int, QByteArray>
+RoomSettingsAllowedRoomsModel::roleNames() const
+{
+ return {
+ {Roles::Name, "name"},
+ {Roles::IsAllowed, "allowed"},
+ {Roles::IsSpaceParent, "isParent"},
+ };
+}
+
+int
+RoomSettingsAllowedRoomsModel::rowCount(const QModelIndex &) const
+{
+ return listedRoomIds.size();
+}
+
+QVariant
+RoomSettingsAllowedRoomsModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() < 0 || index.row() > listedRoomIds.size())
+ return {};
+
+ if (role == Roles::IsAllowed) {
+ return allowedRoomIds.contains(listedRoomIds.at(index.row()));
+ } else if (role == Roles::IsSpaceParent) {
+ return parentSpaces.find(listedRoomIds.at(index.row())) != parentSpaces.cend();
+ } else if (role == Roles::Name) {
+ auto id = listedRoomIds.at(index.row());
+ auto info = cache::client()->getRoomInfo({
+ id.toStdString(),
+ });
+ if (!info.empty())
+ return QString::fromStdString(info[id].name);
+ else
+ return "";
+ } else {
+ return {};
+ }
+}
+
+bool
+RoomSettingsAllowedRoomsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (index.row() < 0 || index.row() > listedRoomIds.size())
+ return false;
+
+ if (role != Roles::IsAllowed)
+ return false;
+
+ if (value.toBool()) {
+ if (!allowedRoomIds.contains(listedRoomIds.at(index.row())))
+ allowedRoomIds.push_back(listedRoomIds.at(index.row()));
+ } else {
+ allowedRoomIds.removeAll(listedRoomIds.at(index.row()));
+ }
+
+ return true;
+}
+
+void
+RoomSettingsAllowedRoomsModel::addRoom(QString room)
+{
+ if (listedRoomIds.contains(room) || !room.startsWith('!'))
+ return;
+
+ beginInsertRows(QModelIndex(), listedRoomIds.size(), listedRoomIds.size());
+ listedRoomIds.push_back(room);
+ allowedRoomIds.push_back(room);
+ endInsertRows();
+}
+
+void
+RoomSettings::applyAllowedFromModel()
+{
+ this->setAllowedRooms(this->allowedRoomsModel->allowedRoomIds);
+ this->allowedRoomsModified_ = true;
+ emit allowedRoomsModifiedChanged();
+}
diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h
index 4cb5bcf4..35698310 100644
--- a/src/ui/RoomSettings.h
+++ b/src/ui/RoomSettings.h
@@ -5,10 +5,13 @@
#pragma once
+#include <QAbstractListModel>
#include <QObject>
#include <QSet>
#include <QString>
+#include <unordered_set>
+
#include <mtx/events/event_type.hpp>
#include <mtx/events/guest_access.hpp>
@@ -27,6 +30,43 @@ signals:
void stopLoading();
};
+class RoomSettings;
+
+class RoomSettingsAllowedRoomsModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ enum Roles
+ {
+ Name,
+ IsAllowed,
+ IsSpaceParent,
+ };
+
+ explicit RoomSettingsAllowedRoomsModel(RoomSettings *parent);
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool
+ setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole) override;
+ Q_INVOKABLE void addRoom(QString room);
+
+ Qt::ItemFlags flags(const QModelIndex &) const override
+ {
+ return Qt::ItemIsEditable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
+ Qt::ItemNeverHasChildren;
+ }
+
+ QStringList allowedRoomIds;
+
+private:
+ QStringList listedRoomIds;
+ std::unordered_set<QString> parentSpaces;
+ RoomSettings *settings;
+};
+
class RoomSettings : public QObject
{
Q_OBJECT
@@ -39,7 +79,10 @@ class RoomSettings : public QObject
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 privateAccess READ privateAccess NOTIFY accessJoinRulesChanged)
+ Q_PROPERTY(bool guestAccess READ guestAccess NOTIFY accessJoinRulesChanged)
+ Q_PROPERTY(bool knockingEnabled READ knockingEnabled NOTIFY accessJoinRulesChanged)
+ Q_PROPERTY(bool restrictedEnabled READ restrictedEnabled NOTIFY accessJoinRulesChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT)
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
@@ -49,6 +92,11 @@ class RoomSettings : public QObject
Q_PROPERTY(bool supportsKnocking READ supportsKnocking CONSTANT)
Q_PROPERTY(bool supportsRestricted READ supportsRestricted CONSTANT)
Q_PROPERTY(bool supportsKnockRestricted READ supportsKnockRestricted CONSTANT)
+ Q_PROPERTY(
+ QStringList allowedRooms READ allowedRooms WRITE setAllowedRooms NOTIFY allowedRoomsChanged)
+ Q_PROPERTY(RoomSettingsAllowedRoomsModel *allowedRoomsModel MEMBER allowedRoomsModel CONSTANT)
+ Q_PROPERTY(
+ bool allowedRoomsModified READ allowedRoomsModified NOTIFY allowedRoomsModifiedChanged)
public:
RoomSettings(QString roomid, QObject *parent = nullptr);
@@ -62,7 +110,10 @@ public:
QString roomAvatarUrl();
int memberCount() const;
int notifications();
- int accessJoinRules();
+ bool privateAccess() const;
+ bool guestAccess() const;
+ bool knockingEnabled() const;
+ bool restrictedEnabled() const;
bool isLoading() const;
//! Whether the user has enough power level to send m.room.join_rules events.
bool canChangeJoinRules() const;
@@ -76,14 +127,22 @@ public:
bool supportsKnocking() const;
bool supportsRestricted() const;
bool supportsKnockRestricted() const;
+ QStringList allowedRooms() const;
+ void setAllowedRooms(QStringList rooms);
+ bool allowedRoomsModified() const { return allowedRoomsModified_; }
Q_INVOKABLE void enableEncryption();
Q_INVOKABLE void updateAvatar();
- Q_INVOKABLE void changeAccessRules(int index);
+ Q_INVOKABLE void changeAccessRules(bool private_,
+ bool guestsAllowed,
+ bool knockingAllowed,
+ bool restrictedAllowed);
Q_INVOKABLE void changeNotifications(int currentIndex);
Q_INVOKABLE void changeTopic(QString topic);
Q_INVOKABLE void changeName(QString name);
+ Q_INVOKABLE void applyAllowedFromModel();
+
signals:
void loadingChanged();
void roomNameChanged();
@@ -92,7 +151,9 @@ signals:
void encryptionChanged();
void notificationsChanged();
void accessJoinRulesChanged();
+ void allowedRoomsChanged();
void displayError(const QString &errorMessage);
+ void allowedRoomsModifiedChanged();
public slots:
void stopLoading();
@@ -106,9 +167,14 @@ private:
private:
QString roomid_;
- bool usesEncryption_ = false;
- bool isLoading_ = false;
+ bool usesEncryption_ = false;
+ bool isLoading_ = false;
+ bool allowedRoomsModified_ = false;
RoomInfo info_;
int notifications_ = 0;
- int accessRules_ = 0;
+
+ mtx::events::state::JoinRules accessRules_;
+ mtx::events::state::AccessState guestRules_ = mtx::events::state::AccessState::Forbidden;
+
+ RoomSettingsAllowedRoomsModel *allowedRoomsModel;
};
|