1 #pragma once 2 3 #include "providers/colors/ColorProvider.hpp" 4 #include "util/RapidJsonSerializeQString.hpp" 5 #include "util/RapidjsonHelpers.hpp" 6 7 #include <QColor> 8 #include <QRegularExpression> 9 #include <QString> 10 #include <QUrl> 11 #include <pajlada/serialize.hpp> 12 13 #include <memory> 14 15 namespace chatterino { 16 17 class HighlightPhrase 18 { 19 public: 20 bool operator==(const HighlightPhrase &other) const; 21 22 /** 23 * @brief Create a new HighlightPhrase. 24 * 25 * Use this constructor when creating a new HighlightPhrase. 26 */ 27 HighlightPhrase(const QString &pattern, bool showInMentions, bool hasAlert, 28 bool hasSound, bool isRegex, bool isCaseSensitive, 29 const QString &soundUrl, QColor color); 30 31 /** 32 * @brief Create a new HighlightPhrase. 33 * 34 * Use this constructor when updating an existing HighlightPhrase's color. 35 */ 36 HighlightPhrase(const QString &pattern, bool showInMentions, bool hasAlert, 37 bool hasSound, bool isRegex, bool isCaseSensitive, 38 const QString &soundUrl, std::shared_ptr<QColor> color); 39 40 const QString &getPattern() const; 41 bool showInMentions() const; 42 bool hasAlert() const; 43 44 /** 45 * @brief Check if this highlight phrase should play a sound when 46 * triggered. 47 * 48 * In distinction from `HighlightPhrase::hasCustomSound`, this method only 49 * checks whether or not ANY sound should be played when the phrase is 50 * triggered. 51 * 52 * To check whether a custom sound is set, use 53 * `HighlightPhrase::hasCustomSound` instead. 54 * 55 * @return true, if this highlight phrase should play a sound when 56 * triggered, false otherwise 57 */ 58 bool hasSound() const; 59 60 /** 61 * @brief Check if this highlight phrase has a custom sound set. 62 * 63 * Note that this method only checks whether the path to the custom sound 64 * is not empty. It does not check whether the file still exists, is a 65 * sound file, or anything else. 66 * 67 * @return true, if the custom sound file path is not empty, false otherwise 68 */ 69 bool hasCustomSound() const; 70 71 bool isRegex() const; 72 bool isValid() const; 73 bool isMatch(const QString &subject) const; 74 bool isCaseSensitive() const; 75 const QUrl &getSoundUrl() const; 76 const std::shared_ptr<QColor> getColor() const; 77 78 /* 79 * XXX: Use the constexpr constructor here once we are building with 80 * Qt>=5.13. 81 */ 82 static QColor FALLBACK_HIGHLIGHT_COLOR; 83 static QColor FALLBACK_REDEEMED_HIGHLIGHT_COLOR; 84 static QColor FALLBACK_SUB_COLOR; 85 86 private: 87 QString pattern_; 88 bool showInMentions_; 89 bool hasAlert_; 90 bool hasSound_; 91 bool isRegex_; 92 bool isCaseSensitive_; 93 QUrl soundUrl_; 94 std::shared_ptr<QColor> color_; 95 QRegularExpression regex_; 96 }; 97 98 } // namespace chatterino 99 100 namespace pajlada { 101 102 namespace { constructError()103 chatterino::HighlightPhrase constructError() 104 { 105 return chatterino::HighlightPhrase(QString(), false, false, false, 106 false, false, QString(), QColor()); 107 } 108 } // namespace 109 110 template <> 111 struct Serialize<chatterino::HighlightPhrase> { getpajlada::Serialize112 static rapidjson::Value get(const chatterino::HighlightPhrase &value, 113 rapidjson::Document::AllocatorType &a) 114 { 115 rapidjson::Value ret(rapidjson::kObjectType); 116 117 chatterino::rj::set(ret, "pattern", value.getPattern(), a); 118 chatterino::rj::set(ret, "showInMentions", value.showInMentions(), a); 119 chatterino::rj::set(ret, "alert", value.hasAlert(), a); 120 chatterino::rj::set(ret, "sound", value.hasSound(), a); 121 chatterino::rj::set(ret, "regex", value.isRegex(), a); 122 chatterino::rj::set(ret, "case", value.isCaseSensitive(), a); 123 chatterino::rj::set(ret, "soundUrl", value.getSoundUrl().toString(), a); 124 chatterino::rj::set(ret, "color", 125 value.getColor()->name(QColor::HexArgb), a); 126 127 return ret; 128 } 129 }; 130 131 template <> 132 struct Deserialize<chatterino::HighlightPhrase> { getpajlada::Deserialize133 static chatterino::HighlightPhrase get(const rapidjson::Value &value, 134 bool *error = nullptr) 135 { 136 if (!value.IsObject()) 137 { 138 PAJLADA_REPORT_ERROR(error) 139 140 return constructError(); 141 } 142 143 QString _pattern; 144 bool _showInMentions = true; 145 bool _hasAlert = true; 146 bool _hasSound = false; 147 bool _isRegex = false; 148 bool _isCaseSensitive = false; 149 QString _soundUrl; 150 QString encodedColor; 151 152 chatterino::rj::getSafe(value, "pattern", _pattern); 153 chatterino::rj::getSafe(value, "showInMentions", _showInMentions); 154 chatterino::rj::getSafe(value, "alert", _hasAlert); 155 chatterino::rj::getSafe(value, "sound", _hasSound); 156 chatterino::rj::getSafe(value, "regex", _isRegex); 157 chatterino::rj::getSafe(value, "case", _isCaseSensitive); 158 chatterino::rj::getSafe(value, "soundUrl", _soundUrl); 159 chatterino::rj::getSafe(value, "color", encodedColor); 160 161 auto _color = QColor(encodedColor); 162 if (!_color.isValid()) 163 _color = chatterino::HighlightPhrase::FALLBACK_HIGHLIGHT_COLOR; 164 165 return chatterino::HighlightPhrase(_pattern, _showInMentions, _hasAlert, 166 _hasSound, _isRegex, 167 _isCaseSensitive, _soundUrl, _color); 168 } 169 }; 170 171 } // namespace pajlada 172