From 7c60459e1f3dc9f2e3a460a283fd239010cd51c0 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Wed, 1 Jan 2020 15:11:04 +0800 Subject: [PATCH 1/8] Disable settings when user doesnt have enough power level --- .../Spectral/Dialog/RoomSettingsDialog.qml | 51 ++++++++++ include/libQuotient | 2 +- src/spectralroom.cpp | 97 +++++++++++++------ src/spectralroom.h | 3 + 4 files changed, 124 insertions(+), 29 deletions(-) diff --git a/imports/Spectral/Dialog/RoomSettingsDialog.qml b/imports/Spectral/Dialog/RoomSettingsDialog.qml index 4919c751f..b9a216914 100644 --- a/imports/Spectral/Dialog/RoomSettingsDialog.qml +++ b/imports/Spectral/Dialog/RoomSettingsDialog.qml @@ -9,6 +9,11 @@ import Spectral.Setting 0.1 Dialog { property var room + readonly property bool canChangeAvatar: room.canSendState("m.room.avatar") + readonly property bool canChangeName: room.canSendState("m.room.name") + readonly property bool canChangeTopic: room.canSendState("m.room.topic") + readonly property bool canChangeCanonicalAlias: room.canSendState("m.room.canonical_alias") + anchors.centerIn: parent width: 480 @@ -36,6 +41,8 @@ Dialog { circular: true + enabled: canChangeAvatar + onClicked: { var fileDialog = openFileDialog.createObject(ApplicationWindow.overlay) @@ -61,6 +68,8 @@ Dialog { text: room.name placeholderText: "Room Name" + + enabled: canChangeName } AutoTextField { @@ -70,6 +79,8 @@ Dialog { text: room.topic placeholderText: "Room Topic" + + enabled: canChangeTopic } } } @@ -179,6 +190,8 @@ Dialog { Button { Layout.alignment: Qt.AlignRight + visible: canChangeName || canChangeTopic + text: "Save" highlighted: true @@ -216,6 +229,8 @@ Dialog { id: canonicalAliasComboBox + enabled: canChangeCanonicalAlias + model: room.remoteAliases currentIndex: room.remoteAliases.indexOf(room.canonicalAlias) @@ -275,6 +290,42 @@ Dialog { } } } + + RowLayout { + Layout.fillWidth: true + + Label { + Layout.preferredWidth: 100 + Layout.alignment: Qt.AlignTop + + wrapMode: Label.Wrap + text: "Remote Aliases" + color: MPalette.lighter + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + Repeater { + model: { + var localAliases = room.localAliases + var remoteAliases = room.remoteAliases + return remoteAliases.filter(n => !localAliases.includes(n)) + } + + delegate: Label { + width: parent.width + + text: modelData + + font.pixelSize: 12 + color: MPalette.lighter + } + } + } + } } } diff --git a/include/libQuotient b/include/libQuotient index 16d670095..d4034fb12 160000 --- a/include/libQuotient +++ b/include/libQuotient @@ -1 +1 @@ -Subproject commit 16d6700950f5f0ebd71481efd5e1a24f04e3c651 +Subproject commit d4034fb12b189156e135dcf0fb94960a1d8e9be9 diff --git a/src/spectralroom.cpp b/src/spectralroom.cpp index 4906ca0b4..87396c305 100644 --- a/src/spectralroom.cpp +++ b/src/spectralroom.cpp @@ -21,6 +21,7 @@ #include "events/reactionevent.h" #include "events/roommessageevent.h" #include "events/typingevent.h" +#include "events/roompowerlevelsevent.h" #include "jobs/downloadfilejob.h" #include "user.h" #include "utils.h" @@ -487,20 +488,32 @@ void SpectralRoom::postPlainMessage(const QString& text, if (isReply) { const auto& replyEvt = **replyIt; - QJsonObject json{{"msgtype", msgTypeToString(type)}, - {"body", "> <" + replyEvt.senderId() + "> " + - eventToString(replyEvt) + "\n\n" + text}, - {"format", "org.matrix.custom.html"}, - {"m.relates_to", - QJsonObject{{"m.in_reply_to", - QJsonObject{{"event_id", replyEventId}}}}}, - {"formatted_body", - "
In reply to " + replyEvt.senderId() + - "
" + eventToString(replyEvt, Qt::RichText) + - "
" + text.toHtmlEscaped()}}; + // clang-format off + QJsonObject json{ + {"msgtype", msgTypeToString(type)}, + {"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) + "\n\n" + text}, + {"format", "org.matrix.custom.html"}, + {"m.relates_to", + { + {"m.in_reply_to", + { + {"event_id", replyEventId} + } + } + } + }, + {"formatted_body", + "
In reply to " + replyEvt.senderId() + + "
" + eventToString(replyEvt, Qt::RichText) + + "
" + text + } + }; + // clang-format on + postJson("m.room.message", json); return; @@ -521,20 +534,32 @@ void SpectralRoom::postHtmlMessage(const QString& text, if (isReply) { const auto& replyEvt = **replyIt; - QJsonObject json{{"msgtype", msgTypeToString(type)}, - {"body", "> <" + replyEvt.senderId() + "> " + - eventToString(replyEvt) + "\n\n" + text}, - {"format", "org.matrix.custom.html"}, - {"m.relates_to", - QJsonObject{{"m.in_reply_to", - QJsonObject{{"event_id", replyEventId}}}}}, - {"formatted_body", - "
In reply to " + replyEvt.senderId() + - "
" + eventToString(replyEvt, Qt::RichText) + - "
" + html}}; + // clang-format off + QJsonObject json{ + {"msgtype", msgTypeToString(type)}, + {"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) + "\n\n" + text}, + {"format", "org.matrix.custom.html"}, + {"m.relates_to", + { + {"m.in_reply_to", + { + {"event_id", replyEventId} + } + } + } + }, + {"formatted_body", + "
In reply to " + replyEvt.senderId() + + "
" + eventToString(replyEvt, Qt::RichText) + + "
" + html + } + }; + // clang-format on + postJson("m.room.message", json); return; @@ -588,3 +613,19 @@ bool SpectralRoom::containsUser(QString userID) const { return Room::memberJoinState(u) != JoinState::Leave; } + +bool SpectralRoom::canSendEvent(const QString& eventType) const { + auto plEvent = getCurrentState(); + auto pl = plEvent->powerLevelForEvent(eventType); + auto currentPl = plEvent->powerLevelForUser(localUser()->id()); + + return currentPl >= pl; +} + +bool SpectralRoom::canSendState(const QString& eventType) const { + auto plEvent = getCurrentState(); + auto pl = plEvent->powerLevelForState(eventType); + auto currentPl = plEvent->powerLevelForUser(localUser()->id()); + + return currentPl >= pl; +} diff --git a/src/spectralroom.h b/src/spectralroom.h index 8fd0bf8cb..308673502 100644 --- a/src/spectralroom.h +++ b/src/spectralroom.h @@ -75,6 +75,9 @@ class SpectralRoom : public Room { Q_INVOKABLE bool containsUser(QString userID) const; + Q_INVOKABLE bool canSendEvent(const QString& eventType) const; + Q_INVOKABLE bool canSendState(const QString& eventType) const; + private: QString m_cachedInput; QSet highlights; From 9cb8181e234e01a2fb0922ab94cc7a7857681bf1 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Wed, 1 Jan 2020 16:40:20 +0800 Subject: [PATCH 2/8] Fix Linux build. --- include/libQuotient | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libQuotient b/include/libQuotient index d4034fb12..3accf7dfd 160000 --- a/include/libQuotient +++ b/include/libQuotient @@ -1 +1 @@ -Subproject commit d4034fb12b189156e135dcf0fb94960a1d8e9be9 +Subproject commit 3accf7dfd82e8e14a7f90a8debee921f2f428679 From 3544e5441fb0b4291113117bfc0d08a2cff7ccf4 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Wed, 1 Jan 2020 23:13:19 +0800 Subject: [PATCH 3/8] Show mod and admin in user list. --- imports/Spectral/Panel/RoomDrawer.qml | 25 ++++++++++++++++++ src/main.cpp | 1 + src/userlistmodel.cpp | 37 +++++++++++++++++++++++++-- src/userlistmodel.h | 32 +++++++++++++++-------- 4 files changed, 83 insertions(+), 12 deletions(-) diff --git a/imports/Spectral/Panel/RoomDrawer.qml b/imports/Spectral/Panel/RoomDrawer.qml index 48561703e..27714d779 100644 --- a/imports/Spectral/Panel/RoomDrawer.qml +++ b/imports/Spectral/Panel/RoomDrawer.qml @@ -235,6 +235,31 @@ Drawer { text: name color: MPalette.foreground + textFormat: Text.PlainText + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + MaterialIcon { + Layout.preferredWidth: height + Layout.fillHeight: true + + enabled: perm != UserType.Member + + icon: { + if (perm == UserType.Admin) { + return "\ue853" + } + if (perm == UserType.Moderator) { + return "\ue8e8" + } + if (perm == UserType.Muted) { + return "\ue92a" + } + return "" + } + + color: MPalette.lighter } } diff --git a/src/main.cpp b/src/main.cpp index babe5d8d0..c4a89ccc7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -53,6 +53,7 @@ int main(int argc, char* argv[]) { qmlRegisterUncreatableType("Spectral", 0, 1, "RoomMessageEvent", "ENUM"); qmlRegisterUncreatableType("Spectral", 0, 1, "RoomType", "ENUM"); + qmlRegisterUncreatableType("Spectral", 0, 1, "UserType", "ENUM"); qRegisterMetaType("User*"); qRegisterMetaType("const User*"); diff --git a/src/userlistmodel.cpp b/src/userlistmodel.cpp index 6ab23ce93..dffa64ac2 100644 --- a/src/userlistmodel.cpp +++ b/src/userlistmodel.cpp @@ -4,6 +4,8 @@ #include #include +#include "events/roompowerlevelsevent.h" + #include #include #include @@ -63,7 +65,7 @@ QVariant UserListModel::data(const QModelIndex& index, int role) const { if (index.row() >= m_users.count()) { qDebug() << "UserListModel, something's wrong: index.row() >= m_users.count()"; - return QVariant(); + return {}; } auto user = m_users.at(index.row()); if (role == NameRole) { @@ -78,8 +80,38 @@ QVariant UserListModel::data(const QModelIndex& index, int role) const { if (role == ObjectRole) { return QVariant::fromValue(user); } + if (role == PermRole) { + auto pl = m_currentRoom->getCurrentState(); + auto userPl = pl->powerLevelForUser(user->id()); - return QVariant(); + if (userPl == pl->content().usersDefault) { + return UserType::Member; + } + + if (userPl < pl->content().usersDefault) { + return UserType::Muted; + } + + auto userPls = pl->users(); + + int highestPl = pl->usersDefault(); + QHash::const_iterator i = userPls.constBegin(); + while (i != userPls.constEnd()) { + if (i.value() > highestPl) { + highestPl = i.value(); + } + + ++i; + } + + if (userPl == highestPl) { + return UserType::Admin; + } + + return UserType::Moderator; + } + + return {}; } int UserListModel::rowCount(const QModelIndex& parent) const { @@ -138,6 +170,7 @@ QHash UserListModel::roleNames() const { roles[UserIDRole] = "userId"; roles[AvatarRole] = "avatar"; roles[ObjectRole] = "user"; + roles[PermRole] = "perm"; return roles; } diff --git a/src/userlistmodel.h b/src/userlistmodel.h index 0e83d37b1..b3d617e35 100644 --- a/src/userlistmodel.h +++ b/src/userlistmodel.h @@ -12,6 +12,19 @@ class Room; class User; } // namespace Quotient +class UserType : public QObject { + Q_OBJECT + + public: + enum Types { + Admin = 1, + Moderator, + Member, + Muted, + }; + Q_ENUMS(Types) +}; + class UserListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY( @@ -21,16 +34,15 @@ class UserListModel : public QAbstractListModel { NameRole = Qt::UserRole + 1, UserIDRole, AvatarRole, - ObjectRole + ObjectRole, + PermRole, }; - using User = Quotient::User; - UserListModel(QObject* parent = nullptr); Quotient::Room* room() const { return m_currentRoom; } void setRoom(Quotient::Room* room); - User* userAt(QModelIndex index) const; + Quotient::User* userAt(QModelIndex index) const; QVariant data(const QModelIndex& index, int role = NameRole) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; @@ -41,16 +53,16 @@ class UserListModel : public QAbstractListModel { void roomChanged(); private slots: - void userAdded(User* user); - void userRemoved(User* user); - void refresh(User* user, QVector roles = {}); - void avatarChanged(User* user, const Quotient::Room* context); + void userAdded(Quotient::User* user); + void userRemoved(Quotient::User* user); + void refresh(Quotient::User* user, QVector roles = {}); + void avatarChanged(Quotient::User* user, const Quotient::Room* context); private: Quotient::Room* m_currentRoom; - QList m_users; + QList m_users; - int findUserPos(User* user) const; + int findUserPos(Quotient::User* user) const; int findUserPos(const QString& username) const; }; From d13a88a8541b0d84df98dbfd9c0e832eeea336d2 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Mon, 6 Jan 2020 01:39:55 +0800 Subject: [PATCH 4/8] Improved user perms. --- imports/Spectral/Panel/RoomDrawer.qml | 24 +++++++++++++----------- src/userlistmodel.cpp | 14 +++++++++++--- src/userlistmodel.h | 3 ++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/imports/Spectral/Panel/RoomDrawer.qml b/imports/Spectral/Panel/RoomDrawer.qml index 27714d779..fc7582336 100644 --- a/imports/Spectral/Panel/RoomDrawer.qml +++ b/imports/Spectral/Panel/RoomDrawer.qml @@ -240,26 +240,28 @@ Drawer { wrapMode: Text.NoWrap } - MaterialIcon { - Layout.preferredWidth: height - Layout.fillHeight: true + Label { + visible: perm != UserType.Member - enabled: perm != UserType.Member - - icon: { + text: { + if (perm == UserType.Owner) { + return "Owner" + } if (perm == UserType.Admin) { - return "\ue853" + return "Admin" } if (perm == UserType.Moderator) { - return "\ue8e8" + return "Mod" } if (perm == UserType.Muted) { - return "\ue92a" + return "Muted" } return "" } - - color: MPalette.lighter + color: perm == UserType.Muted ? MPalette.lighter : MPalette.accent + font.pixelSize: 12 + textFormat: Text.PlainText + wrapMode: Text.NoWrap } } diff --git a/src/userlistmodel.cpp b/src/userlistmodel.cpp index dffa64ac2..9a24f161a 100644 --- a/src/userlistmodel.cpp +++ b/src/userlistmodel.cpp @@ -84,11 +84,11 @@ QVariant UserListModel::data(const QModelIndex& index, int role) const { auto pl = m_currentRoom->getCurrentState(); auto userPl = pl->powerLevelForUser(user->id()); - if (userPl == pl->content().usersDefault) { + if (userPl == pl->content().usersDefault) { // Shortcut return UserType::Member; } - if (userPl < pl->content().usersDefault) { + if (userPl < pl->powerLevelForState("m.room.message")) { return UserType::Muted; } @@ -105,10 +105,18 @@ QVariant UserListModel::data(const QModelIndex& index, int role) const { } if (userPl == highestPl) { + return UserType::Owner; + } + + if (userPl >= pl->powerLevelForState("m.room.power_levels")) { return UserType::Admin; } - return UserType::Moderator; + if (userPl >= pl->ban() || userPl >= pl->kick() || userPl >= pl->redact()) { + return UserType::Moderator; + } + + return UserType::Member; } return {}; diff --git a/src/userlistmodel.h b/src/userlistmodel.h index b3d617e35..c223aed91 100644 --- a/src/userlistmodel.h +++ b/src/userlistmodel.h @@ -17,7 +17,8 @@ class UserType : public QObject { public: enum Types { - Admin = 1, + Owner = 1, + Admin, Moderator, Member, Muted, From df3f3a4da10a7a9f03b96034105d2e8dec6b8437 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Mon, 13 Jan 2020 06:54:59 -0800 Subject: [PATCH 5/8] Update libQuotient and fix CI. --- .gitlab-ci.yml | 1 + imports/Spectral/Panel/RoomPanel.qml | 5 ++++- include/libQuotient | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e5cb60609..fb3d4fa65 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,6 +10,7 @@ build-appimage: stage: build script: - git clone https://gitlab.matrix.org/matrix-org/olm.git && cd olm + - git checkout tags/0.29.0 - cmake . -Bbuild -LA -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install -DBUILD_SHARED_LIBS=NO - cmake --build build --target install --parallel $(nproc) - cd .. diff --git a/imports/Spectral/Panel/RoomPanel.qml b/imports/Spectral/Panel/RoomPanel.qml index c85ab5b07..377c6e5ab 100644 --- a/imports/Spectral/Panel/RoomPanel.qml +++ b/imports/Spectral/Panel/RoomPanel.qml @@ -226,6 +226,10 @@ Item { boundsBehavior: Flickable.DragOverBounds + onModelChanged: { + messageListView.positionViewAtBeginning() + } + model: SortFilterProxyModel { id: sortedMessageEventModel @@ -239,7 +243,6 @@ Item { onModelReset: { movingTimer.stop() - messageListView.positionViewAtBeginning() if (currentRoom) { movingTimer.restart() diff --git a/include/libQuotient b/include/libQuotient index 3accf7dfd..ac48199de 160000 --- a/include/libQuotient +++ b/include/libQuotient @@ -1 +1 @@ -Subproject commit 3accf7dfd82e8e14a7f90a8debee921f2f428679 +Subproject commit ac48199de174aa8cca52e703a3e65034fcd5db07 From 211285e28b00cbae9c986a29f9e1165dd4c8c177 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Mon, 13 Jan 2020 14:59:05 +0000 Subject: [PATCH 6/8] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fb3d4fa65..277bc0152 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,7 +10,6 @@ build-appimage: stage: build script: - git clone https://gitlab.matrix.org/matrix-org/olm.git && cd olm - - git checkout tags/0.29.0 - cmake . -Bbuild -LA -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install -DBUILD_SHARED_LIBS=NO - cmake --build build --target install --parallel $(nproc) - cd .. @@ -20,6 +19,7 @@ build-appimage: - sudo cmake --build build --target install - cd .. - git clone https://github.com/commonmark/cmark.git && cd cmark + - git checkout tags/0.29.0 - cmake . -Bbuild -LA -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install -DCMARK_SHARED=ON -DCMARK_STATIC=ON -DCMARK_TESTS=OFF - cmake --build build --target install --parallel $(nproc) - cd .. From 06f063d8b4bbb89a086f186da55cdb02f432760f Mon Sep 17 00:00:00 2001 From: Black Hat Date: Mon, 13 Jan 2020 15:26:23 +0000 Subject: [PATCH 7/8] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 277bc0152..ca4a9caa2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ build-appimage: - cmake . -Bbuild -LA -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install -DCMARK_SHARED=ON -DCMARK_STATIC=ON -DCMARK_TESTS=OFF - cmake --build build --target install --parallel $(nproc) - cd .. - - cmake . -Bbuild -LA -DUSE_INTREE_LIBQMC=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/usr -DOlm_DIR="olm/install/lib/cmake/Olm" -DQt5Keychain_DIR="qtkeychain/install/lib/x86_64-linux-gnu/cmake/Qt5Keychain" -DCMARK_LIBRARY="$PWD/cmark/install/lib/libcmark_static.a" -DCMARK_INCLUDE_DIR="$PWD/cmark/install/include" + - cmake . -Bbuild -LA -DUSE_INTREE_LIBQMC=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=install/usr -DOlm_DIR="olm/install/lib/cmake/Olm" -DQt5Keychain_DIR="qtkeychain/install/lib/x86_64-linux-gnu/cmake/Qt5Keychain" -DCMARK_LIBRARY="$PWD/cmark/install/lib/libcmark.a" -DCMARK_INCLUDE_DIR="$PWD/cmark/install/include" - cmake --build build --target install --parallel $(nproc) - cp install/usr/share/icons/hicolor/256x256/apps/org.eu.encom.spectral.png install/org.eu.encom.spectral.png - linuxdeployqt install/usr/share/applications/org.eu.encom.spectral.desktop -appimage -qmldir=qml -qmldir=imports From 9fd7d53dd7cfcd8314bfd65be94d0db46c48915d Mon Sep 17 00:00:00 2001 From: Black Date: Tue, 21 Jan 2020 11:15:52 -0800 Subject: [PATCH 8/8] Upgrade libquotient. --- include/libQuotient | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libQuotient b/include/libQuotient index ac48199de..e3a5b3a5e 160000 --- a/include/libQuotient +++ b/include/libQuotient @@ -1 +1 @@ -Subproject commit ac48199de174aa8cca52e703a3e65034fcd5db07 +Subproject commit e3a5b3a5e5253fc5ce67574b01e8d25ec14e4d25