Page MenuHomePhorge

D222.1751253742.diff
No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None

D222.1751253742.diff

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

Mime Type
text/plain
Expires
Sun, Jun 29, 8:22 PM (12 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
239631
Default Alt Text
D222.1751253742.diff (13 KB)

Event Timeline