From 8b26a9f45f6a984bb2d6563407bd975133a3a448 Mon Sep 17 00:00:00 2001 From: James Graham Date: Mon, 13 Mar 2023 18:45:18 +0000 Subject: [PATCH] Cherrypick Room URL preview settings to 23.04 - Add the ability to set the deafult url preview setting for the room if you have sufficient power level. - Add the ability for the user to set the desired url preview setting. network/neochat#560 (cherry picked from commit 81c73037ca71ef6068d266f1119cb48e9bac1597) --- src/neochatroom.cpp | 103 +++++++++++++++++- src/neochatroom.h | 21 ++++ .../Timeline/LinkPreviewDelegate.qml | 2 +- src/qml/RoomSettings/General.qml | 26 +++++ 4 files changed, 147 insertions(+), 5 deletions(-) diff --git a/src/neochatroom.cpp b/src/neochatroom.cpp index 8a79a42fa..c8d1b12ef 100644 --- a/src/neochatroom.cpp +++ b/src/neochatroom.cpp @@ -13,9 +13,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -98,6 +100,14 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS Q_EMIT canEncryptRoomChanged(); }); connect(connection, &Connection::capabilitiesLoaded, this, &NeoChatRoom::maxRoomVersionChanged); + connect(this, &Room::changed, this, [this]() { + Q_EMIT defaultUrlPreviewStateChanged(); + }); + connect(this, &Room::accountDataChanged, this, [this](QString type) { + if (type == "org.matrix.room.preview_urls") { + Q_EMIT urlPreviewEnabledChanged(); + } + }); } void NeoChatRoom::uploadFile(const QUrl &url, const QString &body) @@ -937,7 +947,7 @@ bool NeoChatRoom::canSendState(const QString &eventType) const auto currentPl = plEvent->powerLevelForUser(localUser()->id()); #ifndef QUOTIENT_07 - if (eventType == "m.room.history_visibility") { + if (eventType == "m.room.history_visibility" || eventType == "org.matrix.room.preview_urls") { return false; } else { return currentPl >= pl; @@ -1027,10 +1037,89 @@ void NeoChatRoom::setHistoryVisibility(const QString &historyVisibilityRule) // Not emitting historyVisibilityChanged() here, since that would override the change in the UI with the *current* value, which is not the *new* value. } -int NeoChatRoom::getUserPowerLevel(const QString &userId) const +bool NeoChatRoom::defaultUrlPreviewState() const { - auto powerLevelEvent = getCurrentState(); - return powerLevelEvent->powerLevelForUser(userId); +#ifdef QUOTIENT_07 + auto urlPreviewsDisabled = currentState().get("org.matrix.room.preview_urls"); +#else + auto urlPreviewsDisabled = getCurrentState("org.matrix.room.preview_urls"); +#endif + + // Some rooms will not have this state event set so check for a nullptr return. + if (urlPreviewsDisabled != nullptr) { + return !urlPreviewsDisabled->contentJson()["disable"].toBool(); + } else { + return false; + } +} + +void NeoChatRoom::setDefaultUrlPreviewState(const bool &defaultUrlPreviewState) +{ + if (!canSendState("org.matrix.room.preview_urls")) { + qWarning() << "Power level too low to set the default URL preview state for the room"; + return; + } + + /** + * Note the org.matrix.room.preview_urls room state event is completely undocumented + * so here it is because I'm nice. + * + * Also note this is a different event to org.matrix.room.preview_urls for room + * account data, because even though it has the same name and content it's totally different. + * + * { + * "content": { + * "disable": false + * }, + * "origin_server_ts": 1673115224071, + * "sender": "@bob:kde.org", + * "state_key": "", + * "type": "org.matrix.room.preview_urls", + * "unsigned": { + * "replaces_state": "replaced_event_id", + * "prev_content": { + * "disable": true + * }, + * "prev_sender": "@jeff:kde.org", + * "age": 99 + * }, + * "event_id": "$event_id", + * "room_id": "!room_id:kde.org" + * } + * + * You just have to set disable to true to disable URL previews by default. + */ +#ifdef QUOTIENT_07 + setState("org.matrix.room.preview_urls", "", QJsonObject{{"disable", !defaultUrlPreviewState}}); +#else + qWarning() << "Quotient 0.7 required to set room default url preview setting"; + return; +#endif +} + +bool NeoChatRoom::urlPreviewEnabled() const +{ + if (hasAccountData("org.matrix.room.preview_urls")) { + return !accountData("org.matrix.room.preview_urls")->contentJson()["disable"].toBool(); + } else { + return defaultUrlPreviewState(); + } +} + +void NeoChatRoom::setUrlPreviewEnabled(const bool &urlPreviewEnabled) +{ + /** + * Once again this is undocumented and even though the name and content are the + * same this is a different event to the org.matrix.room.preview_urls room state event. + * + * { + * "content": { + * "disable": true + * } + * "type": "org.matrix.room.preview_urls", + * } + */ + connection()->callApi(localUser()->id(), id(), "org.matrix.room.preview_urls", QJsonObject{{"disable", !urlPreviewEnabled}}); } void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel) @@ -1072,6 +1161,12 @@ void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel } } +int NeoChatRoom::getUserPowerLevel(const QString &userId) const +{ + auto powerLevelEvent = getCurrentState(); + return powerLevelEvent->powerLevelForUser(userId); +} + int NeoChatRoom::powerLevel(const QString &eventName, const bool &isStateEvent) const { #ifdef QUOTIENT_07 diff --git a/src/neochatroom.h b/src/neochatroom.h index abc84389d..e8182d1c8 100644 --- a/src/neochatroom.h +++ b/src/neochatroom.h @@ -52,6 +52,19 @@ class NeoChatRoom : public Quotient::Room Q_PROPERTY(QString joinRule READ joinRule WRITE setJoinRule NOTIFY joinRuleChanged) Q_PROPERTY(QString historyVisibility READ historyVisibility WRITE setHistoryVisibility NOTIFY historyVisibilityChanged) + /** + * @brief Set the default URL preview state for room members. + * + * Assumed false if the org.matrix.room.preview_urls state message has never been + * set. Can only be set if the calling user has a high enough power level. + */ + Q_PROPERTY(bool defaultUrlPreviewState READ defaultUrlPreviewState WRITE setDefaultUrlPreviewState NOTIFY defaultUrlPreviewStateChanged) + + /** + * @brief Enable URL previews for the local user. + */ + Q_PROPERTY(bool urlPreviewEnabled READ urlPreviewEnabled WRITE setUrlPreviewEnabled NOTIFY urlPreviewEnabledChanged) + // Properties for the various permission levels for the room Q_PROPERTY(int defaultUserPowerLevel READ defaultUserPowerLevel WRITE setDefaultUserPowerLevel NOTIFY defaultUserPowerLevelChanged) Q_PROPERTY(int invitePowerLevel READ invitePowerLevel WRITE setInvitePowerLevel NOTIFY invitePowerLevelChanged) @@ -147,6 +160,12 @@ public: [[nodiscard]] QString historyVisibility() const; void setHistoryVisibility(const QString &historyVisibilityRule); + [[nodiscard]] bool defaultUrlPreviewState() const; + void setDefaultUrlPreviewState(const bool &defaultUrlPreviewState); + + [[nodiscard]] bool urlPreviewEnabled() const; + void setUrlPreviewEnabled(const bool &urlPreviewEnabled); + /** * @brief Get the power level for the given user ID in the room. * @@ -389,6 +408,8 @@ Q_SIGNALS: void canEncryptRoomChanged(); void joinRuleChanged(); void historyVisibilityChanged(); + void defaultUrlPreviewStateChanged(); + void urlPreviewEnabledChanged(); void maxRoomVersionChanged(); void defaultUserPowerLevelChanged(); void invitePowerLevelChanged(); diff --git a/src/qml/Component/Timeline/LinkPreviewDelegate.qml b/src/qml/Component/Timeline/LinkPreviewDelegate.qml index 64cb84078..86c0595e8 100644 --- a/src/qml/Component/Timeline/LinkPreviewDelegate.qml +++ b/src/qml/Component/Timeline/LinkPreviewDelegate.qml @@ -49,7 +49,7 @@ Loader { */ property bool indicatorEnabled: false - active: !currentRoom.usesEncryption && model.display && links && links.length > 0 + active: !currentRoom.usesEncryption && model.display && links && links.length > 0 && currentRoom.urlPreviewEnabled visible: Config.showLinkPreview && active sourceComponent: linkPreviewer.loaded ? linkPreviewComponent : loadingComponent diff --git a/src/qml/RoomSettings/General.qml b/src/qml/RoomSettings/General.qml index 1117ce256..609285bc1 100644 --- a/src/qml/RoomSettings/General.qml +++ b/src/qml/RoomSettings/General.qml @@ -263,6 +263,32 @@ Kirigami.ScrollablePage { } } } + MobileForm.FormCard { + Layout.fillWidth: true + contentItem: ColumnLayout { + spacing: 0 + MobileForm.FormCardHeader { + title: i18n("URL Previews") + } + MobileForm.FormCheckDelegate { + text: i18n("Enable URL previews by default for room members") + checked: room.defaultUrlPreviewState + visible: room.canSendState("org.matrix.room.preview_urls") + onToggled: { + room.defaultUrlPreviewState = checked + } + } + MobileForm.FormCheckDelegate { + text: i18n("Enable URL previews") + // Most users won't see the above setting so tell them the default. + description: room.defaultUrlPreviewState ? i18n("URL previews are enabled by default in this room") : i18n("URL previews are disabled by default in this room") + checked: room.urlPreviewEnabled + onToggled: { + room.urlPreviewEnabled = checked + } + } + } + } Kirigami.InlineMessage { Layout.fillWidth: true