diff --git a/CMakeLists.txt b/CMakeLists.txt
index 57bb74b6..c8ccfe7f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -375,6 +375,7 @@ set(SRC_FILES
src/SSOHandler.cpp
src/CombinedImagePackModel.cpp
src/SingleImagePackModel.cpp
+ src/SpaceChildrenModel.cpp
src/ImagePackListModel.cpp
src/TrayIcon.cpp
src/UserSettingsPage.cpp
@@ -570,6 +571,7 @@ qt5_wrap_cpp(MOC_HEADERS
src/RoomsModel.h
src/SSOHandler.h
src/SingleImagePackModel.h
+ src/SpaceChildrenModel.h
src/TrayIcon.h
src/UserSettingsPage.h
src/UsersModel.h
diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml
index 72f30b7a..71b29bd1 100644
--- a/resources/qml/Root.qml
+++ b/resources/qml/Root.qml
@@ -59,6 +59,14 @@ Pane {
}
+ Component {
+ id: spaceChildrenComponent
+
+ SpaceChildren {
+ }
+
+ }
+
Component {
id: roomMembersComponent
@@ -265,6 +273,15 @@ Pane {
destroyOnClose(roomSettings);
}
+ function onOpenSpaceChildrenDialog(spaceChildren, nonChildren) {
+ var spaceChildrenDialog = spaceChildrenComponent.createObject(timelineRoot, {
+ "spaceChildren": spaceChildren,
+ "nonChildren": nonChildren
+ });
+ spaceChildrenDialog.show();
+ destroyOnClose(spaceChildrenDialog);
+ }
+
function onOpenInviteUsersDialog(invitees) {
var dialog = inviteDialog.createObject(timelineRoot, {
"roomId": Rooms.currentRoom.roomId,
diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml
index 110475c7..e00b91a5 100644
--- a/resources/qml/dialogs/RoomSettings.qml
+++ b/resources/qml/dialogs/RoomSettings.qml
@@ -362,6 +362,18 @@ ApplicationWindow {
Layout.alignment: Qt.AlignRight
}
+ Item {
+ Layout.fillWidth: true
+ visible: roomSettings.isSpace
+ }
+
+ Button {
+ visible: roomSettings.isSpace
+ text: qsTr("Manage space children")
+ Layout.alignment: Qt.AlignRight
+ onClicked: TimelineManager.openSpaceChildren(roomSettings.roomId)
+ }
+
Item {
// for adding extra space between sections
Layout.fillWidth: true
diff --git a/resources/qml/dialogs/SpaceChildren.qml b/resources/qml/dialogs/SpaceChildren.qml
new file mode 100644
index 00000000..63fda3e4
--- /dev/null
+++ b/resources/qml/dialogs/SpaceChildren.qml
@@ -0,0 +1,188 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import ".."
+import QtQuick 2.15
+import QtQuick.Controls 2.3
+import QtQuick.Layouts 1.2
+import QtQuick.Window 2.13
+import im.nheko 1.0
+
+ApplicationWindow {
+ id: spaceChildrenDialog
+
+ property SpaceChildrenModel spaceChildren
+ property NonSpaceChildrenModel nonChildren
+
+ minimumWidth: 340
+ minimumHeight: 450
+ width: 450
+ height: 680
+ palette: Nheko.colors
+ color: Nheko.colors.window
+ modality: Qt.NonModal
+ flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
+ title: qsTr("Space children")
+
+ Shortcut {
+ sequence: StandardKey.Cancel
+ onActivated: spaceChildrenDialog.close()
+ }
+
+ ScrollHelper {
+ flickable: flickable
+ anchors.fill: flickable
+ }
+
+ ColumnLayout {
+ id: contentLayout
+ anchors.fill: parent
+ anchors.margins: Nheko.paddingMedium
+ spacing: Nheko.paddingMedium
+
+ Label {
+ color: Nheko.colors.text
+ horizontalAlignment: Label.AlignHCenter
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ text: qsTr("Children of %1").arg(spaceChildren.space.roomName)
+ wrapMode: Text.Wrap
+ font.pointSize: fontMetrics.font.pointSize * 1.5
+ }
+
+ ListView {
+ id: childrenList
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ model: spaceChildren
+ spacing: Nheko.paddingMedium
+ clip: true
+
+ ScrollHelper {
+ flickable: parent
+ anchors.fill: parent
+ }
+
+ delegate: RowLayout {
+ id: childDel
+
+ required property string id
+ required property string roomName
+ required property string avatarUrl
+ required property string alias
+
+ spacing: Nheko.paddingMedium
+ width: ListView.view.width
+
+ Avatar {
+ Layout.alignment: Qt.AlignVCenter
+ Layout.rightMargin: Nheko.paddingMedium
+ width: Nheko.avatarSize
+ height: Nheko.avatarSize
+ url: childDel.avatarUrl.replace("mxc://", "image://MxcImage/")
+ roomid: childDel.id
+ displayName: childDel.roomName
+ }
+
+ ColumnLayout {
+ spacing: Nheko.paddingMedium
+
+ Label {
+ font.bold: true
+ text: childDel.roomName
+ }
+
+ Label {
+ text: childDel.alias
+ visible: childDel.alias
+ color: Nheko.inactiveColors.text
+ }
+ }
+
+ Item { Layout.fillWidth: true }
+
+ ImageButton {
+ image: ":/icons/icons/ui/delete.svg"
+ onClicked: Nheko.removeRoomFromSpace(childDel.id, spaceChildren.space.roomId)
+ }
+ }
+ }
+
+ Label {
+ color: Nheko.colors.text
+ horizontalAlignment: Label.AlignHCenter
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ text: qsTr("Add rooms to %1").arg(spaceChildren.space.roomName)
+ wrapMode: Text.Wrap
+ font.pointSize: fontMetrics.font.pointSize * 1.5
+ }
+
+ ListView {
+ id: nonChildrenList
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ model: nonChildren
+ spacing: Nheko.paddingMedium
+ clip: true
+
+ ScrollHelper {
+ flickable: parent
+ anchors.fill: parent
+ }
+
+ delegate: RowLayout {
+ id: nonChildDel
+
+ required property string id
+ required property string roomName
+ required property string avatarUrl
+ required property string alias
+
+ spacing: Nheko.paddingMedium
+ width: ListView.view.width
+
+ Avatar {
+ Layout.alignment: Qt.AlignVCenter
+ Layout.rightMargin: Nheko.paddingMedium
+ width: Nheko.avatarSize
+ height: Nheko.avatarSize
+ url: nonChildDel.avatarUrl.replace("mxc://", "image://MxcImage/")
+ roomid: nonChildDel.id
+ displayName: nonChildDel.roomName
+ }
+
+ ColumnLayout {
+ spacing: Nheko.paddingMedium
+
+ Label {
+ font.bold: true
+ text: nonChildDel.roomName
+ }
+
+ Label {
+ text: nonChildDel.alias
+ visible: nonChildDel.alias
+ color: Nheko.inactiveColors.text
+ }
+ }
+
+ Item { Layout.fillWidth: true }
+
+ ImageButton {
+ image: ":/icons/icons/ui/add-square-button.svg"
+ onClicked: Nheko.addRoomToSpace(nonChildDel.id, spaceChildren.space.roomId)
+ }
+ }
+ }
+ }
+
+ footer: DialogButtonBox {
+ standardButtons: DialogButtonBox.Ok
+ onAccepted: close()
+ }
+}
diff --git a/resources/res.qrc b/resources/res.qrc
index 3ce63f42..0ccaad8c 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -177,6 +177,7 @@
qml/voip/PlaceCall.qml
qml/voip/ScreenShare.qml
qml/voip/VideoCall.qml
+ qml/dialogs/SpaceChildren.qml
media/ring.ogg
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index ccaf2926..d41972d6 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -747,6 +747,45 @@ ChatPage::joinRoomVia(const std::string &room_id,
reason.toStdString());
}
+void
+ChatPage::addRoomToSpace(const QString &roomId, const QString &spaceId)
+{
+ // Make sure that the user isn't trying to create an infinite loop. Granted, this is not
+ // perfect, since you could have a loop of the form "a => b => a => ...", but this is sufficient
+ // for now.
+ if (roomId == spaceId)
+ return;
+
+ mtx::events::state::space::Child child;
+ child.via = {roomId.splitRef(QStringLiteral(":")).last().toString().toStdString()};
+ http::client()->send_state_event(
+ roomId.toStdString(),
+ child,
+ [this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ if (err) {
+ emit showNotification(tr("Failed to add room to space: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ }
+ });
+}
+
+void
+ChatPage::removeRoomFromSpace(const QString &roomId, const QString &spaceId)
+{
+ auto childEvent = cache::client()->getStateEvent(
+ spaceId.toStdString(), "m.space.child");
+ if (childEvent.has_value())
+ http::client()->redact_event(
+ roomId.toStdString(),
+ childEvent->event_id,
+ [this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ if (err) {
+ emit showNotification(tr("Failed to remove room from space: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ }
+ });
+}
+
void
ChatPage::createRoom(const mtx::requests::CreateRoom &req)
{
diff --git a/src/ChatPage.h b/src/ChatPage.h
index 2673a3de..131db288 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -94,6 +94,9 @@ public slots:
bool promptForConfirmation = true,
const QString &reason = "");
+ void addRoomToSpace(const QString &roomId, const QString &spaceId);
+ void removeRoomFromSpace(const QString &roomId, const QString &spaceId);
+
void inviteUser(QString userid, QString reason);
void kickUser(QString userid, QString reason);
void banUser(QString userid, QString reason);
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index ffc3c6c1..9f9dfa91 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -34,6 +34,7 @@
#include "RoomDirectoryModel.h"
#include "RoomsModel.h"
#include "SingleImagePackModel.h"
+#include "SpaceChildrenModel.h"
#include "TrayIcon.h"
#include "UserSettingsPage.h"
#include "UsersModel.h"
@@ -212,6 +213,18 @@ MainWindow::registerQmlTypes()
0,
"SingleImagePackModel",
QStringLiteral("SingleImagePackModel needs to be instantiated on the C++ side"));
+ qmlRegisterUncreatableType(
+ "im.nheko",
+ 1,
+ 0,
+ "SpaceChildrenModel",
+ "SpaceChildrenModel needs to be instantiated on the C++ side");
+ qmlRegisterUncreatableType(
+ "im.nheko",
+ 1,
+ 0,
+ "NonSpaceChildrenModel",
+ "NonSpaceChildrenModel needs to be instantiated on the C++ side");
qmlRegisterUncreatableType(
"im.nheko",
1,
diff --git a/src/SpaceChildrenModel.cpp b/src/SpaceChildrenModel.cpp
new file mode 100644
index 00000000..f71aa0dd
--- /dev/null
+++ b/src/SpaceChildrenModel.cpp
@@ -0,0 +1,106 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "SpaceChildrenModel.h"
+
+#include "Cache.h"
+#include "Cache_p.h"
+
+SpaceChildrenModel::SpaceChildrenModel(QSharedPointer space, QObject *parent)
+ : QAbstractListModel{parent}
+ , m_space{space}
+{
+ auto joinedRooms = cache::joinedRooms();
+ for (const auto &child : cache::client()->getChildRoomIds(m_space->roomId().toStdString())) {
+ m_childIds.push_back(QString::fromStdString(child));
+
+ if (std::find(std::begin(joinedRooms), std::end(joinedRooms), child) !=
+ std::end(joinedRooms))
+ m_childInfos.push_back(cache::singleRoomInfo(child));
+ else // TODO: replace with code to fetch a non-joined room
+ m_childInfos.push_back(cache::singleRoomInfo(child));
+ }
+}
+
+QHash
+SpaceChildrenModel::roleNames() const
+{
+ return {{Roles::Id, "id"},
+ {Roles::RoomName, "roomName"},
+ {Roles::AvatarUrl, "avatarUrl"},
+ {Roles::Alias, "alias"}};
+}
+
+QVariant
+SpaceChildrenModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= (int)m_childIds.size() || index.row() < 0)
+ return {};
+
+ switch (role) {
+ case Roles::Id:
+ return m_childIds[index.row()];
+ case Roles::RoomName:
+ return QString::fromStdString(m_childInfos[index.row()].name);
+ case Roles::AvatarUrl:
+ return QString::fromStdString(m_childInfos[index.row()].avatar_url);
+ case Roles::Alias: {
+ auto aliases = cache::client()->getRoomAliases(m_childIds[index.row()].toStdString());
+ if (aliases.has_value())
+ return QString::fromStdString(aliases->alias);
+ else
+ return {};
+ }
+ default:
+ return {};
+ }
+}
+
+NonSpaceChildrenModel::NonSpaceChildrenModel(QSharedPointer space, QObject *parent)
+ : QAbstractListModel{parent}
+ , m_space{space}
+{
+ auto children = cache::client()->getChildRoomIds(m_space->roomId().toStdString());
+ for (const auto &room : cache::joinedRooms()) {
+ if (room == space->roomId().toStdString() ||
+ std::find(std::begin(children), std::end(children), room) == std::end(children)) {
+ m_roomIds.push_back(QString::fromStdString(room));
+ m_roomInfos.push_back(cache::singleRoomInfo(room));
+ }
+ }
+}
+
+QHash
+NonSpaceChildrenModel::roleNames() const
+{
+ return {{Roles::Id, "id"},
+ {Roles::RoomName, "roomName"},
+ {Roles::AvatarUrl, "avatarUrl"},
+ {Roles::Alias, "alias"}};
+}
+
+QVariant
+NonSpaceChildrenModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= (int)m_roomIds.size() || index.row() < 0)
+ return {};
+
+ switch (role) {
+ case Roles::Id:
+ return m_roomIds[index.row()];
+ case Roles::RoomName:
+ return QString::fromStdString(m_roomInfos[index.row()].name);
+ case Roles::AvatarUrl:
+ return QString::fromStdString(m_roomInfos[index.row()].avatar_url);
+ case Roles::Alias: {
+ auto aliases = cache::client()->getRoomAliases(m_roomIds[index.row()].toStdString());
+ if (aliases.has_value())
+ return QString::fromStdString(aliases->alias);
+ else
+ return {};
+ }
+ default:
+ return {};
+ }
+}
diff --git a/src/SpaceChildrenModel.h b/src/SpaceChildrenModel.h
new file mode 100644
index 00000000..1fce5aa4
--- /dev/null
+++ b/src/SpaceChildrenModel.h
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef SPACECHILDRENMODEL_H
+#define SPACECHILDRENMODEL_H
+
+#include
+#include
+
+#include "timeline/TimelineModel.h"
+
+class SpaceChildrenModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(TimelineModel *space READ space CONSTANT)
+
+public:
+ enum Roles
+ {
+ Id,
+ RoomName,
+ AvatarUrl,
+ Alias,
+ };
+
+ explicit SpaceChildrenModel(QSharedPointer space, QObject *parent = nullptr);
+
+ TimelineModel *space() const { return m_space.data(); }
+
+ int rowCount(const QModelIndex &parent) const override
+ {
+ Q_UNUSED(parent);
+ return m_childIds.size();
+ }
+ QHash roleNames() const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+private:
+ QSharedPointer m_space;
+ QStringList m_childIds;
+ QList m_childInfos;
+};
+
+class NonSpaceChildrenModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(TimelineModel *space READ space CONSTANT)
+
+public:
+ enum Roles
+ {
+ Id,
+ RoomName,
+ AvatarUrl,
+ Alias,
+ };
+
+ explicit NonSpaceChildrenModel(QSharedPointer space, QObject *parent = nullptr);
+
+ TimelineModel *space() const { return m_space.data(); }
+
+ int rowCount(const QModelIndex &parent) const override
+ {
+ Q_UNUSED(parent);
+ return m_roomIds.size();
+ }
+ QHash roleNames() const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+private:
+ QSharedPointer m_space;
+ QStringList m_roomIds;
+ QList m_roomInfos;
+};
+
+#endif // SPACECHILDRENMODEL_H
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 3bccd8f3..4e2401e8 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -180,6 +180,16 @@ TimelineViewManager::openRoomSettings(QString room_id)
emit openRoomSettingsDialog(settings);
}
+void
+TimelineViewManager::openSpaceChildren(const QString &spaceId)
+{
+ auto children = new SpaceChildrenModel{rooms_->getRoomById(spaceId)};
+ auto nonChildren = new NonSpaceChildrenModel{rooms_->getRoomById(spaceId)};
+ QQmlEngine::setObjectOwnership(children, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(nonChildren, QQmlEngine::JavaScriptOwnership);
+ emit openSpaceChildrenDialog(children, nonChildren);
+}
+
void
TimelineViewManager::openInviteUsers(QString roomId)
{
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 08943e8c..207824ec 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -17,6 +17,7 @@
#include "Cache.h"
#include "JdenticonProvider.h"
#include "Logging.h"
+#include "SpaceChildrenModel.h"
#include "TimelineModel.h"
#include "Utils.h"
#include "emoji/EmojiModel.h"
@@ -65,6 +66,7 @@ public:
Q_INVOKABLE void openRoomMembers(TimelineModel *room);
Q_INVOKABLE void openRoomSettings(QString room_id);
+ Q_INVOKABLE void openSpaceChildren(const QString &spaceId);
Q_INVOKABLE void openInviteUsers(QString roomId);
Q_INVOKABLE void openGlobalUserProfile(QString userId);
Q_INVOKABLE UserProfile *getGlobalUserProfile(QString userId);
@@ -86,6 +88,7 @@ signals:
void focusInput();
void openRoomMembersDialog(MemberList *members, TimelineModel *room);
void openRoomSettingsDialog(RoomSettings *settings);
+ void openSpaceChildrenDialog(SpaceChildrenModel *children, NonSpaceChildrenModel *nonChildren);
void openInviteUsersDialog(InviteesModel *invitees);
void openProfile(UserProfile *profile);
void showImagePackSettings(TimelineModel *room, ImagePackListModel *packlist);
diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp
index 9ffbb666..25d6465e 100644
--- a/src/ui/NhekoGlobalObject.cpp
+++ b/src/ui/NhekoGlobalObject.cpp
@@ -128,7 +128,12 @@ Nheko::logout() const
}
void
-Nheko::createRoom(QString name, QString topic, QString aliasLocalpart, bool isEncrypted, bool isSpace, int preset)
+Nheko::createRoom(QString name,
+ QString topic,
+ QString aliasLocalpart,
+ bool isEncrypted,
+ bool isSpace,
+ int preset)
{
mtx::requests::CreateRoom req;
@@ -156,9 +161,21 @@ Nheko::createRoom(QString name, QString topic, QString aliasLocalpart, bool isEn
}
if (isSpace) {
- req.creation_content = mtx::events::state::Create{};
+ req.creation_content = mtx::events::state::Create{};
req.creation_content->type = "m.space";
}
emit ChatPage::instance()->createRoom(req);
}
+
+void
+Nheko::addRoomToSpace(const QString &roomId, const QString &spaceId)
+{
+ ChatPage::instance()->addRoomToSpace(roomId, spaceId);
+}
+
+void
+Nheko::removeRoomFromSpace(const QString &roomId, const QString &spaceId)
+{
+ ChatPage::instance()->removeRoomFromSpace(roomId, spaceId);
+}
diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h
index 9e1cbd7e..742a5d93 100644
--- a/src/ui/NhekoGlobalObject.h
+++ b/src/ui/NhekoGlobalObject.h
@@ -52,8 +52,14 @@ public:
Q_INVOKABLE void setStatusMessage(QString msg) const;
Q_INVOKABLE void showUserSettingsPage() const;
Q_INVOKABLE void logout() const;
- Q_INVOKABLE void
- createRoom(QString name, QString topic, QString aliasLocalpart, bool isEncrypted, bool isSpace, int preset);
+ Q_INVOKABLE void createRoom(QString name,
+ QString topic,
+ QString aliasLocalpart,
+ bool isEncrypted,
+ bool isSpace,
+ int preset);
+ Q_INVOKABLE void addRoomToSpace(const QString &roomId, const QString &spaceId);
+ Q_INVOKABLE void removeRoomFromSpace(const QString &roomId, const QString &spaceId);
public slots:
void updateUserProfile();
diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp
index 42db1955..12dc48fa 100644
--- a/src/ui/RoomSettings.cpp
+++ b/src/ui/RoomSettings.cpp
@@ -243,6 +243,19 @@ RoomSettings::canChangeAvatar() const
return false;
}
+bool
+RoomSettings::canSetSpaceChild() const
+{
+ try {
+ return cache::hasEnoughPowerLevel(
+ {EventType::SpaceChild}, roomid_.toStdString(), utils::localUser().toStdString());
+ } catch (const lmdb::error &e) {
+ nhlog::db()->warn("lmdb error: {}", e.what());
+ }
+
+ return false;
+}
+
bool
RoomSettings::isEncryptionEnabled() const
{
diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h
index 9912cfd6..7710941a 100644
--- a/src/ui/RoomSettings.h
+++ b/src/ui/RoomSettings.h
@@ -37,6 +37,7 @@ class RoomSettings : public QObject
Q_PROPERTY(QString plainRoomName READ plainRoomName NOTIFY roomNameChanged)
Q_PROPERTY(QString plainRoomTopic READ plainRoomTopic NOTIFY roomTopicChanged)
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged)
+ Q_PROPERTY(bool isSpace READ isSpace CONSTANT)
Q_PROPERTY(int memberCount READ memberCount CONSTANT)
Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged)
Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged)
@@ -45,6 +46,7 @@ class RoomSettings : public QObject
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
Q_PROPERTY(bool canChangeName READ canChangeName CONSTANT)
Q_PROPERTY(bool canChangeTopic READ canChangeTopic CONSTANT)
+ Q_PROPERTY(bool canSetSpaceChild READ canSetSpaceChild CONSTANT)
Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged)
Q_PROPERTY(bool supportsKnocking READ supportsKnocking CONSTANT)
Q_PROPERTY(bool supportsRestricted READ supportsRestricted CONSTANT)
@@ -59,6 +61,7 @@ public:
QString plainRoomTopic() const;
QString roomVersion() const;
QString roomAvatarUrl();
+ bool isSpace() const { return info_.is_space; }
int memberCount() const;
int notifications();
int accessJoinRules();
@@ -71,6 +74,8 @@ public:
bool canChangeTopic() const;
//! Whether the user has enough power level to send m.room.avatar event.
bool canChangeAvatar() const;
+ //! Whether the user has enough power level to add children to a space.
+ bool canSetSpaceChild() const;
bool isEncryptionEnabled() const;
bool supportsKnocking() const;
bool supportsRestricted() const;