Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2595771
D222.1751279146.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D222.1751279146.diff
View Options
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -43,6 +43,7 @@
matrix-room-pinned-events-timeline.cpp
matrix-room-member.cpp
matrix-room-member-list-model.cpp
+ matrix-room-state.cpp
matrix-event-reader.cpp
matrix-event-reader-list-model.cpp
matrix-event-reaction-list-model.cpp
@@ -219,6 +220,7 @@
room-settings/RoomInvitePage.qml
room-settings/RoomStickerPacksPage.qml
room-settings/RoomStickerPackItemDelegate.qml
+ room-settings/RoomStatePage.qml
device-mgmt/Device.qml
device-mgmt/DeviceList.qml
diff --git a/src/contents/ui/Main.qml b/src/contents/ui/Main.qml
--- a/src/contents/ui/Main.qml
+++ b/src/contents/ui/Main.qml
@@ -239,6 +239,12 @@
});
}
+ function activateRoomStatePage(room) {
+ pageStack.push(Qt.resolvedUrl("room-settings/RoomStatePage.qml"), {
+ room
+ });
+ }
+
function activateUserPage(user, room, userId) {
pageStack.push(Qt.resolvedUrl("UserPage.qml"), {
userId: userId || user.userId,
diff --git a/src/contents/ui/room-settings/RoomSettingsPage.qml b/src/contents/ui/room-settings/RoomSettingsPage.qml
--- a/src/contents/ui/room-settings/RoomSettingsPage.qml
+++ b/src/contents/ui/room-settings/RoomSettingsPage.qml
@@ -356,6 +356,14 @@
}
}
+ Button {
+ text: l10n.get('room-explore-state-action')
+ Layout.fillWidth: true
+ onClicked: {
+ activateRoomStatePage(roomSettingsPage.room);
+ }
+ }
+
Button {
objectName: 'leaveRoomButton'
text: l10n.get('room-leave-action')
diff --git a/src/contents/ui/room-settings/RoomStatePage.qml b/src/contents/ui/room-settings/RoomStatePage.qml
new file mode 100644
--- /dev/null
+++ b/src/contents/ui/room-settings/RoomStatePage.qml
@@ -0,0 +1,71 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2025 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import org.kde.kirigami as Kirigami
+import moe.kazv.mxc.kazv 0.0 as MK
+import '../matrix-helpers.js' as Helpers
+import '..' as Kazv
+
+Kazv.ClosableScrollablePage {
+ id: roomStatePage
+ property var room
+ property var roomNameProvider: Kazv.RoomNameProvider {
+ room: roomStatePage.room
+ }
+ property var roomDisplayName: roomNameProvider.name
+ property var allState: room.allState()
+ property string selectedType: ''
+ title: l10n.get('room-state-page-title', { room: roomDisplayName })
+
+ ColumnLayout {
+ Flow {
+ id: typeChooser
+ Layout.fillWidth: true
+ Repeater {
+ model: allState.types
+ Kirigami.Chip {
+ required property string modelData
+ objectName: `chip_${modelData}`
+ closable: false
+ text: modelData
+ checkable: true
+ checked: roomStatePage.selectedType === modelData
+ onClicked: {
+ roomStatePage.selectedType = modelData
+ }
+ }
+ }
+ }
+
+ ListView {
+ id: lv
+ objectName: 'stateEventList'
+ model: allState.eventsForType(roomStatePage.selectedType)
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.minimumHeight: childrenRect.height
+ delegate: ColumnLayout {
+ id: viewItem
+ property var event: lv.model.at(index)
+ width: ListView.view.width
+ Label {
+ Layout.fillWidth: true
+ textFormat: Qt.RichText
+ text: l10n.get('room-state-page-state-key', { stateKey: MK.KazvUtil.escapeHtml(viewItem.event.stateKey) })
+ }
+ Kazv.EventViewWrapper {
+ event: viewItem.event
+ Layout.fillWidth: true
+ compactMode: false
+ displayTime: false
+ }
+ }
+ }
+ }
+}
diff --git a/src/l10n/cmn-Hans/100-ui.ftl b/src/l10n/cmn-Hans/100-ui.ftl
--- a/src/l10n/cmn-Hans/100-ui.ftl
+++ b/src/l10n/cmn-Hans/100-ui.ftl
@@ -381,6 +381,10 @@
room-invite-page-invite-button = 邀请
room-invite-action = 邀请到房间...
+room-explore-state-action = 查看完整房间状态...
+room-state-page-title = { $room } 的状态
+room-state-page-state-key = 状态键:「<code>{ $stateKey }</code>」
+
confirm-upload-popup-title = 确认上传
confirm-upload-popup-prompt = 即将上传「{ $file }」({ $current } / { $total })。
confirm-upload-popup-prompt-single-file = 即将上传「{ $file }」。
diff --git a/src/l10n/en/100-ui.ftl b/src/l10n/en/100-ui.ftl
--- a/src/l10n/en/100-ui.ftl
+++ b/src/l10n/en/100-ui.ftl
@@ -403,6 +403,10 @@
room-invite-page-invite-button = Invite
room-invite-action = Invite to room...
+room-explore-state-action = View full room state...
+room-state-page-title = Room state of { $room }
+room-state-page-state-key = State key: "<code>{ $stateKey }</code>"
+
confirm-upload-popup-title = Confirm upload
confirm-upload-popup-prompt = You are about to upload "{ $file }" ({ $current } / { $total }).
confirm-upload-popup-prompt-single-file = You are about to upload "{ $file }".
diff --git a/src/matrix-room-state.hpp b/src/matrix-room-state.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-room-state.hpp
@@ -0,0 +1,33 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2025 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include <QObject>
+#include <QQmlEngine>
+#include <lager/extra/qt.hpp>
+#include <room/room.hpp>
+#include "kazv-abstract-list-model.hpp"
+Q_MOC_INCLUDE("matrix-event-list.hpp")
+
+class MatrixEventList;
+
+class MatrixRoomState : public KazvAbstractListModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+
+ lager::reader<immer::map<Kazv::KeyOfState, Kazv::Event>> m_state;
+
+public:
+ explicit MatrixRoomState(lager::reader<immer::map<Kazv::KeyOfState, Kazv::Event>> state, QObject *parent = 0);
+ ~MatrixRoomState() override;
+
+ LAGER_QT_READER(QStringList, types);
+
+ Q_INVOKABLE MatrixEventList *eventsForType(const QString &type) const;
+};
diff --git a/src/matrix-room-state.cpp b/src/matrix-room-state.cpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-room-state.cpp
@@ -0,0 +1,45 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2025 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <kazv-defs.hpp>
+#include "matrix-room-state.hpp"
+#include "matrix-event-list.hpp"
+
+using namespace Kazv;
+
+MatrixRoomState::MatrixRoomState(lager::reader<immer::map<KeyOfState, Event>> state, QObject *parent)
+ : KazvAbstractListModel(parent)
+ , m_state(state)
+ , LAGER_QT(types)(m_state.map([](const immer::map<KeyOfState, Event> &s) {
+ QStringList res;
+ for (const auto &[k, v] : s) {
+ auto type = QString::fromStdString(k.type);
+ if (std::find(res.cbegin(), res.cend(), type) == res.cend()) {
+ res.push_back(type);
+ }
+ }
+ return res;
+ }))
+{
+ initCountCursor(LAGER_QT(types).map([](const QStringList &l) {
+ return static_cast<int>(l.size());
+ }));
+}
+
+MatrixRoomState::~MatrixRoomState() = default;
+
+MatrixEventList *MatrixRoomState::eventsForType(const QString &type) const
+{
+ return new MatrixEventList(m_state.map([wantedType=type.toStdString()](const immer::map<KeyOfState, Event> &s) {
+ EventList res;
+ for (const auto &[k, v] : s) {
+ if (k.type == wantedType) {
+ res = std::move(res).push_back(v);
+ }
+ }
+ return res;
+ }));
+}
diff --git a/src/matrix-room.hpp b/src/matrix-room.hpp
--- a/src/matrix-room.hpp
+++ b/src/matrix-room.hpp
@@ -18,6 +18,7 @@
Q_MOC_INCLUDE("matrix-room-timeline.hpp")
Q_MOC_INCLUDE("matrix-room-pinned-events-timeline.hpp")
Q_MOC_INCLUDE("matrix-sticker-pack-list.hpp")
+Q_MOC_INCLUDE("matrix-room-state.hpp")
class MatrixRoomTimeline;
class MatrixRoomPinnedEventsTimeline;
@@ -26,6 +27,7 @@
class MatrixRoomMemberListModel;
class MatrixEvent;
class MatrixStickerPackList;
+class MatrixRoomState;
nlohmann::json makeTextMessageJson(const QString &text, const QString &relType, const QString &relatedTo, Kazv::Event replyToEvent);
@@ -73,6 +75,8 @@
Q_INVOKABLE MatrixRoomMember *member(QString userId) const;
+ Q_INVOKABLE MatrixRoomState *allState() const;
+
Q_INVOKABLE MatrixEvent *state(const QString &type, const QString &stateKey) const;
Q_INVOKABLE MatrixRoomTimeline *timeline() const;
diff --git a/src/matrix-room.cpp b/src/matrix-room.cpp
--- a/src/matrix-room.cpp
+++ b/src/matrix-room.cpp
@@ -21,6 +21,7 @@
#include "matrix-room-pinned-events-timeline.hpp"
#include "matrix-room-member.hpp"
#include "matrix-room-member-list-model.hpp"
+#include "matrix-room-state.hpp"
#include "matrix-promise.hpp"
#include "matrix-event.hpp"
#include "matrix-sticker-pack-list.hpp"
@@ -415,6 +416,11 @@
return new MatrixRoomMember(m_room.memberEventFor(userId.toStdString()));
}
+MatrixRoomState *MatrixRoom::allState() const
+{
+ return new MatrixRoomState(m_room.stateEvents());
+}
+
MatrixEvent *MatrixRoom::state(const QString &type, const QString &stateKey) const
{
return new MatrixEvent(m_room.state({type.toStdString(), stateKey.toStdString()}));
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -24,6 +24,7 @@
matrix-room-timeline-test.cpp
matrix-room-member-list-model-test.cpp
matrix-room-list-test.cpp
+ matrix-room-state-test.cpp
kazv-markdown-test.cpp
matrix-sticker-pack-test.cpp
matrix-link-test.cpp
diff --git a/src/tests/matrix-room-state-test.cpp b/src/tests/matrix-room-state-test.cpp
new file mode 100644
--- /dev/null
+++ b/src/tests/matrix-room-state-test.cpp
@@ -0,0 +1,57 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2025 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <kazv-defs.hpp>
+#include <matrix-room-state.hpp>
+#include <memory>
+#include <QtTest>
+#include <factory.hpp>
+#include <matrix-sdk.hpp>
+#include <matrix-room-list.hpp>
+#include <matrix-room.hpp>
+#include <matrix-event-list.hpp>
+#include "test-model.hpp"
+#include "test-utils.hpp"
+
+using namespace Qt::Literals::StringLiterals;
+using namespace Kazv;
+using namespace Kazv::Factory;
+
+class MatrixRoomStateTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testSimple();
+};
+
+void MatrixRoomStateTest::testSimple()
+{
+ auto state = EventList{
+ makeMemberEvent(),
+ makeMemberEvent(),
+ makeEvent(withEventType("m.room.name") | withStateKey("")),
+ makeEvent(withEventType("moe.kazv.mxc.foo") | withStateKey("a")),
+ };
+
+ auto r = makeRoom(withRoomState(state));
+ auto c = makeClient(withRoom(r));
+
+ std::unique_ptr<MatrixSdk> sdk{makeTestSdk(SdkModel{c})};
+ auto roomList = toUniquePtr(sdk->roomList());
+ auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
+ auto allState = toUniquePtr(room->allState());
+
+ QCOMPARE(allState->count(), 3);
+ auto members = toUniquePtr(allState->eventsForType(u"m.room.member"_s));
+ QCOMPARE(members->count(), 2);
+ auto names = toUniquePtr(allState->eventsForType(u"m.room.name"_s));
+ QCOMPARE(names->count(), 1);
+}
+
+QTEST_MAIN(MatrixRoomStateTest)
+
+#include "matrix-room-state-test.moc"
diff --git a/src/tests/quick-tests/tst_RoomStatePage.qml b/src/tests/quick-tests/tst_RoomStatePage.qml
new file mode 100644
--- /dev/null
+++ b/src/tests/quick-tests/tst_RoomStatePage.qml
@@ -0,0 +1,62 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2025 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick
+import QtQuick.Layouts
+import QtTest
+import '../../contents/ui' as Kazv
+import '../../contents/ui/room-settings' as KazvRS
+import './test-helpers' as QmlHelpers
+import 'test-helpers.js' as JsHelpers
+import moe.kazv.mxc.kazv as MK
+
+QmlHelpers.TestItem {
+ id: upper
+
+ property var stateObj: QtObject {
+ property var types: ['m.room.member', 'm.room.create']
+ property var events: {
+ 'm.room.member': [{ stateKey: '@foo:example.org' }, { stateKey: '@bar:example.org' }],
+ 'm.room.create': [{ stateKey: '' }],
+ }
+
+ function eventsForType(type) {
+ return events[type];
+ }
+ }
+ property var room: QtObject {
+ property var membership: MK.MatrixRoom.Join
+ function allState() {
+ return upper.stateObj;
+ }
+ }
+
+ KazvRS.RoomStatePage {
+ id: roomStatePage
+ room: upper.room
+ anchors.fill: parent
+ }
+
+ TestCase {
+ id: roomStatePageTest
+ name: 'RoomStatePageTest'
+ when: windowShown
+
+ function test_simple() {
+ const createChip = findChild(roomStatePage, 'chip_m.room.create');
+ const memberChip = findChild(roomStatePage, 'chip_m.room.member');
+ const eventList = findChild(roomStatePage, 'stateEventList');
+ verify(createChip);
+ verify(memberChip);
+ mouseClick(createChip);
+ verify(createChip.checked);
+ compare(eventList.count, 1);
+ mouseClick(memberChip);
+ verify(memberChip.checked);
+ compare(eventList.count, 2);
+ }
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jun 30, 3:25 AM (16 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
239631
Default Alt Text
D222.1751279146.diff (13 KB)
Attached To
Mode
D222: Implement exploring full room state
Attached
Detach File
Event Timeline
Log In to Comment