Better Highlights (#1320)

* Support for user-defined sounds and colors

* Make color & sound columns selectable

* Add custom row for subscription highlights

* Add subscriptions to custom highlights and centrally manage highlight colors

* Dynamically update message highlight colors
This commit is contained in:
Leon Richardt
2020-01-25 11:03:10 +01:00
committed by pajlada
parent 00414eb779
commit 5957551d06
29 changed files with 1822 additions and 187 deletions
+69 -64
View File
@@ -1,5 +1,6 @@
#pragma once
#include "providers/colors/ColorProvider.hpp"
#include "util/RapidJsonSerializeQString.hpp"
#include "util/RapidjsonHelpers.hpp"
@@ -12,70 +13,64 @@ namespace chatterino {
class HighlightPhrase
{
public:
bool operator==(const HighlightPhrase &other) const
{
return std::tie(this->pattern_, this->sound_, this->alert_,
this->isRegex_, this->caseSensitive_) ==
std::tie(other.pattern_, other.sound_, other.alert_,
other.isRegex_, other.caseSensitive_);
}
bool operator==(const HighlightPhrase &other) const;
HighlightPhrase(const QString &pattern, bool alert, bool sound,
bool isRegex, bool caseSensitive)
: pattern_(pattern)
, alert_(alert)
, sound_(sound)
, isRegex_(isRegex)
, caseSensitive_(caseSensitive)
, regex_(
isRegex_ ? pattern
: "\\b" + QRegularExpression::escape(pattern) + "\\b",
QRegularExpression::UseUnicodePropertiesOption |
(caseSensitive_ ? QRegularExpression::NoPatternOption
: QRegularExpression::CaseInsensitiveOption))
{
}
HighlightPhrase(const QString &pattern, bool hasAlert, bool hasSound,
bool isRegex, bool isCaseSensitive, const QString &soundUrl,
QColor color);
const QString &getPattern() const
{
return this->pattern_;
}
bool getAlert() const
{
return this->alert_;
}
bool getSound() const
{
return this->sound_;
}
bool isRegex() const
{
return this->isRegex_;
}
HighlightPhrase(const QString &pattern, bool hasAlert, bool hasSound,
bool isRegex, bool isCaseSensitive, const QString &soundUrl,
std::shared_ptr<QColor> color);
bool isValid() const
{
return !this->pattern_.isEmpty() && this->regex_.isValid();
}
const QString &getPattern() const;
bool hasAlert() const;
bool isMatch(const QString &subject) const
{
return this->isValid() && this->regex_.match(subject).hasMatch();
}
/**
* @brief Check if this highlight phrase should play a sound when
* triggered.
*
* In distinction from `HighlightPhrase::hasCustomSound`, this method only
* checks whether or not ANY sound should be played when the phrase is
* triggered.
*
* To check whether a custom sound is set, use
* `HighlightPhrase::hasCustomSound` instead.
*
* @return true, if this highlight phrase should play a sound when
* triggered, false otherwise
*/
bool hasSound() const;
bool isCaseSensitive() const
{
return this->caseSensitive_;
}
/**
* @brief Check if this highlight phrase has a custom sound set.
*
* Note that this method only checks whether the path to the custom sound
* is not empty. It does not check whether the file still exists, is a
* sound file, or anything else.
*
* @return true, if the custom sound file path is not empty, false otherwise
*/
bool hasCustomSound() const;
bool isRegex() const;
bool isValid() const;
bool isMatch(const QString &subject) const;
bool isCaseSensitive() const;
const QUrl &getSoundUrl() const;
const std::shared_ptr<QColor> getColor() const;
private:
QString pattern_;
bool alert_;
bool sound_;
bool hasAlert_;
bool hasSound_;
bool isRegex_;
bool caseSensitive_;
bool isCaseSensitive_;
QUrl soundUrl_;
std::shared_ptr<QColor> color_;
QRegularExpression regex_;
};
} // namespace chatterino
namespace pajlada {
@@ -88,10 +83,13 @@ struct Serialize<chatterino::HighlightPhrase> {
rapidjson::Value ret(rapidjson::kObjectType);
chatterino::rj::set(ret, "pattern", value.getPattern(), a);
chatterino::rj::set(ret, "alert", value.getAlert(), a);
chatterino::rj::set(ret, "sound", value.getSound(), a);
chatterino::rj::set(ret, "alert", value.hasAlert(), a);
chatterino::rj::set(ret, "sound", value.hasSound(), a);
chatterino::rj::set(ret, "regex", value.isRegex(), a);
chatterino::rj::set(ret, "case", value.isCaseSensitive(), a);
chatterino::rj::set(ret, "soundUrl", value.getSoundUrl().toString(), a);
chatterino::rj::set(ret, "color",
value.getColor()->name(QColor::HexArgb), a);
return ret;
}
@@ -104,23 +102,30 @@ struct Deserialize<chatterino::HighlightPhrase> {
if (!value.IsObject())
{
return chatterino::HighlightPhrase(QString(), true, false, false,
false);
false, "", QColor());
}
QString _pattern;
bool _alert = true;
bool _sound = false;
bool _hasAlert = true;
bool _hasSound = false;
bool _isRegex = false;
bool _caseSensitive = false;
bool _isCaseSensitive = false;
QString _soundUrl;
QString encodedColor;
chatterino::rj::getSafe(value, "pattern", _pattern);
chatterino::rj::getSafe(value, "alert", _alert);
chatterino::rj::getSafe(value, "sound", _sound);
chatterino::rj::getSafe(value, "alert", _hasAlert);
chatterino::rj::getSafe(value, "sound", _hasSound);
chatterino::rj::getSafe(value, "regex", _isRegex);
chatterino::rj::getSafe(value, "case", _caseSensitive);
chatterino::rj::getSafe(value, "case", _isCaseSensitive);
chatterino::rj::getSafe(value, "soundUrl", _soundUrl);
chatterino::rj::getSafe(value, "color", encodedColor);
return chatterino::HighlightPhrase(_pattern, _alert, _sound, _isRegex,
_caseSensitive);
auto _color = QColor(encodedColor);
return chatterino::HighlightPhrase(_pattern, _hasAlert, _hasSound,
_isRegex, _isCaseSensitive,
_soundUrl, _color);
}
};