diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp
index 7b267bcb..6d60c2b9 100644
--- a/src/timeline/CommunitiesModel.cpp
+++ b/src/timeline/CommunitiesModel.cpp
@@ -5,20 +5,29 @@
#include "CommunitiesModel.h"
+#include <mtx/responses/common.hpp>
#include <set>
#include "Cache.h"
#include "Cache_p.h"
#include "ChatPage.h"
#include "Logging.h"
+#include "MatrixClient.h"
+#include "Permissions.h"
#include "UserSettingsPage.h"
#include "Utils.h"
+#include "timeline/TimelineModel.h"
+
+Q_DECLARE_METATYPE(SpaceItem)
CommunitiesModel::CommunitiesModel(QObject *parent)
: QAbstractListModel(parent)
, hiddenTagIds_{UserSettings::instance()->hiddenTags()}
, mutedTagIds_{UserSettings::instance()->mutedTags()}
-{}
+{
+ static auto ignore = qRegisterMetaType<SpaceItem>();
+ (void)ignore;
+}
QHash<int, QByteArray>
CommunitiesModel::roleNames() const
@@ -723,3 +732,156 @@ FilteredCommunitiesModel::filterAcceptsRow(int sourceRow, const QModelIndex &) c
return true;
}
+
+QVariantList
+CommunitiesModel::spaceChildrenListFromIndex(QString room, int idx) const
+{
+ if (idx < -1)
+ return {};
+
+ auto room_ = room.toStdString();
+
+ int begin = idx + 1;
+ int end = idx >= 0 ? this->spaceOrder_.lastChild(idx) + 1 : this->spaceOrder_.size();
+ QVariantList ret;
+
+ bool canSendParent = Permissions(room).canChange(qml_mtx_events::SpaceParent);
+
+ for (int i = begin; i < end; i++) {
+ const auto &e = spaceOrder_.tree[i];
+ if (e.depth == spaceOrder_.tree[begin].depth && spaces_.count(e.id)) {
+ bool canSendChild = Permissions(e.id).canChange(qml_mtx_events::SpaceChild);
+ auto spaceId = e.id.toStdString();
+ auto child =
+ cache::client()->getStateEvent<mtx::events::state::space::Child>(spaceId, room_);
+ auto parent =
+ cache::client()->getStateEvent<mtx::events::state::space::Parent>(room_, spaceId);
+
+ bool childValid =
+ child && !child->content.via.value_or(std::vector<std::string>{}).empty();
+ bool parentValid =
+ parent && !parent->content.via.value_or(std::vector<std::string>{}).empty();
+ bool canonical = parent && parent->content.canonical;
+
+ if (e.id == room) {
+ canonical = parentValid = childValid = canSendChild = canSendParent = false;
+ }
+
+ ret.push_back(
+ QVariant::fromValue(SpaceItem(e.id,
+ QString::fromStdString(spaces_.at(e.id).name),
+ i,
+ childValid,
+ parentValid,
+ canonical,
+ canSendChild,
+ canSendParent)));
+ }
+ }
+
+ nhlog::ui()->critical("Returning {} spaces", ret.size());
+ return ret;
+}
+
+void
+CommunitiesModel::updateSpaceStatus(QString space,
+ QString room,
+ bool setParent,
+ bool setChild,
+ bool canonical) const
+{
+ nhlog::ui()->critical("Setting space {} children {}: {} {} {}",
+ space.toStdString(),
+ room.toStdString(),
+ setParent,
+ setChild,
+ canonical);
+ auto child =
+ cache::client()
+ ->getStateEvent<mtx::events::state::space::Child>(space.toStdString(), room.toStdString())
+ .value_or(mtx::events::StateEvent<mtx::events::state::space::Child>{})
+ .content;
+ auto parent =
+ cache::client()
+ ->getStateEvent<mtx::events::state::space::Parent>(room.toStdString(), space.toStdString())
+ .value_or(mtx::events::StateEvent<mtx::events::state::space::Parent>{})
+ .content;
+
+ if (setChild) {
+ if (!child.via || child.via->empty()) {
+ child.via = utils::roomVias(room.toStdString());
+ child.suggested = true;
+
+ http::client()->send_state_event(
+ space.toStdString(),
+ room.toStdString(),
+ child,
+ [space, room](mtx::responses::EventId, mtx::http::RequestErr err) {
+ if (err) {
+ ChatPage::instance()->showNotification(
+ tr("Failed to update space child: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ nhlog::net()->error("Failed to update child {} of {}: {}",
+ room.toStdString(),
+ space.toStdString());
+ }
+ });
+ }
+ } else {
+ if (child.via && !child.via->empty()) {
+ http::client()->send_state_event(
+ space.toStdString(),
+ room.toStdString(),
+ mtx::events::state::space::Child{},
+ [space, room](mtx::responses::EventId, mtx::http::RequestErr err) {
+ if (err) {
+ ChatPage::instance()->showNotification(
+ tr("Failed to delete space child: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ nhlog::net()->error("Failed to delete child {} of {}: {}",
+ room.toStdString(),
+ space.toStdString());
+ }
+ });
+ }
+ }
+
+ if (setParent) {
+ if (!parent.via || parent.via->empty() || canonical != parent.canonical) {
+ parent.via = utils::roomVias(room.toStdString());
+ parent.canonical = canonical;
+
+ http::client()->send_state_event(
+ room.toStdString(),
+ space.toStdString(),
+ parent,
+ [space, room](mtx::responses::EventId, mtx::http::RequestErr err) {
+ if (err) {
+ ChatPage::instance()->showNotification(
+ tr("Failed to update space parent: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ nhlog::net()->error("Failed to update parent {} of {}: {}",
+ space.toStdString(),
+ room.toStdString());
+ }
+ });
+ }
+ } else {
+ if (parent.via && !parent.via->empty()) {
+ http::client()->send_state_event(
+ room.toStdString(),
+ space.toStdString(),
+ mtx::events::state::space::Parent{},
+ [space, room](mtx::responses::EventId, mtx::http::RequestErr err) {
+ if (err) {
+ ChatPage::instance()->showNotification(
+ tr("Failed to delete space parent: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ nhlog::net()->error("Failed to delete parent {} of {}: {}",
+ space.toStdString(),
+ room.toStdString());
+ }
+ });
+ }
+ }
+}
diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h
index 85e65dd7..89f1ed07 100644
--- a/src/timeline/CommunitiesModel.h
+++ b/src/timeline/CommunitiesModel.h
@@ -29,6 +29,47 @@ public:
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
};
+class SpaceItem
+{
+ Q_GADGET
+
+ Q_PROPERTY(QString roomid MEMBER roomid CONSTANT)
+ Q_PROPERTY(QString name MEMBER name CONSTANT)
+ Q_PROPERTY(int treeIndex MEMBER treeIndex CONSTANT)
+
+ Q_PROPERTY(bool childValid MEMBER childValid CONSTANT)
+ Q_PROPERTY(bool parentValid MEMBER parentValid CONSTANT)
+ Q_PROPERTY(bool canonical MEMBER canonical CONSTANT)
+
+ Q_PROPERTY(bool canEditParent MEMBER canEditParent CONSTANT)
+ Q_PROPERTY(bool canEditChild MEMBER canEditChild CONSTANT)
+
+public:
+ SpaceItem() {}
+ SpaceItem(QString roomid_,
+ QString name_,
+ int treeIndex_,
+ bool childValid_,
+ bool parentValid_,
+ bool canonical_,
+ bool canEditChild_,
+ bool canEditParent_)
+ : roomid(std::move(roomid_))
+ , name(std::move(name_))
+ , treeIndex(treeIndex_)
+ , childValid(childValid_)
+ , parentValid(parentValid_)
+ , canonical(canonical_)
+ , canEditParent(canEditParent_)
+ , canEditChild(canEditChild_)
+ {}
+
+ QString roomid, name;
+ int treeIndex = 0;
+ bool childValid = false, parentValid = false, canonical = false;
+ bool canEditParent = false, canEditChild = false;
+};
+
class CommunitiesModel : public QAbstractListModel
{
Q_OBJECT
@@ -125,6 +166,13 @@ public:
return false;
}
+ Q_INVOKABLE QVariantList spaceChildrenListFromIndex(QString room, int idx = -1) const;
+ Q_INVOKABLE void updateSpaceStatus(QString space,
+ QString room,
+ bool setParent,
+ bool setChild,
+ bool canonical) const;
+
public slots:
void initializeSidebar();
void sync(const mtx::responses::Sync &sync_);
@@ -148,6 +196,7 @@ public slots:
}
void toggleTagId(QString tagId);
void toggleTagMute(QString tagId);
+
FilteredCommunitiesModel *filtered() { return new FilteredCommunitiesModel(this, this); }
signals:
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index fe4e7850..03abd3d5 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -546,6 +546,13 @@ RoomlistModel::sync(const mtx::responses::Sync &sync_)
}
}
}
+ for (const auto &e : room.account_data.events) {
+ if (std::holds_alternative<
+ mtx::events::AccountDataEvent<mtx::events::account_data::Tags>>(e)) {
+ if (auto idx = roomidToIndex(qroomid); idx != -1)
+ emit dataChanged(index(idx), index(idx), {Tags});
+ }
+ }
}
for (const auto &[room_id, room] : sync_.rooms.leave) {
|