diff --git a/src/Application.cpp b/src/Application.cpp index 4e0ae212..62f8f392 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -5,8 +5,6 @@ #include "common/Args.hpp" #include "controllers/accounts/AccountController.hpp" #include "controllers/commands/CommandController.hpp" -#include "controllers/highlights/HighlightBlacklistUser.hpp" -#include "controllers/highlights/HighlightPhrase.hpp" #include "controllers/ignores/IgnoreController.hpp" #include "controllers/moderationactions/ModerationActions.hpp" #include "controllers/notifications/NotificationController.hpp" @@ -31,7 +29,6 @@ #include "singletons/Updates.hpp" #include "singletons/WindowManager.hpp" #include "util/IsBigEndian.hpp" -#include "util/PersistSignalVector.hpp" #include "util/PostToThread.hpp" #include "widgets/Notebook.hpp" #include "widgets/Window.hpp" @@ -48,11 +45,7 @@ Application *Application::instance = nullptr; // to each other Application::Application(Settings &_settings, Paths &_paths) - : highlightedMessages(*new SignalVector()) - , highlightedUsers(*new SignalVector()) - , blacklistedUsers(*new SignalVector()) - - , themes(&this->emplace()) + : themes(&this->emplace()) , fonts(&this->emplace()) , emotes(&this->emplace()) , windows(&this->emplace()) @@ -62,7 +55,6 @@ Application::Application(Settings &_settings, Paths &_paths) , commands(&this->emplace()) , notifications(&this->emplace()) , pings(&this->emplace()) - , ignores(&this->emplace()) , taggedUsers(&this->emplace()) , moderationActions(&this->emplace()) , twitch2(&this->emplace()) @@ -71,10 +63,6 @@ Application::Application(Settings &_settings, Paths &_paths) { this->instance = this; - persist(this->highlightedMessages, "/highlighting/highlights"); - persist(this->blacklistedUsers, "/highlighting/blacklist"); - persist(this->highlightedUsers, "/highlighting/users"); - this->fonts->fontChanged.connect( [this]() { this->windows->layoutChannelViews(); }); @@ -329,28 +317,4 @@ Application *getApp() return Application::instance; } -bool Application::isHighlightedUser(const QString &username) -{ - for (const auto &highlightedUser : this->highlightedUsers) - { - if (highlightedUser.isMatch(username)) - return true; - } - - return false; -} - -bool Application::isBlacklistedUser(const QString &username) -{ - auto items = this->blacklistedUsers.readOnly(); - - for (const auto &blacklistedUser : *items) - { - if (blacklistedUser.isMatch(username)) - return true; - } - - return false; -} - } // namespace chatterino diff --git a/src/Application.hpp b/src/Application.hpp index 966e21ef..fa04a34d 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -32,9 +32,6 @@ class Fonts; class Toasts; class ChatterinoBadges; -class HighlightPhrase; -class HighlightBlacklistUser; - class Application { std::vector> singletons_; @@ -54,15 +51,6 @@ public: friend void test(); - // clang-format off - SignalVector &highlightedMessages; - SignalVector &highlightedUsers; - SignalVector &blacklistedUsers; - // clang-format on - - bool isHighlightedUser(const QString &username); - bool isBlacklistedUser(const QString &username); - Theme *const themes{}; Fonts *const fonts{}; Emotes *const emotes{}; @@ -73,7 +61,6 @@ public: CommandController *const commands{}; NotificationController *const notifications{}; MutedChannelController *const pings{}; - IgnoreController *const ignores{}; TaggedUsersController *const taggedUsers{}; ModerationActions *const moderationActions{}; TwitchIrcServer *const twitch2{}; diff --git a/src/controllers/ignores/IgnoreController.cpp b/src/controllers/ignores/IgnoreController.cpp index 3ce1d562..0415032e 100644 --- a/src/controllers/ignores/IgnoreController.cpp +++ b/src/controllers/ignores/IgnoreController.cpp @@ -12,8 +12,6 @@ void IgnoreController::initialize(Settings &, Paths &) { assert(!this->initialized_); this->initialized_ = true; - - persist(this->phrases, "/ignore/phrases"); } } // namespace chatterino diff --git a/src/controllers/ignores/IgnoreController.hpp b/src/controllers/ignores/IgnoreController.hpp index 979647a0..c0b11e82 100644 --- a/src/controllers/ignores/IgnoreController.hpp +++ b/src/controllers/ignores/IgnoreController.hpp @@ -19,8 +19,6 @@ class IgnoreController final : public Singleton public: virtual void initialize(Settings &settings, Paths &paths) override; - SignalVector phrases; - private: bool initialized_ = false; }; diff --git a/src/providers/colors/ColorProvider.cpp b/src/providers/colors/ColorProvider.cpp index ce61a69f..e1be8d6f 100644 --- a/src/providers/colors/ColorProvider.cpp +++ b/src/providers/colors/ColorProvider.cpp @@ -37,12 +37,12 @@ QSet ColorProvider::recentColors() const * Currently, only colors used in highlight phrases are considered. This * may change at any point in the future. */ - for (auto phrase : getApp()->highlightedMessages) + for (auto phrase : getSettings()->highlightedMessages) { retVal.insert(*phrase.getColor()); } - for (auto userHl : getApp()->highlightedUsers) + for (auto userHl : getSettings()->highlightedUsers) { retVal.insert(*userHl.getColor()); } diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 8902512d..730bf3ca 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -169,7 +169,7 @@ bool TwitchMessageBuilder::isIgnored() const auto app = getApp(); // TODO(pajlada): Do we need to check if the phrase is valid first? - auto phrases = app->ignores->phrases.readOnly(); + auto phrases = getCSettings().ignoredMessages.readOnly(); for (const auto &phrase : *phrases) { if (phrase.isBlock() && phrase.isMatch(this->originalMessage_)) @@ -764,8 +764,7 @@ void TwitchMessageBuilder::appendUsername() void TwitchMessageBuilder::runIgnoreReplaces( std::vector> &twitchEmotes) { - auto app = getApp(); - auto phrases = app->ignores->phrases.readOnly(); + auto phrases = getCSettings().ignoredMessages.readOnly(); auto removeEmotesInRange = [](int pos, int len, std::vector> @@ -1017,7 +1016,7 @@ void TwitchMessageBuilder::parseHighlights() QString currentUsername = currentUser->getUserName(); - if (app->isBlacklistedUser(this->ircMessage->nick())) + if (getCSettings().isBlacklistedUser(this->ircMessage->nick())) { // Do nothing. We ignore highlights from this user. return; @@ -1057,7 +1056,7 @@ void TwitchMessageBuilder::parseHighlights() } // Highlight because of sender - auto userHighlights = app->highlightedUsers.readOnly(); + auto userHighlights = getCSettings().highlightedUsers.readOnly(); for (const HighlightPhrase &userHighlight : *userHighlights) { if (!userHighlight.isMatch(this->ircMessage->nick())) @@ -1109,7 +1108,7 @@ void TwitchMessageBuilder::parseHighlights() // TODO: This vector should only be rebuilt upon highlights being changed // fourtf: should be implemented in the HighlightsController std::vector activeHighlights = - app->highlightedMessages.cloneVector(); + getSettings()->highlightedMessages.cloneVector(); if (getSettings()->enableSelfHighlight && currentUsername.size() > 0) { diff --git a/src/singletons/Settings.cpp b/src/singletons/Settings.cpp index 30ba15ec..0e42db01 100644 --- a/src/singletons/Settings.cpp +++ b/src/singletons/Settings.cpp @@ -1,19 +1,71 @@ #include "singletons/Settings.hpp" #include "Application.hpp" +#include "controllers/highlights/HighlightBlacklistUser.hpp" +#include "controllers/highlights/HighlightPhrase.hpp" +#include "controllers/ignores/IgnorePhrase.hpp" #include "singletons/Paths.hpp" #include "singletons/Resources.hpp" #include "singletons/WindowManager.hpp" +#include "util/PersistSignalVector.hpp" #include "util/WindowsHelper.hpp" namespace chatterino { +ConcurrentSettings *concurrentInstance_{}; + +ConcurrentSettings::ConcurrentSettings() + : highlightedMessages(*new SignalVector()) + , highlightedUsers(*new SignalVector()) + , blacklistedUsers(*new SignalVector()) + , ignoredMessages(*new SignalVector()) +{ +} + +bool ConcurrentSettings::isHighlightedUser(const QString &username) +{ + for (const auto &highlightedUser : this->highlightedUsers) + { + if (highlightedUser.isMatch(username)) + return true; + } + + return false; +} + +bool ConcurrentSettings::isBlacklistedUser(const QString &username) +{ + auto items = this->blacklistedUsers.readOnly(); + + for (const auto &blacklistedUser : *items) + { + if (blacklistedUser.isMatch(username)) + return true; + } + + return false; +} + +ConcurrentSettings &getCSettings() +{ + // `concurrentInstance_` gets assigned in Settings ctor. + assert(concurrentInstance_); + + return *concurrentInstance_; +} + Settings *Settings::instance_ = nullptr; Settings::Settings(const QString &settingsDirectory) : ABSettings(settingsDirectory) { instance_ = this; + concurrentInstance_ = this; + + persist(this->highlightedMessages, "/highlighting/highlights"); + persist(this->blacklistedUsers, "/highlighting/blacklist"); + persist(this->highlightedUsers, "/highlighting/users"); + persist(this->ignoredMessages, "/ignore/phrases"); #ifdef USEWINSDK this->autorun = isRegisteredForStartup(); diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index f0d1679d..cc2e4e3c 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -5,13 +5,38 @@ #include "BaseSettings.hpp" #include "common/Channel.hpp" +#include "common/SignalVector.hpp" #include "controllers/highlights/HighlightPhrase.hpp" #include "controllers/moderationactions/ModerationAction.hpp" #include "singletons/Toasts.hpp" namespace chatterino { -class Settings : public ABSettings +class HighlightPhrase; +class HighlightBlacklistUser; +class IgnorePhrase; + +// Settings which are availlable for reading on all threads. +class ConcurrentSettings +{ +public: + ConcurrentSettings(); + + // clang-format off + SignalVector &highlightedMessages; + SignalVector &highlightedUsers; + SignalVector &blacklistedUsers; + SignalVector &ignoredMessages; + // clang-format on + + bool isHighlightedUser(const QString &username); + bool isBlacklistedUser(const QString &username); +}; + +ConcurrentSettings &getCSettings(); + +// These settings are still accessed concurrently in the code but it is bad practice. +class Settings : public ABSettings, public ConcurrentSettings { static Settings *instance_; diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index d6041448..3b830702 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -8,6 +8,7 @@ #include "providers/twitch/PartialTwitchUser.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "singletons/Resources.hpp" +#include "singletons/Settings.hpp" #include "util/LayoutCreator.hpp" #include "util/PostToThread.hpp" #include "widgets/Label.hpp" @@ -336,23 +337,23 @@ void UserInfoPopup::installEvents() if (checked) { - getApp()->blacklistedUsers.insert( + getSettings()->blacklistedUsers.insert( HighlightBlacklistUser{this->userName_, false}); this->ui_.ignoreHighlights->setEnabled(true); } else { - const auto &vector = getApp()->blacklistedUsers.raw(); + const auto &vector = getSettings()->blacklistedUsers.raw(); for (int i = 0; i < vector.size(); i++) { if (this->userName_ == vector[i].getPattern()) { - getApp()->blacklistedUsers.removeAt(i); + getSettings()->blacklistedUsers.removeAt(i); i--; } } - if (getApp()->isBlacklistedUser(this->userName_)) + if (getSettings()->isBlacklistedUser(this->userName_)) { this->ui_.ignoreHighlights->setToolTip( "Name matched by regex"); @@ -455,7 +456,7 @@ void UserInfoPopup::updateUserData() // get ignoreHighlights state bool isIgnoringHighlights = false; - const auto &vector = getApp()->blacklistedUsers.raw(); + const auto &vector = getSettings()->blacklistedUsers.raw(); for (int i = 0; i < vector.size(); i++) { if (this->userName_ == vector[i].getPattern()) @@ -464,7 +465,7 @@ void UserInfoPopup::updateUserData() break; } } - if (getApp()->isBlacklistedUser(this->userName_) && + if (getSettings()->isBlacklistedUser(this->userName_) && !isIgnoringHighlights) { this->ui_.ignoreHighlights->setToolTip("Name matched by regex"); diff --git a/src/widgets/settingspages/HighlightingPage.cpp b/src/widgets/settingspages/HighlightingPage.cpp index 5013bc30..2ba16f62 100644 --- a/src/widgets/settingspages/HighlightingPage.cpp +++ b/src/widgets/settingspages/HighlightingPage.cpp @@ -52,7 +52,8 @@ HighlightingPage::HighlightingPage() highlights .emplace( (new HighlightModel(nullptr)) - ->initialized(&app->highlightedMessages)) + ->initialized( + &getSettings()->highlightedMessages)) .getElement(); view->addRegexHelpLink(); view->setTitles({"Pattern", "Flash\ntaskbar", "Play\nsound", @@ -71,7 +72,7 @@ HighlightingPage::HighlightingPage() }); view->addButtonPressed.connect([] { - getApp()->highlightedMessages.append(HighlightPhrase{ + getSettings()->highlightedMessages.append(HighlightPhrase{ "my phrase", true, false, false, false, "", *ColorProvider::instance().color( ColorType::SelfHighlight)}); @@ -94,7 +95,7 @@ HighlightingPage::HighlightingPage() pingUsers .emplace( (new UserHighlightModel(nullptr)) - ->initialized(&app->highlightedUsers)) + ->initialized(&getSettings()->highlightedUsers)) .getElement(); view->addRegexHelpLink(); @@ -118,7 +119,7 @@ HighlightingPage::HighlightingPage() }); view->addButtonPressed.connect([] { - getApp()->highlightedUsers.append(HighlightPhrase{ + getSettings()->highlightedUsers.append(HighlightPhrase{ "highlighted user", true, false, false, false, "", *ColorProvider::instance().color( ColorType::SelfHighlight)}); @@ -140,7 +141,7 @@ HighlightingPage::HighlightingPage() disabledUsers .emplace( (new HighlightBlacklistModel(nullptr)) - ->initialized(&app->blacklistedUsers)) + ->initialized(&getSettings()->blacklistedUsers)) .getElement(); view->addRegexHelpLink(); @@ -158,7 +159,7 @@ HighlightingPage::HighlightingPage() }); view->addButtonPressed.connect([] { - getApp()->blacklistedUsers.append( + getSettings()->blacklistedUsers.append( HighlightBlacklistUser{"blacklisted user", false}); }); } diff --git a/src/widgets/settingspages/IgnoresPage.cpp b/src/widgets/settingspages/IgnoresPage.cpp index c16b1858..0e3fe2ad 100644 --- a/src/widgets/settingspages/IgnoresPage.cpp +++ b/src/widgets/settingspages/IgnoresPage.cpp @@ -46,7 +46,7 @@ void addPhrasesTab(LayoutCreator layout) layout .emplace( (new IgnoreModel(nullptr)) - ->initialized(&getApp()->ignores->phrases)) + ->initialized(&getSettings()->ignoredMessages)) .getElement(); view->setTitles( {"Pattern", "Regex", "Case Sensitive", "Block", "Replacement"}); @@ -62,7 +62,7 @@ void addPhrasesTab(LayoutCreator layout) }); view->addButtonPressed.connect([] { - getApp()->ignores->phrases.append( + getSettings()->ignoredMessages.append( IgnorePhrase{"my pattern", false, false, getSettings()->ignoredPhraseReplace.getValue(), true}); });