Overhaul highlight system (#3399)

Checks have been moved into a Controller allowing for easier tests.
This commit is contained in:
pajlada
2022-06-05 17:40:57 +02:00
committed by GitHub
parent 6c38d3ecab
commit 7ccf60111d
20 changed files with 1112 additions and 240 deletions
+2
View File
@@ -7,6 +7,7 @@
#include "common/Version.hpp"
#include "controllers/accounts/AccountController.hpp"
#include "controllers/commands/CommandController.hpp"
#include "controllers/highlights/HighlightController.hpp"
#include "controllers/hotkeys/HotkeyController.hpp"
#include "controllers/ignores/IgnoreController.hpp"
#include "controllers/notifications/NotificationController.hpp"
@@ -67,6 +68,7 @@ Application::Application(Settings &_settings, Paths &_paths)
, commands(&this->emplace<CommandController>())
, notifications(&this->emplace<NotificationController>())
, highlights(&this->emplace<HighlightController>())
, twitch(&this->emplace<TwitchIrcServer>())
, chatterinoBadges(&this->emplace<ChatterinoBadges>())
, ffzBadges(&this->emplace<FfzBadges>())
+2
View File
@@ -15,6 +15,7 @@ class PubSub;
class CommandController;
class AccountController;
class NotificationController;
class HighlightController;
class HotkeyController;
class Theme;
@@ -80,6 +81,7 @@ public:
CommandController *const commands{};
NotificationController *const notifications{};
HighlightController *const highlights{};
TwitchIrcServer *const twitch{};
ChatterinoBadges *const chatterinoBadges{};
FfzBadges *const ffzBadges{};
+1 -1
View File
@@ -112,7 +112,7 @@ Settings *getSettings()
static_assert(std::is_same_v<AB_SETTINGS_CLASS, Settings>,
"`AB_SETTINGS_CLASS` must be the same as `Settings`");
assert(AB_SETTINGS_CLASS::instance);
assert(AB_SETTINGS_CLASS::instance != nullptr);
return AB_SETTINGS_CLASS::instance;
}
+3 -2
View File
@@ -1,12 +1,13 @@
#ifndef AB_SETTINGS_H
#define AB_SETTINGS_H
#include "common/ChatterinoSetting.hpp"
#include <rapidjson/document.h>
#include <QString>
#include <memory>
#include <pajlada/settings/settingdata.hpp>
#include "common/ChatterinoSetting.hpp"
#include <memory>
#ifdef AB_CUSTOM_SETTINGS
# define AB_SETTINGS_CLASS ABSettings
+2
View File
@@ -81,6 +81,8 @@ set(SOURCE_FILES
controllers/highlights/HighlightBadge.hpp
controllers/highlights/HighlightBlacklistModel.cpp
controllers/highlights/HighlightBlacklistModel.hpp
controllers/highlights/HighlightController.cpp
controllers/highlights/HighlightController.hpp
controllers/highlights/HighlightModel.cpp
controllers/highlights/HighlightModel.hpp
controllers/highlights/HighlightPhrase.cpp
+1
View File
@@ -39,3 +39,4 @@ Q_LOGGING_CATEGORY(chatterinoWebsocket, "chatterino.websocket", logThreshold);
Q_LOGGING_CATEGORY(chatterinoWidget, "chatterino.widget", logThreshold);
Q_LOGGING_CATEGORY(chatterinoWindowmanager, "chatterino.windowmanager",
logThreshold);
Q_LOGGING_CATEGORY(chatterinoHighlights, "chatterino.highlights", logThreshold);
+1
View File
@@ -30,3 +30,4 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoUpdate);
Q_DECLARE_LOGGING_CATEGORY(chatterinoWebsocket);
Q_DECLARE_LOGGING_CATEGORY(chatterinoWidget);
Q_DECLARE_LOGGING_CATEGORY(chatterinoWindowmanager);
Q_DECLARE_LOGGING_CATEGORY(chatterinoHighlights);
@@ -0,0 +1,358 @@
#include "controllers/highlights/HighlightController.hpp"
#include "common/QLogging.hpp"
namespace {
using namespace chatterino;
auto highlightPhraseCheck(HighlightPhrase highlight) -> HighlightCheck
{
return HighlightCheck{
[highlight](
const auto &args, const auto &badges, const auto &senderName,
const auto &originalMessage) -> boost::optional<HighlightResult> {
(void)args; // unused
(void)badges; // unused
(void)originalMessage; // unused
if (!highlight.isMatch(originalMessage))
{
return boost::none;
}
boost::optional<QUrl> highlightSoundUrl;
if (highlight.hasCustomSound())
{
highlightSoundUrl = highlight.getSoundUrl();
}
return HighlightResult{
highlight.hasAlert(), highlight.hasSound(),
highlightSoundUrl, highlight.getColor(),
highlight.showInMentions(),
};
}};
}
void rebuildSubscriptionHighlights(Settings &settings,
std::vector<HighlightCheck> &checks)
{
if (settings.enableSubHighlight)
{
auto highlightSound = settings.enableSubHighlightSound.getValue();
auto highlightAlert = settings.enableSubHighlightTaskbar.getValue();
auto highlightSoundUrlValue =
settings.whisperHighlightSoundUrl.getValue();
boost::optional<QUrl> highlightSoundUrl;
if (!highlightSoundUrlValue.isEmpty())
{
highlightSoundUrl = highlightSoundUrlValue;
}
// The custom sub highlight color is handled in ColorProvider
checks.emplace_back(HighlightCheck{
[=](const auto &args, const auto &badges, const auto &senderName,
const auto &originalMessage)
-> boost::optional<HighlightResult> {
(void)badges; // unused
(void)senderName; // unused
(void)originalMessage; // unused
if (!args.isSubscriptionMessage)
{
return boost::none;
}
auto highlightColor =
ColorProvider::instance().color(ColorType::Subscription);
return HighlightResult{
highlightAlert, // alert
highlightSound, // playSound
highlightSoundUrl, // customSoundUrl
highlightColor, // color
false, // showInMentions
};
}});
}
}
void rebuildWhisperHighlights(Settings &settings,
std::vector<HighlightCheck> &checks)
{
if (settings.enableWhisperHighlight)
{
auto highlightSound = settings.enableWhisperHighlightSound.getValue();
auto highlightAlert = settings.enableWhisperHighlightTaskbar.getValue();
auto highlightSoundUrlValue =
settings.whisperHighlightSoundUrl.getValue();
boost::optional<QUrl> highlightSoundUrl;
if (!highlightSoundUrlValue.isEmpty())
{
highlightSoundUrl = highlightSoundUrlValue;
}
// The custom whisper highlight color is handled in ColorProvider
checks.emplace_back(HighlightCheck{
[=](const auto &args, const auto &badges, const auto &senderName,
const auto &originalMessage)
-> boost::optional<HighlightResult> {
(void)badges; // unused
(void)senderName; // unused
(void)originalMessage; // unused
if (!args.isReceivedWhisper)
{
return boost::none;
}
return HighlightResult{
highlightAlert,
highlightSound,
highlightSoundUrl,
ColorProvider::instance().color(ColorType::Whisper),
false,
};
}});
}
}
void rebuildMessageHighlights(Settings &settings,
std::vector<HighlightCheck> &checks)
{
auto currentUser = getIApp()->getAccounts()->twitch.getCurrent();
QString currentUsername = currentUser->getUserName();
if (settings.enableSelfHighlight && !currentUsername.isEmpty())
{
HighlightPhrase highlight(
currentUsername, settings.showSelfHighlightInMentions,
settings.enableSelfHighlightTaskbar,
settings.enableSelfHighlightSound, false, false,
settings.selfHighlightSoundUrl.getValue(),
ColorProvider::instance().color(ColorType::SelfHighlight));
checks.emplace_back(highlightPhraseCheck(highlight));
}
auto messageHighlights = settings.highlightedMessages.readOnly();
for (const auto &highlight : *messageHighlights)
{
checks.emplace_back(highlightPhraseCheck(highlight));
}
}
void rebuildUserHighlights(Settings &settings,
std::vector<HighlightCheck> &checks)
{
auto userHighlights = settings.highlightedUsers.readOnly();
for (const auto &highlight : *userHighlights)
{
checks.emplace_back(HighlightCheck{
[highlight](const auto &args, const auto &badges,
const auto &senderName, const auto &originalMessage)
-> boost::optional<HighlightResult> {
(void)args; // unused
(void)badges; // unused
(void)originalMessage; // unused
if (!highlight.isMatch(senderName))
{
return boost::none;
}
boost::optional<QUrl> highlightSoundUrl;
if (highlight.hasCustomSound())
{
highlightSoundUrl = highlight.getSoundUrl();
}
return HighlightResult{
highlight.hasAlert(),
highlight.hasSound(),
highlightSoundUrl,
highlight.getColor(),
false, // showInMentions
};
}});
}
}
void rebuildBadgeHighlights(Settings &settings,
std::vector<HighlightCheck> &checks)
{
auto badgeHighlights = settings.highlightedBadges.readOnly();
for (const auto &highlight : *badgeHighlights)
{
checks.emplace_back(HighlightCheck{
[highlight](const auto &args, const auto &badges,
const auto &senderName, const auto &originalMessage)
-> boost::optional<HighlightResult> {
(void)args; // unused
(void)senderName; // unused
(void)originalMessage; // unused
for (const Badge &badge : badges)
{
if (highlight.isMatch(badge))
{
boost::optional<QUrl> highlightSoundUrl;
if (highlight.hasCustomSound())
{
highlightSoundUrl = highlight.getSoundUrl();
}
return HighlightResult{
highlight.hasAlert(),
highlight.hasSound(),
highlightSoundUrl,
highlight.getColor(),
false, // showInMentions
};
}
}
return boost::none;
}});
}
}
} // namespace
namespace chatterino {
void HighlightController::initialize(Settings &settings, Paths & /*paths*/)
{
this->rebuildListener_.addSetting(settings.enableWhisperHighlight);
this->rebuildListener_.addSetting(settings.enableWhisperHighlightSound);
this->rebuildListener_.addSetting(settings.enableWhisperHighlightTaskbar);
this->rebuildListener_.addSetting(settings.whisperHighlightSoundUrl);
this->rebuildListener_.addSetting(settings.whisperHighlightColor);
this->rebuildListener_.addSetting(settings.enableSelfHighlight);
this->rebuildListener_.addSetting(settings.enableSubHighlight);
this->rebuildListener_.addSetting(settings.enableSubHighlightSound);
this->rebuildListener_.addSetting(settings.enableSubHighlightTaskbar);
this->rebuildListener_.setCB([this, &settings] {
qCDebug(chatterinoHighlights)
<< "Rebuild checks because a setting changed";
this->rebuildChecks(settings);
});
this->signalHolder_.managedConnect(
getCSettings().highlightedBadges.delayedItemsChanged,
[this, &settings] {
qCDebug(chatterinoHighlights)
<< "Rebuild checks because highlight badges changed";
this->rebuildChecks(settings);
});
this->signalHolder_.managedConnect(
getCSettings().highlightedUsers.delayedItemsChanged, [this, &settings] {
qCDebug(chatterinoHighlights)
<< "Rebuild checks because highlight users changed";
this->rebuildChecks(settings);
});
this->signalHolder_.managedConnect(
getCSettings().highlightedMessages.delayedItemsChanged,
[this, &settings] {
qCDebug(chatterinoHighlights)
<< "Rebuild checks because highlight messages changed";
this->rebuildChecks(settings);
});
getIApp()->getAccounts()->twitch.currentUserChanged.connect(
[this, &settings] {
qCDebug(chatterinoHighlights)
<< "Rebuild checks because user swapped accounts";
this->rebuildChecks(settings);
});
this->rebuildChecks(settings);
}
void HighlightController::rebuildChecks(Settings &settings)
{
// Access checks for modification
auto checks = this->checks_.access();
checks->clear();
// CURRENT ORDER:
// Subscription -> Whisper -> User -> Message -> Badge
rebuildSubscriptionHighlights(settings, *checks);
rebuildWhisperHighlights(settings, *checks);
rebuildUserHighlights(settings, *checks);
rebuildMessageHighlights(settings, *checks);
rebuildBadgeHighlights(settings, *checks);
}
std::pair<bool, HighlightResult> HighlightController::check(
const MessageParseArgs &args, const std::vector<Badge> &badges,
const QString &senderName, const QString &originalMessage) const
{
bool highlighted = false;
auto result = HighlightResult::emptyResult();
// Access for checking
const auto checks = this->checks_.accessConst();
for (const auto &check : *checks)
{
if (auto checkResult =
check.cb(args, badges, senderName, originalMessage);
checkResult)
{
highlighted = true;
if (checkResult->alert)
{
if (!result.alert)
{
result.alert = checkResult->alert;
}
}
if (checkResult->playSound)
{
if (!result.playSound)
{
result.playSound = checkResult->playSound;
}
}
if (checkResult->customSoundUrl)
{
if (!result.customSoundUrl)
{
result.customSoundUrl = checkResult->customSoundUrl;
}
}
if (checkResult->color)
{
if (!result.color)
{
result.color = checkResult->color;
}
}
if (result.full())
{
// The final highlight result does not have room to add any more parameters, early out
break;
}
}
}
return {highlighted, result};
}
} // namespace chatterino
@@ -0,0 +1,159 @@
#pragma once
#include "common/Singleton.hpp"
#include "common/UniqueAccess.hpp"
#include "messages/MessageBuilder.hpp"
#include "providers/twitch/TwitchBadge.hpp"
#include "singletons/Paths.hpp"
#include "singletons/Settings.hpp"
#include <QColor>
#include <QUrl>
#include <boost/optional.hpp>
#include <functional>
#include <memory>
#include <utility>
namespace chatterino {
struct HighlightResult {
HighlightResult(bool _alert, bool _playSound,
boost::optional<QUrl> _customSoundUrl,
std::shared_ptr<QColor> _color, bool _showInMentions)
: alert(_alert)
, playSound(_playSound)
, customSoundUrl(std::move(_customSoundUrl))
, color(std::move(_color))
, showInMentions(_showInMentions)
{
}
/**
* @brief Construct an empty HighlightResult with all side-effects disabled
**/
static HighlightResult emptyResult()
{
return {
false, false, boost::none, nullptr, false,
};
}
/**
* @brief true if highlight should trigger the taskbar to flash
**/
bool alert{false};
/**
* @brief true if highlight should play a notification sound
**/
bool playSound{false};
/**
* @brief Can be set to a different sound that should play when this highlight is activated
*
* May only be set if playSound is true
**/
boost::optional<QUrl> customSoundUrl{};
/**
* @brief set if highlight should set a background color
**/
std::shared_ptr<QColor> color{};
/**
* @brief true if highlight should show message in the /mentions split
**/
bool showInMentions{false};
bool operator==(const HighlightResult &other) const
{
if (this->alert != other.alert)
{
return false;
}
if (this->playSound != other.playSound)
{
return false;
}
if (this->customSoundUrl != other.customSoundUrl)
{
return false;
}
if (this->color && other.color)
{
if (*this->color != *other.color)
{
return false;
}
}
if (this->showInMentions != other.showInMentions)
{
return false;
}
return true;
}
bool operator!=(const HighlightResult &other) const
{
return !(*this == other);
}
/**
* @brief Returns true if no side-effect has been enabled
**/
[[nodiscard]] bool empty() const
{
return !this->alert && !this->playSound &&
!this->customSoundUrl.has_value() && !this->color &&
!this->showInMentions;
}
/**
* @brief Returns true if all side-effects have been enabled
**/
[[nodiscard]] bool full() const
{
return this->alert && this->playSound &&
this->customSoundUrl.has_value() && this->color &&
this->showInMentions;
}
};
struct HighlightCheck {
using Checker = std::function<boost::optional<HighlightResult>(
const MessageParseArgs &args, const std::vector<Badge> &badges,
const QString &senderName, const QString &originalMessage)>;
Checker cb;
};
class HighlightController final : public Singleton
{
public:
void initialize(Settings &settings, Paths &paths) override;
/**
* @brief Checks the given message parameters if it matches our internal checks, and returns a result
**/
[[nodiscard]] std::pair<bool, HighlightResult> check(
const MessageParseArgs &args, const std::vector<Badge> &badges,
const QString &senderName, const QString &originalMessage) const;
private:
/**
* @brief rebuildChecks is called whenever some outside variable has been changed and our checks need to be updated
*
* rebuilds are always full, so if something changes we throw away all checks and build them all up from scratch
**/
void rebuildChecks(Settings &settings);
UniqueAccess<std::vector<HighlightCheck>> checks_;
pajlada::SettingListener rebuildListener_;
pajlada::Signals::SignalHolder signalHolder_;
};
} // namespace chatterino
+1
View File
@@ -34,6 +34,7 @@ struct MessageParseArgs {
bool isSentWhisper = false;
bool trimSubscriberUsername = false;
bool isStaffOrBroadcaster = false;
bool isSubscriptionMessage = false;
QString channelPointRewardId = "";
};
+27 -235
View File
@@ -2,6 +2,7 @@
#include "Application.hpp"
#include "common/QLogging.hpp"
#include "controllers/highlights/HighlightController.hpp"
#include "controllers/ignores/IgnoreController.hpp"
#include "controllers/ignores/IgnorePhrase.hpp"
#include "messages/MessageElement.hpp"
@@ -140,259 +141,50 @@ void SharedMessageBuilder::parseUsername()
void SharedMessageBuilder::parseHighlights()
{
auto app = getApp();
if (getCSettings().isBlacklistedUser(this->ircMessage->nick()))
{
// Do nothing. We ignore highlights from this user.
return;
}
// Highlight because it's a whisper
if (this->args.isReceivedWhisper && getSettings()->enableWhisperHighlight)
auto currentUser = getIApp()->getAccounts()->twitch.getCurrent();
if (this->ircMessage->nick() == currentUser->getUserName())
{
if (getSettings()->enableWhisperHighlightTaskbar)
{
this->highlightAlert_ = true;
}
if (getSettings()->enableWhisperHighlightSound)
{
this->highlightSound_ = true;
// Use custom sound if set, otherwise use fallback
if (!getSettings()->whisperHighlightSoundUrl.getValue().isEmpty())
{
this->highlightSoundUrl_ =
QUrl(getSettings()->whisperHighlightSoundUrl.getValue());
}
else
{
this->highlightSoundUrl_ = getFallbackHighlightSound();
}
}
this->message().highlightColor =
ColorProvider::instance().color(ColorType::Whisper);
/*
* Do _NOT_ return yet, we might want to apply phrase/user name
* highlights (which override whisper color/sound).
*/
}
// Highlight because of sender
auto userHighlights = getCSettings().highlightedUsers.readOnly();
for (const HighlightPhrase &userHighlight : *userHighlights)
{
if (!userHighlight.isMatch(this->ircMessage->nick()))
{
continue;
}
qCDebug(chatterinoMessage)
<< "Highlight because user" << this->ircMessage->nick()
<< "sent a message";
this->message().flags.set(MessageFlag::Highlighted);
if (!(this->message().flags.has(MessageFlag::Subscription) &&
getSettings()->enableSubHighlight))
{
this->message().highlightColor = userHighlight.getColor();
}
if (userHighlight.showInMentions())
{
this->message().flags.set(MessageFlag::ShowInMentions);
}
if (userHighlight.hasAlert())
{
this->highlightAlert_ = true;
}
if (userHighlight.hasSound())
{
this->highlightSound_ = true;
// Use custom sound if set, otherwise use the fallback sound
if (userHighlight.hasCustomSound())
{
this->highlightSoundUrl_ = userHighlight.getSoundUrl();
}
else
{
this->highlightSoundUrl_ = getFallbackHighlightSound();
}
}
if (this->highlightAlert_ && this->highlightSound_)
{
/*
* User name highlights "beat" highlight phrases: If a message has
* all attributes (color, taskbar flashing, sound) set, highlight
* phrases will not be checked.
*/
return;
}
}
auto currentUser = app->accounts->twitch.getCurrent();
QString currentUsername = currentUser->getUserName();
if (this->ircMessage->nick() == currentUsername)
{
// Do nothing. Highlights cannot be triggered by yourself
// Do nothing. We ignore any potential highlights from the logged in user
return;
}
// Highlight because it's a subscription
if (this->message().flags.has(MessageFlag::Subscription) &&
getSettings()->enableSubHighlight)
auto badges = SharedMessageBuilder::parseBadgeTag(this->tags);
auto [highlighted, highlightResult] = getApp()->highlights->check(
this->args, badges, this->ircMessage->nick(), this->originalMessage_);
if (!highlighted)
{
if (getSettings()->enableSubHighlightTaskbar)
{
this->highlightAlert_ = true;
}
if (getSettings()->enableSubHighlightSound)
{
this->highlightSound_ = true;
// Use custom sound if set, otherwise use fallback
if (!getSettings()->subHighlightSoundUrl.getValue().isEmpty())
{
this->highlightSoundUrl_ =
QUrl(getSettings()->subHighlightSoundUrl.getValue());
}
else
{
this->highlightSoundUrl_ = getFallbackHighlightSound();
}
}
this->message().flags.set(MessageFlag::Highlighted);
this->message().highlightColor =
ColorProvider::instance().color(ColorType::Subscription);
return;
}
// TODO: This vector should only be rebuilt upon highlights being changed
// fourtf: should be implemented in the HighlightsController
std::vector<HighlightPhrase> activeHighlights =
getSettings()->highlightedMessages.cloneVector();
// This message triggered one or more highlights, act upon the highlight result
if (!currentUser->isAnon() && getSettings()->enableSelfHighlight &&
currentUsername.size() > 0)
this->message().flags.set(MessageFlag::Highlighted);
this->highlightAlert_ = highlightResult.alert;
this->highlightSound_ = highlightResult.playSound;
this->message().highlightColor = highlightResult.color;
if (highlightResult.customSoundUrl)
{
HighlightPhrase selfHighlight(
currentUsername, getSettings()->showSelfHighlightInMentions,
getSettings()->enableSelfHighlightTaskbar,
getSettings()->enableSelfHighlightSound, false, false,
getSettings()->selfHighlightSoundUrl.getValue(),
ColorProvider::instance().color(ColorType::SelfHighlight));
activeHighlights.emplace_back(std::move(selfHighlight));
this->highlightSoundUrl_ = highlightResult.customSoundUrl.get();
}
else
{
this->highlightSoundUrl_ = getFallbackHighlightSound();
}
// Highlight because of message
for (const HighlightPhrase &highlight : activeHighlights)
if (highlightResult.showInMentions)
{
if (!highlight.isMatch(this->originalMessage_))
{
continue;
}
this->message().flags.set(MessageFlag::Highlighted);
if (!(this->message().flags.has(MessageFlag::Subscription) &&
getSettings()->enableSubHighlight))
{
this->message().highlightColor = highlight.getColor();
}
if (highlight.showInMentions())
{
this->message().flags.set(MessageFlag::ShowInMentions);
}
if (highlight.hasAlert())
{
this->highlightAlert_ = true;
}
// Only set highlightSound_ if it hasn't been set by username
// highlights already.
if (highlight.hasSound() && !this->highlightSound_)
{
this->highlightSound_ = true;
// Use custom sound if set, otherwise use fallback sound
if (highlight.hasCustomSound())
{
this->highlightSoundUrl_ = highlight.getSoundUrl();
}
else
{
this->highlightSoundUrl_ = getFallbackHighlightSound();
}
}
if (this->highlightAlert_ && this->highlightSound_)
{
/*
* Break once no further attributes (taskbar, sound) can be
* applied.
*/
break;
}
}
// Highlight because of badge
auto badges = this->parseBadgeTag(this->tags);
auto badgeHighlights = getCSettings().highlightedBadges.readOnly();
bool badgeHighlightSet = false;
for (const HighlightBadge &highlight : *badgeHighlights)
{
for (const Badge &badge : badges)
{
if (!highlight.isMatch(badge))
{
continue;
}
if (!badgeHighlightSet)
{
this->message().flags.set(MessageFlag::Highlighted);
if (!(this->message().flags.has(MessageFlag::Subscription) &&
getSettings()->enableSubHighlight))
{
this->message().highlightColor = highlight.getColor();
}
badgeHighlightSet = true;
}
if (highlight.hasAlert())
{
this->highlightAlert_ = true;
}
// Only set highlightSound_ if it hasn't been set by badge
// highlights already.
if (highlight.hasSound() && !this->highlightSound_)
{
this->highlightSound_ = true;
// Use custom sound if set, otherwise use fallback sound
this->highlightSoundUrl_ = highlight.hasCustomSound()
? highlight.getSoundUrl()
: getFallbackHighlightSound();
}
if (this->highlightAlert_ && this->highlightSound_)
{
/*
* Break once no further attributes (taskbar, sound) can be
* applied.
*/
break;
}
}
this->message().flags.set(MessageFlag::ShowInMentions);
}
}
@@ -264,6 +264,7 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *_message,
MessageParseArgs args;
if (isSub)
{
args.isSubscriptionMessage = true;
args.trimSubscriberUsername = true;
}
+1 -1
View File
@@ -125,7 +125,7 @@ bool TwitchAccount::isAnon() const
void TwitchAccount::loadBlocks()
{
getHelix()->loadBlocks(
getApp()->accounts->twitch.getCurrent()->userId_,
getIApp()->getAccounts()->twitch.getCurrent()->userId_,
[this](std::vector<HelixBlock> blocks) {
auto ignores = this->ignores_.access();
auto userIds = this->ignoresUserIds_.access();
+1 -1
View File
@@ -44,7 +44,7 @@ bool ScrollbarHighlight::isFirstMessageHighlight() const
bool ScrollbarHighlight::isNull() const
{
return this->style_ == None;
return this->style_ == None || !this->color_;
}
} // namespace chatterino