Merge pull request #891 from tastytea/hidden-events-gui

Add GUI to change hidden events per room
pull/939/head
DeepBlueV7.X 3 years ago committed by GitHub
commit a930e3c804
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CMakeLists.txt
  2. 2
      io.github.NhekoReborn.Nheko.yaml
  3. 127
      resources/qml/dialogs/HiddenEventsDialog.qml
  4. 18
      resources/qml/dialogs/RoomSettings.qml
  5. 1
      resources/res.qrc
  6. 56
      src/Cache.cpp
  7. 2
      src/MainWindow.cpp
  8. 112
      src/timeline/TimelineModel.cpp
  9. 2
      src/timeline/TimelineModel.h
  10. 93
      src/ui/HiddenEvents.cpp
  11. 46
      src/ui/HiddenEvents.h
  12. 3
      src/ui/RoomSettings.cpp
  13. 2
      src/ui/RoomSettings.h

@ -332,6 +332,7 @@ set(SRC_FILES
src/timeline/RoomlistModel.cpp
# UI components
src/ui/HiddenEvents.cpp
src/ui/MxcAnimatedImage.cpp
src/ui/MxcMediaProxy.cpp
src/ui/NhekoCursorShape.cpp
@ -403,7 +404,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG 8c03d9ac58274695a71d0eb32519ebce29bc536e
GIT_TAG 31a703c9febdfcaaf4e8a74abd424b6fc462e573
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
@ -527,6 +528,7 @@ qt5_wrap_cpp(MOC_HEADERS
src/timeline/RoomlistModel.h
# UI components
src/ui/HiddenEvents.h
src/ui/MxcAnimatedImage.h
src/ui/MxcMediaProxy.h
src/ui/NhekoCursorShape.h

@ -191,7 +191,7 @@ modules:
buildsystem: cmake-ninja
name: mtxclient
sources:
- commit: 8c03d9ac58274695a71d0eb32519ebce29bc536e
- commit: 31a703c9febdfcaaf4e8a74abd424b6fc462e573
#tag: v0.6.1
type: git
url: https://github.com/Nheko-Reborn/mtxclient.git

@ -0,0 +1,127 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
import ".."
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import im.nheko 1.0
ApplicationWindow {
id: hiddenEventsDialog
property string roomid: ""
property string roomName: ""
property var onAccepted: undefined
modality: Qt.NonModal
flags: Qt.Dialog | Qt.WindowTitleHint
minimumWidth: 250
minimumHeight: 220
HiddenEvents {
id: hiddenEvents
roomid: hiddenEventsDialog.roomid
}
title: {
if (roomid) {
return qsTr("Hidden events for %1").arg(roomName);
}
else {
return qsTr("Hidden events");
}
}
Shortcut {
sequence: StandardKey.Cancel
onActivated: dbb.rejected()
}
ColumnLayout {
spacing: Nheko.paddingMedium
anchors.margins: Nheko.paddingMedium
anchors.fill: parent
MatrixText {
id: promptLabel
text: {
if (roomid) {
return qsTr("These events will be be <b>shown</b> in %1:").arg(roomName);
}
else {
return qsTr("These events will be be <b>shown</b> in all rooms:");
}
}
font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.2)
Layout.fillWidth: true
Layout.fillHeight: false
}
GridLayout {
columns: 2
rowSpacing: Nheko.paddingMedium
Layout.fillWidth: true
Layout.fillHeight: true
MatrixText {
text: qsTr("User events")
ToolTip.text: qsTr("Joins, leaves, avatar and name changes, bans, …")
ToolTip.visible: hh1.hovered
Layout.fillWidth: true
HoverHandler {
id: hh1
}
}
ToggleButton {
Layout.alignment: Qt.AlignRight
checked: !hiddenEvents.hiddenEvents.includes(MtxEvent.Member)
onToggled: hiddenEvents.toggle(MtxEvent.Member)
}
MatrixText {
text: qsTr("Power level changes")
ToolTip.text: qsTr("Sent when a moderator is added/removed or the permissions of a room are changed.")
ToolTip.visible: hh2.hovered
Layout.fillWidth: true
HoverHandler {
id: hh2
}
}
ToggleButton {
Layout.alignment: Qt.AlignRight
checked: !hiddenEvents.hiddenEvents.includes(MtxEvent.PowerLevels)
onToggled: hiddenEvents.toggle(MtxEvent.PowerLevels)
}
MatrixText {
text: qsTr("Stickers")
Layout.fillWidth: true
}
ToggleButton {
Layout.alignment: Qt.AlignRight
checked: !hiddenEvents.hiddenEvents.includes(MtxEvent.Sticker)
onToggled: hiddenEvents.toggle(MtxEvent.Sticker)
}
}
}
footer: DialogButtonBox {
id: dbb
standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
onAccepted: {
hiddenEvents.save();
hiddenEventsDialog.close();
}
onRejected: hiddenEventsDialog.close();
}
}

@ -254,6 +254,23 @@ ApplicationWindow {
Layout.alignment: Qt.AlignRight
}
MatrixText {
text: qsTr("Hidden events")
}
HiddenEventsDialog {
id: hiddenEventsDialog
roomid: roomSettings.roomId
roomName: roomSettings.roomName
}
Button {
text: qsTr("Configure")
ToolTip.text: qsTr("Select events to hide in this room")
onClicked: hiddenEventsDialog.show()
Layout.alignment: Qt.AlignRight
}
Item {
// for adding extra space between sections
Layout.fillWidth: true
@ -302,5 +319,4 @@ ApplicationWindow {
}
}
}

@ -152,6 +152,7 @@
<file>qml/dialogs/RoomMembers.qml</file>
<file>qml/dialogs/RoomSettings.qml</file>
<file>qml/dialogs/UserProfile.qml</file>
<file>qml/dialogs/HiddenEventsDialog.qml</file>
<file>qml/emoji/EmojiPicker.qml</file>
<file>qml/emoji/StickerPicker.qml</file>
<file>qml/ui/NhekoSlider.qml</file>

@ -173,24 +173,31 @@ Cache::isHiddenEvent(lmdb::txn &txn,
}
mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
hiddenEvents.hidden_event_types = {
EventType::Reaction, EventType::CallCandidates, EventType::Unsupported};
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, ""))
hiddenEvents =
std::move(std::get<mtx::events::AccountDataEvent<
mtx::events::account_data::nheko_extensions::HiddenEvents>>(*temp)
.content);
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id))
hiddenEvents =
std::move(std::get<mtx::events::AccountDataEvent<
mtx::events::account_data::nheko_extensions::HiddenEvents>>(*temp)
.content);
hiddenEvents.hidden_event_types = std::vector{
EventType::Reaction,
EventType::CallCandidates,
EventType::Unsupported,
};
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, "")) {
auto h = std::get<
mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
*temp);
if (h.content.hidden_event_types)
hiddenEvents = std::move(h.content);
}
if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id)) {
auto h = std::get<
mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
*temp);
if (h.content.hidden_event_types)
hiddenEvents = std::move(h.content);
}
return std::visit(
[hiddenEvents](const auto &ev) {
return std::any_of(hiddenEvents.hidden_event_types.begin(),
hiddenEvents.hidden_event_types.end(),
return std::any_of(hiddenEvents.hidden_event_types->begin(),
hiddenEvents.hidden_event_types->end(),
[ev](EventType type) { return type == ev.type; });
},
e);
@ -1515,6 +1522,16 @@ Cache::saveState(const mtx::responses::Sync &res)
for (const auto &ev : res.account_data.events)
std::visit(
[&txn, &accountDataDb](const auto &event) {
if constexpr (std::is_same_v<
std::remove_cv_t<std::remove_reference_t<decltype(event)>>,
AccountDataEvent<
mtx::events::account_data::nheko_extensions::HiddenEvents>>) {
if (!event.content.hidden_event_types) {
accountDataDb.del(txn, "im.nheko.hidden_events");
return;
}
}
auto j = json(event);
accountDataDb.put(txn, j["type"].get<std::string>(), j.dump());
},
@ -1589,6 +1606,15 @@ Cache::saveState(const mtx::responses::Sync &res)
for (const auto &evt : room.second.account_data.events) {
std::visit(
[&txn, &accountDataDb](const auto &event) {
if constexpr (std::is_same_v<
std::remove_cv_t<std::remove_reference_t<decltype(event)>>,
AccountDataEvent<mtx::events::account_data::nheko_extensions::
HiddenEvents>>) {
if (!event.content.hidden_event_types) {
accountDataDb.del(txn, "im.nheko.hidden_events");
return;
}
}
auto j = json(event);
accountDataDb.put(txn, j["type"].get<std::string>(), j.dump());
},

@ -44,6 +44,7 @@
#include "encryption/SelfVerificationStatus.h"
#include "timeline/DelegateChooser.h"
#include "timeline/TimelineViewManager.h"
#include "ui/HiddenEvents.h"
#include "ui/MxcAnimatedImage.h"
#include "ui/MxcMediaProxy.h"
#include "ui/NhekoCursorShape.h"
@ -168,6 +169,7 @@ MainWindow::registerQmlTypes()
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
qmlRegisterUncreatableType<DeviceVerificationFlow>(
"im.nheko",
1,

@ -50,59 +50,7 @@ struct RoomEventType
template<class T>
qml_mtx_events::EventType operator()(const mtx::events::Event<T> &e)
{
using mtx::events::EventType;
switch (e.type) {
case EventType::RoomKeyRequest:
return qml_mtx_events::EventType::KeyRequest;
case EventType::Reaction:
return qml_mtx_events::EventType::Reaction;
case EventType::RoomAliases:
return qml_mtx_events::EventType::Aliases;
case EventType::RoomAvatar:
return qml_mtx_events::EventType::Avatar;
case EventType::RoomCanonicalAlias:
return qml_mtx_events::EventType::CanonicalAlias;
case EventType::RoomCreate:
return qml_mtx_events::EventType::RoomCreate;
case EventType::RoomEncrypted:
return qml_mtx_events::EventType::Encrypted;
case EventType::RoomEncryption:
return qml_mtx_events::EventType::Encryption;
case EventType::RoomGuestAccess:
return qml_mtx_events::EventType::RoomGuestAccess;
case EventType::RoomHistoryVisibility:
return qml_mtx_events::EventType::RoomHistoryVisibility;
case EventType::RoomJoinRules:
return qml_mtx_events::EventType::RoomJoinRules;
case EventType::RoomMember:
return qml_mtx_events::EventType::Member;
case EventType::RoomMessage:
return qml_mtx_events::EventType::UnknownMessage;
case EventType::RoomName:
return qml_mtx_events::EventType::Name;
case EventType::RoomPowerLevels:
return qml_mtx_events::EventType::PowerLevels;
case EventType::RoomTopic:
return qml_mtx_events::EventType::Topic;
case EventType::RoomTombstone:
return qml_mtx_events::EventType::Tombstone;
case EventType::RoomRedaction:
return qml_mtx_events::EventType::Redaction;
case EventType::RoomPinnedEvents:
return qml_mtx_events::EventType::PinnedEvents;
case EventType::Sticker:
return qml_mtx_events::EventType::Sticker;
case EventType::Tag:
return qml_mtx_events::EventType::Tag;
case EventType::SpaceParent:
return qml_mtx_events::EventType::SpaceParent;
case EventType::SpaceChild:
return qml_mtx_events::EventType::SpaceChild;
case EventType::Unsupported:
return qml_mtx_events::EventType::Unsupported;
default:
return qml_mtx_events::EventType::UnknownMessage;
}
return qml_mtx_events::toRoomEventType(e.type);
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Audio> &)
{
@ -198,6 +146,64 @@ struct RoomEventType
};
}
qml_mtx_events::EventType
qml_mtx_events::toRoomEventType(mtx::events::EventType e)
{
using mtx::events::EventType;
switch (e) {
case EventType::RoomKeyRequest:
return qml_mtx_events::EventType::KeyRequest;
case EventType::Reaction:
return qml_mtx_events::EventType::Reaction;
case EventType::RoomAliases:
return qml_mtx_events::EventType::Aliases;
case EventType::RoomAvatar:
return qml_mtx_events::EventType::Avatar;
case EventType::RoomCanonicalAlias:
return qml_mtx_events::EventType::CanonicalAlias;
case EventType::RoomCreate:
return qml_mtx_events::EventType::RoomCreate;
case EventType::RoomEncrypted:
return qml_mtx_events::EventType::Encrypted;
case EventType::RoomEncryption:
return qml_mtx_events::EventType::Encryption;
case EventType::RoomGuestAccess:
return qml_mtx_events::EventType::RoomGuestAccess;
case EventType::RoomHistoryVisibility:
return qml_mtx_events::EventType::RoomHistoryVisibility;
case EventType::RoomJoinRules:
return qml_mtx_events::EventType::RoomJoinRules;
case EventType::RoomMember:
return qml_mtx_events::EventType::Member;
case EventType::RoomMessage:
return qml_mtx_events::EventType::UnknownMessage;
case EventType::RoomName:
return qml_mtx_events::EventType::Name;
case EventType::RoomPowerLevels:
return qml_mtx_events::EventType::PowerLevels;
case EventType::RoomTopic:
return qml_mtx_events::EventType::Topic;
case EventType::RoomTombstone:
return qml_mtx_events::EventType::Tombstone;
case EventType::RoomRedaction:
return qml_mtx_events::EventType::Redaction;
case EventType::RoomPinnedEvents:
return qml_mtx_events::EventType::PinnedEvents;
case EventType::Sticker:
return qml_mtx_events::EventType::Sticker;
case EventType::Tag:
return qml_mtx_events::EventType::Tag;
case EventType::SpaceParent:
return qml_mtx_events::EventType::SpaceParent;
case EventType::SpaceChild:
return qml_mtx_events::EventType::SpaceChild;
case EventType::Unsupported:
return qml_mtx_events::EventType::Unsupported;
default:
return qml_mtx_events::EventType::UnknownMessage;
}
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::collections::TimelineEvents &event)
{

@ -125,6 +125,8 @@ enum EventType
};
Q_ENUM_NS(EventType)
mtx::events::EventType fromRoomEventType(qml_mtx_events::EventType);
qml_mtx_events::EventType
toRoomEventType(mtx::events::EventType e);
enum EventState
{

@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "HiddenEvents.h"
#include "Cache_p.h"
#include "MainWindow.h"
#include "MatrixClient.h"
void
HiddenEvents::load()
{
using namespace mtx::events;
mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
hiddenEvents.hidden_event_types = std::vector{
EventType::Reaction,
EventType::CallCandidates,
EventType::Unsupported,
};
if (auto temp =
cache::client()->getAccountData(mtx::events::EventType::NhekoHiddenEvents, "")) {
auto h = std::get<
mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
*temp);
if (h.content.hidden_event_types)
hiddenEvents = std::move(h.content);
}
if (!roomid_.isEmpty()) {
if (auto temp = cache::client()->getAccountData(mtx::events::EventType::NhekoHiddenEvents,
roomid_.toStdString())) {
auto h = std::get<mtx::events::AccountDataEvent<
mtx::events::account_data::nheko_extensions::HiddenEvents>>(*temp);
if (h.content.hidden_event_types)
hiddenEvents = std::move(h.content);
}
}
hiddenEvents_.clear();
hiddenEvents_ = std::move(hiddenEvents.hidden_event_types.value());
emit hiddenEventsChanged();
}
Q_INVOKABLE void
HiddenEvents::toggle(int type)
{
auto t = qml_mtx_events::fromRoomEventType(static_cast<qml_mtx_events::EventType>(type));
if (auto it = std::find(begin(hiddenEvents_), end(hiddenEvents_), t); it != end(hiddenEvents_))
hiddenEvents_.erase(it);
else
hiddenEvents_.push_back(t);
emit hiddenEventsChanged();
}
QVariantList
HiddenEvents::hiddenEvents() const
{
QVariantList l;
for (const auto &e : hiddenEvents_) {
l.push_back(qml_mtx_events::toRoomEventType(e));
}
return l;
}
void
HiddenEvents::save()
{
mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
hiddenEvents.hidden_event_types = hiddenEvents_;
if (roomid_.isEmpty())
http::client()->put_account_data(hiddenEvents, [](mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to set hidden events: {}", *e);
MainWindow::instance()->showNotification(
tr("Failed to set hidden events: %1")
.arg(QString::fromStdString(e->matrix_error.error)));
}
});
else
http::client()->put_room_account_data(
roomid_.toStdString(), hiddenEvents, [](mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to set hidden events: {}", *e);
MainWindow::instance()->showNotification(
tr("Failed to set hidden events: %1")
.arg(QString::fromStdString(e->matrix_error.error)));
}
});
}

@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QObject>
#include <QString>
#include <QVariantList>
#include "timeline/TimelineModel.h"
class HiddenEvents : public QObject
{
Q_OBJECT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged REQUIRED)
Q_PROPERTY(QVariantList hiddenEvents READ hiddenEvents NOTIFY hiddenEventsChanged)
public:
explicit HiddenEvents(QObject *p = nullptr)
: QObject(p)
{}
Q_INVOKABLE void toggle(int type);
Q_INVOKABLE void save();
[[nodiscard]] QString roomid() const { return roomid_; }
void setRoomid(const QString &r)
{
roomid_ = r;
emit roomidChanged();
load();
}
[[nodiscard]] QVariantList hiddenEvents() const;
signals:
void roomidChanged();
void hiddenEventsChanged();
private:
QString roomid_;
std::vector<mtx::events::EventType> hiddenEvents_;
void load();
};

@ -12,10 +12,13 @@
#include <QMimeDatabase>
#include <QStandardPaths>
#include <QVBoxLayout>
#include <mtx/events/event_type.hpp>
#include <mtx/responses/common.hpp>
#include <mtx/responses/media.hpp>
#include <mtxclient/http/client.hpp>
#include "Cache.h"
#include "Cache_p.h"
#include "Config.h"
#include "Logging.h"
#include "MatrixClient.h"

@ -8,8 +8,10 @@
#include <QLabel>
#include <QObject>
#include <QPushButton>
#include <QSet>
#include <QString>
#include <mtx/events/event_type.hpp>
#include <mtx/events/guest_access.hpp>
#include "CacheStructs.h"

Loading…
Cancel
Save