From bfcc9ff7a4f042f02b1780b9f506831c0ac2b284 Mon Sep 17 00:00:00 2001 From: xel86 Date: Sat, 1 Oct 2022 08:30:29 -0400 Subject: [PATCH] Add search predicates for badges and sub tiers (#4013) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 2 + src/CMakeLists.txt | 4 ++ src/messages/search/BadgePredicate.cpp | 48 ++++++++++++++++++++++++ src/messages/search/BadgePredicate.hpp | 38 +++++++++++++++++++ src/messages/search/SubtierPredicate.cpp | 35 +++++++++++++++++ src/messages/search/SubtierPredicate.hpp | 38 +++++++++++++++++++ src/widgets/helper/SearchPopup.cpp | 26 +++++++++++++ 7 files changed, 191 insertions(+) create mode 100644 src/messages/search/BadgePredicate.cpp create mode 100644 src/messages/search/BadgePredicate.hpp create mode 100644 src/messages/search/SubtierPredicate.cpp create mode 100644 src/messages/search/SubtierPredicate.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index e08fc631a..8fe87b659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ - Minor: Clicking `A message from x was deleted` messages will now jump to the message in question. (#3953) - Minor: Added `is:first-msg` search option. (#3700) - Minor: Added `is:elevated-msg` search option. (#4018) +- Minor: Added `subtier:` search option (e.g. `subtier:3` to find Tier 3 subs). (#4013) +- Minor: Added `badge:` search option (e.g. `badge:mod` to users with the moderator badge). (#4013) - Minor: Added AutoMod message flag filter. (#3938) - Minor: Added chatter count for each category in viewer list. (#3683, #3719) - Minor: Added option to open a user's chat in a new tab from the usercard profile picture context menu. (#3625) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af6067cf7..c9618370e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -156,6 +156,8 @@ set(SOURCE_FILES messages/layouts/MessageLayoutElement.hpp messages/search/AuthorPredicate.cpp messages/search/AuthorPredicate.hpp + messages/search/BadgePredicate.cpp + messages/search/BadgePredicate.hpp messages/search/ChannelPredicate.cpp messages/search/ChannelPredicate.hpp messages/search/LinkPredicate.cpp @@ -166,6 +168,8 @@ set(SOURCE_FILES messages/search/RegexPredicate.hpp messages/search/SubstringPredicate.cpp messages/search/SubstringPredicate.hpp + messages/search/SubtierPredicate.cpp + messages/search/SubtierPredicate.hpp providers/IvrApi.cpp providers/IvrApi.hpp diff --git a/src/messages/search/BadgePredicate.cpp b/src/messages/search/BadgePredicate.cpp new file mode 100644 index 000000000..308624658 --- /dev/null +++ b/src/messages/search/BadgePredicate.cpp @@ -0,0 +1,48 @@ +#include "messages/search/BadgePredicate.hpp" + +#include "util/Qt.hpp" + +namespace chatterino { + +BadgePredicate::BadgePredicate(const QStringList &badges) +{ + // Check if any comma-seperated values were passed and transform those + for (const auto &entry : badges) + { + for (const auto &badge : entry.split(',', Qt::SkipEmptyParts)) + { + // convert short form name of certain badges to formal name + if (badge.compare("mod", Qt::CaseInsensitive) == 0) + { + this->badges_ << "moderator"; + } + else if (badge.compare("sub", Qt::CaseInsensitive) == 0) + { + this->badges_ << "subscriber"; + } + else if (badge.compare("prime", Qt::CaseInsensitive) == 0) + { + this->badges_ << "premium"; + } + else + { + this->badges_ << badge; + } + } + } +} + +bool BadgePredicate::appliesTo(const Message &message) +{ + for (const Badge &badge : message.badges) + { + if (badges_.contains(badge.key_, Qt::CaseInsensitive)) + { + return true; + } + } + + return false; +} + +} // namespace chatterino diff --git a/src/messages/search/BadgePredicate.hpp b/src/messages/search/BadgePredicate.hpp new file mode 100644 index 000000000..f4e990eec --- /dev/null +++ b/src/messages/search/BadgePredicate.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "messages/search/MessagePredicate.hpp" + +namespace chatterino { + +/** + * @brief MessagePredicate checking for the badges of a message. + * + * This predicate will only allow messages that are sent by a list of users, + * specified by their user names, who have a badge specified (i.e 'staff'). + */ +class BadgePredicate : public MessagePredicate +{ +public: + /** + * @brief Create an BadgePredicate with a list of badges to search for. + * + * @param badges a list of badges that a message should contain + */ + BadgePredicate(const QStringList &badges); + + /** + * @brief Checks whether the message contains any of the badges passed + * in the constructor. + * + * @param message the message to check + * @return true if the message contains a badge listed in the specified badges, + * false otherwise + */ + bool appliesTo(const Message &message) override; + +private: + /// Holds the badges that will be searched for + QStringList badges_; +}; + +} // namespace chatterino diff --git a/src/messages/search/SubtierPredicate.cpp b/src/messages/search/SubtierPredicate.cpp new file mode 100644 index 000000000..8c4ce3f13 --- /dev/null +++ b/src/messages/search/SubtierPredicate.cpp @@ -0,0 +1,35 @@ +#include "messages/search/SubtierPredicate.hpp" + +#include "util/Qt.hpp" + +namespace chatterino { + +SubtierPredicate::SubtierPredicate(const QStringList &subtiers) +{ + // Check if any comma-seperated values were passed and transform those + for (const auto &entry : subtiers) + { + for (const auto &subtier : entry.split(',', Qt::SkipEmptyParts)) + { + this->subtiers_ << subtier; + } + } +} + +bool SubtierPredicate::appliesTo(const Message &message) +{ + for (const Badge &badge : message.badges) + { + if (badge.key_ == "subscriber") + { + const auto &subTier = + badge.value_.length() > 3 ? badge.value_.at(0) : '1'; + + return subtiers_.contains(subTier); + } + } + + return false; +} + +} // namespace chatterino diff --git a/src/messages/search/SubtierPredicate.hpp b/src/messages/search/SubtierPredicate.hpp new file mode 100644 index 000000000..87bcfe10d --- /dev/null +++ b/src/messages/search/SubtierPredicate.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "messages/search/MessagePredicate.hpp" + +namespace chatterino { + +/** + * @brief MessagePredicate checking for the badges of a message. + * + * This predicate will only allow messages that are sent by a subscribed user + * who has a specified subtier (i.e. 1,2,3..) + */ +class SubtierPredicate : public MessagePredicate +{ +public: + /** + * @brief Create an SubtierPredicate with a list of subtiers to search for. + * + * @param subtiers a list of subtiers that a message should contain + */ + SubtierPredicate(const QStringList &subtiers); + + /** + * @brief Checks whether the message contains any of the subtiers passed + * in the constructor. + * + * @param message the message to check + * @return true if the message contains a subtier listed in the specified subtiers, + * false otherwise + */ + bool appliesTo(const Message &message) override; + +private: + /// Holds the subtiers that will be searched for + QStringList subtiers_; +}; + +} // namespace chatterino diff --git a/src/widgets/helper/SearchPopup.cpp b/src/widgets/helper/SearchPopup.cpp index 85d2e21f0..f09186165 100644 --- a/src/widgets/helper/SearchPopup.cpp +++ b/src/widgets/helper/SearchPopup.cpp @@ -7,11 +7,13 @@ #include "common/Channel.hpp" #include "controllers/hotkeys/HotkeyController.hpp" #include "messages/search/AuthorPredicate.hpp" +#include "messages/search/BadgePredicate.hpp" #include "messages/search/ChannelPredicate.hpp" #include "messages/search/LinkPredicate.hpp" #include "messages/search/MessageFlagsPredicate.hpp" #include "messages/search/RegexPredicate.hpp" #include "messages/search/SubstringPredicate.hpp" +#include "messages/search/SubtierPredicate.hpp" #include "singletons/WindowManager.hpp" #include "widgets/helper/ChannelView.hpp" @@ -297,6 +299,8 @@ std::vector> SearchPopup::parsePredicates( std::vector> predicates; QStringList authors; QStringList channels; + QStringList badges; + QStringList subtiers; while (it.hasNext()) { @@ -312,6 +316,14 @@ std::vector> SearchPopup::parsePredicates( { authors.append(value); } + else if (name == "badge") + { + badges.append(value); + } + else if (name == "subtier") + { + subtiers.append(value); + } else if (name == "has" && value == "link") { predicates.push_back(std::make_unique()); @@ -337,10 +349,24 @@ std::vector> SearchPopup::parsePredicates( } if (!authors.empty()) + { predicates.push_back(std::make_unique(authors)); + } if (!channels.empty()) + { predicates.push_back(std::make_unique(channels)); + } + + if (!badges.empty()) + { + predicates.push_back(std::make_unique(badges)); + } + + if (!subtiers.empty()) + { + predicates.push_back(std::make_unique(subtiers)); + } return predicates; }