From fdb9d7ab40da1d6b40ae11c3988af7082b6bc7cd Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 23 Jan 2021 00:30:45 +0100 Subject: [PATCH] Allow users to hide rooms with specific tags --- resources/styles/nheko-dark.qss | 3 +- resources/styles/nheko.qss | 3 +- resources/styles/system.qss | 1 + src/ChatPage.cpp | 25 +++++++++-- src/CommunitiesList.cpp | 30 +++++++++++-- src/CommunitiesList.h | 5 ++- src/CommunitiesListItem.cpp | 80 ++++++++++++++++++++++++++------- src/CommunitiesListItem.h | 25 ++++++++--- src/MatrixClient.cpp | 3 ++ src/RoomInfoListItem.cpp | 4 +- src/RoomInfoListItem.h | 4 +- src/RoomList.cpp | 16 ++++--- src/RoomList.h | 6 ++- 13 files changed, 159 insertions(+), 46 deletions(-) diff --git a/resources/styles/nheko-dark.qss b/resources/styles/nheko-dark.qss index 547e4256..af189f0e 100644 --- a/resources/styles/nheko-dark.qss +++ b/resources/styles/nheko-dark.qss @@ -155,11 +155,12 @@ RoomInfoListItem > Avatar { CommunitiesListItem { qproperty-highlightedBackgroundColor: #4d84c7; + qproperty-disabledBackgroundColor: palette(mid); qproperty-hoverBackgroundColor: rgb(67, 70, 77); qproperty-backgroundColor: #2d3139; qproperty-avatarBgColor: #202228; - qproperty-avatarFgColor: palette(window); + qproperty-avatarFgColor: black; } LoadingIndicator { diff --git a/resources/styles/nheko.qss b/resources/styles/nheko.qss index 81d97f65..edf3880b 100644 --- a/resources/styles/nheko.qss +++ b/resources/styles/nheko.qss @@ -122,11 +122,12 @@ RoomInfoListItem > Avatar { CommunitiesListItem { qproperty-highlightedBackgroundColor: #38A3D8; + qproperty-disabledBackgroundColor: palette(mid); qproperty-hoverBackgroundColor: rgb(70, 77, 93); qproperty-backgroundColor: #f2f5f8; qproperty-avatarBgColor: #eee; - qproperty-avatarFgColor: black; + qproperty-avatarFgColor: palette(buttonText); } #ChatPageLoadSpinner { diff --git a/resources/styles/system.qss b/resources/styles/system.qss index d65c8baa..bab85126 100644 --- a/resources/styles/system.qss +++ b/resources/styles/system.qss @@ -118,6 +118,7 @@ RoomInfoListItem > Avatar { CommunitiesListItem { qproperty-highlightedBackgroundColor: palette(highlight); + qproperty-disabledBackgroundColor: palette(mid); qproperty-hoverBackgroundColor: palette(light); qproperty-backgroundColor: palette(window); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 0377ce30..3df67fcc 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -267,10 +267,27 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) [this](const QString &groupId) { current_community_ = groupId; - if (groupId == "world") - room_list_->removeFilter(); - else - room_list_->applyFilter(communitiesList_->roomList(groupId)); + if (groupId == "world") { + auto hidden = communitiesList_->hiddenTagsAndCommunities(); + std::set roomsToHide = communitiesList_->roomList(groupId); + for (const auto &hiddenTag : hidden) { + auto temp = communitiesList_->roomList(hiddenTag); + roomsToHide.insert(temp.begin(), temp.end()); + } + + room_list_->removeFilter(roomsToHide); + } else { + auto hidden = communitiesList_->hiddenTagsAndCommunities(); + hidden.erase(current_community_); + + auto roomsToShow = communitiesList_->roomList(groupId); + for (const auto &hiddenTag : hidden) { + for (const auto &r : communitiesList_->roomList(hiddenTag)) + roomsToShow.erase(r); + } + + room_list_->applyFilter(roomsToShow); + } }); connect(¬ificationsManager, diff --git a/src/CommunitiesList.cpp b/src/CommunitiesList.cpp index f3af9932..38d27864 100644 --- a/src/CommunitiesList.cpp +++ b/src/CommunitiesList.cpp @@ -135,6 +135,14 @@ CommunitiesList::addCommunity(const std::string &group_id) &CommunitiesListItem::clicked, this, &CommunitiesList::highlightSelectedCommunity); + connect(list_item, &CommunitiesListItem::isDisabledChanged, this, [this]() { + for (const auto &community : communities_) { + if (community.second->isPressed()) { + emit highlightSelectedCommunity(community.first); + break; + } + } + }); if (group_id.empty() || group_id.front() != '+') return; @@ -157,7 +165,9 @@ CommunitiesList::addCommunity(const std::string &group_id) connect(this, &CommunitiesList::groupRoomsRetrieved, this, - [this](const QString &id, const std::map &rooms) { + [this](const QString &id, const std::set &rooms) { + nhlog::ui()->info( + "Fetched rooms for {}: {}", id.toStdString(), rooms.size()); if (communities_.find(id) == communities_.end()) return; @@ -179,9 +189,9 @@ CommunitiesList::addCommunity(const std::string &group_id) return; } - std::map room_ids; + std::set room_ids; for (const auto &room : res.at("chunk")) - room_ids.emplace(QString::fromStdString(room.at("room_id")), true); + room_ids.emplace(QString::fromStdString(room.at("room_id"))); emit groupRoomsRetrieved(id, room_ids); }); @@ -256,7 +266,7 @@ CommunitiesList::fetchCommunityAvatar(const QString &id, const QString &avatarUr }); } -std::map +std::set CommunitiesList::roomList(const QString &id) const { if (communityExists(id)) @@ -277,6 +287,18 @@ CommunitiesList::currentTags() const return tags; } +std::set +CommunitiesList::hiddenTagsAndCommunities() const +{ + std::set hiddenTags; + for (auto &entry : communities_) { + if (entry.second->isDisabled()) + hiddenTags.insert(entry.first); + } + + return hiddenTags; +} + void CommunitiesList::sortEntries() { diff --git a/src/CommunitiesList.h b/src/CommunitiesList.h index 63f7af07..d62beb8d 100644 --- a/src/CommunitiesList.h +++ b/src/CommunitiesList.h @@ -24,17 +24,18 @@ public: void addCommunity(const std::string &id); void removeCommunity(const QString &id) { communities_.erase(id); }; - std::map roomList(const QString &id) const; + std::set roomList(const QString &id) const; void syncTags(const std::map &info); void setTagsForRoom(const QString &id, const std::vector &tags); std::vector currentTags() const; + std::set hiddenTagsAndCommunities() const; signals: void communityChanged(const QString &id); void avatarRetrieved(const QString &id, const QPixmap &img); void groupProfileRetrieved(const QString &group_id, const mtx::responses::GroupProfile &); - void groupRoomsRetrieved(const QString &group_id, const std::map &res); + void groupRoomsRetrieved(const QString &group_id, const std::set &res); public slots: void updateCommunityAvatar(const QString &id, const QPixmap &img); diff --git a/src/CommunitiesListItem.cpp b/src/CommunitiesListItem.cpp index dca91441..01c39fdc 100644 --- a/src/CommunitiesListItem.cpp +++ b/src/CommunitiesListItem.cpp @@ -1,5 +1,6 @@ #include "CommunitiesListItem.h" +#include #include #include "Utils.h" @@ -20,18 +21,28 @@ CommunitiesListItem::CommunitiesListItem(QString group_id, QWidget *parent) rippleOverlay_->setClipPath(path); rippleOverlay_->setClipping(true); - if (groupId_ == "world") - avatar_ = QPixmap(":/icons/icons/ui/world.png"); - else if (groupId_ == "tag:m.favourite") - avatar_ = QPixmap(":/icons/icons/ui/star.png"); - else if (groupId_ == "tag:m.lowpriority") - avatar_ = QPixmap(":/icons/icons/ui/lowprio.png"); - else if (groupId_.startsWith("tag:")) - avatar_ = QPixmap(":/icons/icons/ui/tag.png"); + menu_ = new QMenu(this); + hideRoomsWithTagAction_ = + new QAction(tr("Hide rooms with this tag or from this community"), this); + hideRoomsWithTagAction_->setCheckable(true); + menu_->addAction(hideRoomsWithTagAction_); + connect(menu_, &QMenu::aboutToShow, this, [this]() { + hideRoomsWithTagAction_->setChecked(isDisabled_); + }); + + connect(hideRoomsWithTagAction_, &QAction::triggered, this, [this](bool checked) { + this->setDisabled(checked); + }); updateTooltip(); } +void +CommunitiesListItem::contextMenuEvent(QContextMenuEvent *event) +{ + menu_->popup(event->globalPos()); +} + void CommunitiesListItem::setName(QString name) { @@ -48,6 +59,16 @@ CommunitiesListItem::setPressedState(bool state) } } +void +CommunitiesListItem::setDisabled(bool state) +{ + if (isDisabled_ != state) { + isDisabled_ = state; + update(); + emit isDisabledChanged(); + } +} + void CommunitiesListItem::mousePressEvent(QMouseEvent *event) { @@ -80,22 +101,47 @@ CommunitiesListItem::paintEvent(QPaintEvent *) if (isPressed_) p.fillRect(rect(), highlightedBackgroundColor_); + else if (isDisabled_) + p.fillRect(rect(), disabledBackgroundColor_); else if (underMouse()) p.fillRect(rect(), hoverBackgroundColor_); else p.fillRect(rect(), backgroundColor_); if (avatar_.isNull()) { - QFont font; - font.setPointSizeF(font.pointSizeF() * 1.3); - p.setFont(font); + QPixmap source; + if (groupId_ == "world") + source = QPixmap(":/icons/icons/ui/world.png"); + else if (groupId_ == "tag:m.favourite") + source = QPixmap(":/icons/icons/ui/star.png"); + else if (groupId_ == "tag:m.lowpriority") + source = QPixmap(":/icons/icons/ui/lowprio.png"); + else if (groupId_.startsWith("tag:")) + source = QPixmap(":/icons/icons/ui/tag.png"); - p.drawLetterAvatar(utils::firstChar(resolveName()), - avatarFgColor_, - avatarBgColor_, - width(), - height(), - IconSize); + if (source.isNull()) { + QFont font; + font.setPointSizeF(font.pointSizeF() * 1.3); + p.setFont(font); + + p.drawLetterAvatar(utils::firstChar(resolveName()), + avatarFgColor_, + avatarBgColor_, + width(), + height(), + IconSize); + } else { + QPainter painter(&source); + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(source.rect(), avatarFgColor_); + painter.end(); + + const int imageSz = 32; + p.drawPixmap( + QRect( + (width() - imageSz) / 2, (height() - imageSz) / 2, imageSz, imageSz), + source); + } } else { p.save(); diff --git a/src/CommunitiesListItem.h b/src/CommunitiesListItem.h index 535a6ec0..a80e3200 100644 --- a/src/CommunitiesListItem.h +++ b/src/CommunitiesListItem.h @@ -3,17 +3,22 @@ #include #include +#include + #include "Config.h" #include "ui/Theme.h" class RippleOverlay; class QMouseEvent; +class QMenu; class CommunitiesListItem : public QWidget { Q_OBJECT Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE setHighlightedBackgroundColor) + Q_PROPERTY(QColor disabledBackgroundColor READ disabledBackgroundColor WRITE + setDisabledBackgroundColor) Q_PROPERTY( QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor) Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor) @@ -26,16 +31,18 @@ public: void setName(QString name); bool isPressed() const { return isPressed_; } + bool isDisabled() const { return isDisabled_; } void setAvatar(const QImage &img); - void setRooms(std::map room_ids) { room_ids_ = std::move(room_ids); } - void addRoom(const QString &id) { room_ids_[id] = true; } + void setRooms(std::set room_ids) { room_ids_ = std::move(room_ids); } + void addRoom(const QString &id) { room_ids_.insert(id); } void delRoom(const QString &id) { room_ids_.erase(id); } - std::map rooms() const { return room_ids_; } + std::set rooms() const { return room_ids_; } bool is_tag() const { return groupId_.startsWith("tag:"); } QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; } + QColor disabledBackgroundColor() const { return disabledBackgroundColor_; } QColor hoverBackgroundColor() const { return hoverBackgroundColor_; } QColor backgroundColor() const { return backgroundColor_; } @@ -43,6 +50,7 @@ public: QColor avatarBgColor() const { return avatarBgColor_; } void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; } + void setDisabledBackgroundColor(QColor &color) { disabledBackgroundColor_ = color; } void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; } void setBackgroundColor(QColor &color) { backgroundColor_ = color; } @@ -56,13 +64,16 @@ public: signals: void clicked(const QString &group_id); + void isDisabledChanged(); public slots: void setPressedState(bool state); + void setDisabled(bool state); protected: void mousePressEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; + void contextMenuEvent(QContextMenuEvent *event) override; private: const int IconSize = 36; @@ -70,20 +81,24 @@ private: QString resolveName() const; void updateTooltip(); - std::map room_ids_; + std::set room_ids_; QString name_; QString groupId_; QPixmap avatar_; QColor highlightedBackgroundColor_; + QColor disabledBackgroundColor_; QColor hoverBackgroundColor_; QColor backgroundColor_; QColor avatarFgColor_; QColor avatarBgColor_; - bool isPressed_ = false; + bool isPressed_ = false; + bool isDisabled_ = false; RippleOverlay *rippleOverlay_; + QMenu *menu_; + QAction *hideRoomsWithTagAction_; }; diff --git a/src/MatrixClient.cpp b/src/MatrixClient.cpp index b69ba480..669dc270 100644 --- a/src/MatrixClient.cpp +++ b/src/MatrixClient.cpp @@ -1,6 +1,7 @@ #include "MatrixClient.h" #include +#include #include #include @@ -21,6 +22,7 @@ Q_DECLARE_METATYPE(nlohmann::json) Q_DECLARE_METATYPE(std::string) Q_DECLARE_METATYPE(std::vector) Q_DECLARE_METATYPE(std::vector) +Q_DECLARE_METATYPE(std::set) namespace { auto client_ = std::make_shared(); @@ -55,6 +57,7 @@ init() qRegisterMetaType>(); qRegisterMetaType>(); qRegisterMetaType>("std::map"); + qRegisterMetaType>(); } } // namespace http diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp index 427af632..b5ba5af1 100644 --- a/src/RoomInfoListItem.cpp +++ b/src/RoomInfoListItem.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include "Splitter.h" #include "UserSettingsPage.h" #include "Utils.h" -#include "ui/Menu.h" #include "ui/Ripple.h" #include "ui/RippleOverlay.h" @@ -98,7 +98,7 @@ RoomInfoListItem::init(QWidget *parent) bubbleDiameter_ = QFontMetrics(unreadCountFont_).averageCharWidth() * 3; - menu_ = new Menu(this); + menu_ = new QMenu(this); leaveRoom_ = new QAction(tr("Leave room"), this); connect(leaveRoom_, &QAction::triggered, this, [this]() { emit leaveRoom(roomId_); }); diff --git a/src/RoomInfoListItem.h b/src/RoomInfoListItem.h index af919592..baa8b98b 100644 --- a/src/RoomInfoListItem.h +++ b/src/RoomInfoListItem.h @@ -28,7 +28,7 @@ #include "UserSettingsPage.h" #include "ui/Avatar.h" -class Menu; +class QMenu; class RippleOverlay; class RoomInfoListItem : public QWidget @@ -178,7 +178,7 @@ private: DescInfo lastMsgInfo_; - Menu *menu_; + QMenu *menu_; QAction *leaveRoom_; bool isPressed_ = false; diff --git a/src/RoomList.cpp b/src/RoomList.cpp index aab89491..764a8e42 100644 --- a/src/RoomList.cpp +++ b/src/RoomList.cpp @@ -50,8 +50,8 @@ RoomList::RoomList(QSharedPointer userSettings, QWidget *parent) QScroller::grabGesture(scrollArea_, QScroller::TouchGesture); QScroller::grabGesture(scrollArea_, QScroller::LeftMouseButtonGesture); - // The scrollbar on macOS will hide itself when not active so it won't interfere - // with the content. +// The scrollbar on macOS will hide itself when not active so it won't interfere +// with the content. #if not defined(Q_OS_MAC) scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); #endif @@ -411,20 +411,24 @@ RoomList::closeJoinRoomDialog(bool isJoining, QString roomAlias) } void -RoomList::removeFilter() +RoomList::removeFilter(const std::set &roomsToHide) { setUpdatesEnabled(false); for (int i = 0; i < contentsLayout_->count(); i++) { auto widget = qobject_cast(contentsLayout_->itemAt(i)->widget()); - if (widget) - widget->show(); + if (widget) { + if (roomsToHide.find(widget->roomId()) == roomsToHide.end()) + widget->show(); + else + widget->hide(); + } } setUpdatesEnabled(true); } void -RoomList::applyFilter(const std::map &filter) +RoomList::applyFilter(const std::set &filter) { // Disabling paint updates will resolve issues with screen flickering on big room lists. setUpdatesEnabled(false); diff --git a/src/RoomList.h b/src/RoomList.h index 02aac869..5350a2ab 100644 --- a/src/RoomList.h +++ b/src/RoomList.h @@ -23,6 +23,8 @@ #include #include +#include + #include "CacheStructs.h" #include "UserSettingsPage.h" @@ -54,9 +56,9 @@ public: void addInvitedRoom(const QString &room_id, const RoomInfo &info); void removeRoom(const QString &room_id, bool reset); //! Hide rooms that are not present in the given filter. - void applyFilter(const std::map &rooms); + void applyFilter(const std::set &rooms); //! Show all the available rooms. - void removeFilter(); + void removeFilter(const std::set &roomsToHide); void updateRoom(const QString &room_id, const RoomInfo &info); void cleanupInvites(const std::map &invites);