mirror-chatterino2/src/Application.cpp

357 lines
10 KiB
C++
Raw Normal View History

2018-06-26 14:09:39 +02:00
#include "Application.hpp"
2019-09-22 10:53:39 +02:00
#include <atomic>
#include "common/Args.hpp"
2018-06-26 14:09:39 +02:00
#include "controllers/accounts/AccountController.hpp"
#include "controllers/commands/CommandController.hpp"
#include "controllers/highlights/HighlightBlacklistUser.hpp"
#include "controllers/highlights/HighlightPhrase.hpp"
2018-06-26 14:09:39 +02:00
#include "controllers/ignores/IgnoreController.hpp"
#include "controllers/moderationactions/ModerationActions.hpp"
#include "controllers/notifications/NotificationController.hpp"
2020-02-23 20:34:00 +01:00
#include "controllers/pings/MutedChannelController.hpp"
2018-06-26 14:09:39 +02:00
#include "controllers/taggedusers/TaggedUsersController.hpp"
2018-08-07 01:35:24 +02:00
#include "messages/MessageBuilder.hpp"
2018-08-02 14:23:27 +02:00
#include "providers/bttv/BttvEmotes.hpp"
#include "providers/chatterino/ChatterinoBadges.hpp"
2018-08-02 14:23:27 +02:00
#include "providers/ffz/FfzEmotes.hpp"
#include "providers/irc/Irc2.hpp"
2018-07-06 19:23:47 +02:00
#include "providers/twitch/PubsubClient.hpp"
#include "providers/twitch/TwitchIrcServer.hpp"
#include "singletons/Emotes.hpp"
2018-06-28 19:46:45 +02:00
#include "singletons/Fonts.hpp"
#include "singletons/Logging.hpp"
#include "singletons/NativeMessaging.hpp"
#include "singletons/Paths.hpp"
#include "singletons/Resources.hpp"
#include "singletons/Settings.hpp"
2018-06-28 20:03:04 +02:00
#include "singletons/Theme.hpp"
2018-08-11 12:47:03 +02:00
#include "singletons/Toasts.hpp"
2019-09-02 10:52:01 +02:00
#include "singletons/Updates.hpp"
2018-06-26 14:09:39 +02:00
#include "singletons/WindowManager.hpp"
2018-06-27 13:03:38 +02:00
#include "util/IsBigEndian.hpp"
#include "util/PersistSignalVector.hpp"
2018-06-26 14:09:39 +02:00
#include "util/PostToThread.hpp"
2019-09-22 15:32:36 +02:00
#include "widgets/Notebook.hpp"
#include "widgets/Window.hpp"
2019-09-22 15:32:36 +02:00
#include "widgets/splits/Split.hpp"
namespace chatterino {
static std::atomic<bool> isAppInitialized{false};
2018-08-02 14:23:27 +02:00
Application *Application::instance = nullptr;
// this class is responsible for handling the workflow of Chatterino
2018-08-06 21:17:03 +02:00
// It will create the instances of the major classes, and connect their signals
// to each other
2018-08-02 14:23:27 +02:00
Application::Application(Settings &_settings, Paths &_paths)
: highlightedMessages(*new SignalVector<HighlightPhrase>())
, highlightedUsers(*new SignalVector<HighlightPhrase>())
, blacklistedUsers(*new SignalVector<HighlightBlacklistUser>())
, themes(&this->emplace<Theme>())
2018-08-02 14:23:27 +02:00
, fonts(&this->emplace<Fonts>())
, emotes(&this->emplace<Emotes>())
, windows(&this->emplace<WindowManager>())
2018-08-19 15:09:00 +02:00
, toasts(&this->emplace<Toasts>())
2018-08-19 19:02:49 +02:00
2018-08-02 14:23:27 +02:00
, accounts(&this->emplace<AccountController>())
, commands(&this->emplace<CommandController>())
, notifications(&this->emplace<NotificationController>())
2020-02-23 20:34:00 +01:00
, pings(&this->emplace<MutedChannelController>())
2018-08-02 14:23:27 +02:00
, ignores(&this->emplace<IgnoreController>())
, taggedUsers(&this->emplace<TaggedUsersController>())
, moderationActions(&this->emplace<ModerationActions>())
, twitch2(&this->emplace<TwitchIrcServer>())
, chatterinoBadges(&this->emplace<ChatterinoBadges>())
2018-08-02 14:23:27 +02:00
, logging(&this->emplace<Logging>())
{
2018-08-02 14:23:27 +02:00
this->instance = this;
persist(this->highlightedMessages, "/highlighting/highlights");
persist(this->blacklistedUsers, "/highlighting/blacklist");
persist(this->highlightedUsers, "/highlighting/users");
2018-08-06 21:17:03 +02:00
this->fonts->fontChanged.connect(
[this]() { this->windows->layoutChannelViews(); });
2018-04-09 22:59:19 +02:00
2018-07-07 11:41:01 +02:00
this->twitch.server = this->twitch2;
this->twitch.pubsub = this->twitch2->pubsub;
}
2018-08-02 14:23:27 +02:00
void Application::initialize(Settings &settings, Paths &paths)
{
assert(isAppInitialized == false);
isAppInitialized = true;
if (getSettings()->enableExperimentalIrc)
{
Irc::instance().load();
}
2019-09-14 20:45:01 +02:00
2018-10-21 13:43:02 +02:00
for (auto &singleton : this->singletons_)
{
2018-08-02 14:23:27 +02:00
singleton->initialize(settings, paths);
2018-07-07 11:41:01 +02:00
}
2019-09-22 15:32:36 +02:00
// add crash message
if (getArgs().crashRecovery)
{
if (auto selected =
this->windows->getMainWindow().getNotebook().getSelectedPage())
{
if (auto container = dynamic_cast<SplitContainer *>(selected))
{
for (auto &&split : container->getSplits())
{
if (auto channel = split->getChannel(); !channel->isEmpty())
{
channel->addMessage(makeSystemMessage(
"Chatterino unexpectedly crashed and restarted. "
"You can disable automatic restarts in the "
"settings."));
}
}
}
}
}
this->windows->updateWordTypeMask();
2018-09-17 12:51:16 +02:00
this->initNm(paths);
2018-08-02 14:23:27 +02:00
this->initPubsub();
this->moderationActions->items.delayedItemsChanged.connect(
[this] { this->windows->forceLayoutChannelViews(); });
2018-08-02 14:23:27 +02:00
}
int Application::run(QApplication &qtApp)
{
assert(isAppInitialized);
this->twitch.server->connect();
this->windows->getMainWindow().show();
getSettings()->betaUpdates.connect(
[] { Updates::instance().checkForUpdates(); }, false);
2019-09-02 10:52:01 +02:00
2018-08-02 14:23:27 +02:00
return qtApp.exec();
}
void Application::save()
{
2018-10-21 13:43:02 +02:00
for (auto &singleton : this->singletons_)
{
2018-08-02 14:23:27 +02:00
singleton->save();
}
}
2018-09-17 12:51:16 +02:00
void Application::initNm(Paths &paths)
2018-08-02 14:23:27 +02:00
{
2019-09-08 18:06:43 +02:00
(void)paths;
#ifdef Q_OS_WIN
2019-08-19 23:13:20 +02:00
# if defined QT_NO_DEBUG || defined C_DEBUG_NM
2018-09-17 12:51:16 +02:00
registerNmHost(paths);
this->nmServer.start();
2018-08-15 22:46:20 +02:00
# endif
#endif
2018-08-02 14:23:27 +02:00
}
2018-08-02 14:23:27 +02:00
void Application::initPubsub()
{
2018-06-26 17:42:35 +02:00
this->twitch.pubsub->signals_.whisper.sent.connect([](const auto &msg) {
qDebug() << "WHISPER SENT LOL"; //
});
2018-06-26 17:42:35 +02:00
this->twitch.pubsub->signals_.whisper.received.connect([](const auto &msg) {
qDebug() << "WHISPER RECEIVED LOL"; //
});
2018-08-06 21:17:03 +02:00
this->twitch.pubsub->signals_.moderation.chatCleared.connect(
[this](const auto &action) {
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
2018-10-21 13:43:02 +02:00
if (chan->isEmpty())
{
2018-08-06 21:17:03 +02:00
return;
}
2018-04-29 13:24:37 +02:00
2018-08-06 21:17:03 +02:00
QString text =
QString("%1 cleared the chat").arg(action.source.name);
2018-04-29 13:24:37 +02:00
2018-08-07 01:35:24 +02:00
auto msg = makeSystemMessage(text);
2018-08-06 21:17:03 +02:00
postToThread([chan, msg] { chan->addMessage(msg); });
});
2018-08-06 21:17:03 +02:00
this->twitch.pubsub->signals_.moderation.modeChanged.connect(
[this](const auto &action) {
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
2018-10-21 13:43:02 +02:00
if (chan->isEmpty())
{
2018-08-06 21:17:03 +02:00
return;
}
2018-04-29 13:24:37 +02:00
2018-08-06 21:17:03 +02:00
QString text =
QString("%1 turned %2 %3 mode") //
.arg(action.source.name)
.arg(action.state == ModeChangedAction::State::On ? "on"
: "off")
.arg(action.getModeName());
2018-04-29 13:24:37 +02:00
2018-10-21 13:43:02 +02:00
if (action.duration > 0)
{
2018-08-06 21:17:03 +02:00
text.append(" (" + QString::number(action.duration) +
" seconds)");
}
2018-04-29 13:24:37 +02:00
2018-08-07 01:35:24 +02:00
auto msg = makeSystemMessage(text);
2018-08-06 21:17:03 +02:00
postToThread([chan, msg] { chan->addMessage(msg); });
});
2018-06-26 17:42:35 +02:00
this->twitch.pubsub->signals_.moderation.moderationStateChanged.connect(
[this](const auto &action) {
2018-08-06 21:17:03 +02:00
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
2018-10-21 13:43:02 +02:00
if (chan->isEmpty())
{
2018-06-26 17:42:35 +02:00
return;
}
2018-04-29 13:24:37 +02:00
2018-06-26 17:42:35 +02:00
QString text;
2018-04-29 13:24:37 +02:00
2018-10-21 13:43:02 +02:00
if (action.modded)
{
2018-08-06 21:17:03 +02:00
text = QString("%1 modded %2")
.arg(action.source.name, action.target.name);
2018-10-21 13:43:02 +02:00
}
else
{
2018-08-06 21:17:03 +02:00
text = QString("%1 unmodded %2")
.arg(action.source.name, action.target.name);
2018-06-26 17:42:35 +02:00
}
2018-04-29 13:24:37 +02:00
2018-08-07 01:35:24 +02:00
auto msg = makeSystemMessage(text);
2018-06-26 17:42:35 +02:00
postToThread([chan, msg] { chan->addMessage(msg); });
});
2018-08-06 21:17:03 +02:00
this->twitch.pubsub->signals_.moderation.userBanned.connect(
[&](const auto &action) {
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
2018-10-21 13:43:02 +02:00
if (chan->isEmpty())
{
2018-08-06 21:17:03 +02:00
return;
}
2018-08-07 01:35:24 +02:00
MessageBuilder msg(action);
2018-08-07 07:55:31 +02:00
msg->flags.set(MessageFlag::PubSub);
2018-08-07 01:35:24 +02:00
postToThread([chan, msg = msg.release()] {
chan->addOrReplaceTimeout(msg);
});
2018-08-06 21:17:03 +02:00
});
2018-08-06 21:17:03 +02:00
this->twitch.pubsub->signals_.moderation.userUnbanned.connect(
[&](const auto &action) {
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
2018-10-21 13:43:02 +02:00
if (chan->isEmpty())
{
2018-08-06 21:17:03 +02:00
return;
}
2018-08-07 01:35:24 +02:00
auto msg = MessageBuilder(action).release();
2018-08-06 21:17:03 +02:00
postToThread([chan, msg] { chan->addMessage(msg); });
});
this->twitch.pubsub->signals_.moderation.automodMessage.connect(
[&](const auto &action) {
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
if (chan->isEmpty())
{
return;
}
postToThread([chan, action] {
auto p = makeAutomodMessage(action);
chan->addMessage(p.first);
chan->addMessage(p.second);
});
});
this->twitch.pubsub->signals_.moderation.automodUserMessage.connect(
[&](const auto &action) {
auto chan =
this->twitch.server->getChannelOrEmptyByID(action.roomID);
if (chan->isEmpty())
{
return;
}
auto msg = MessageBuilder(action).release();
postToThread([chan, msg] { chan->addMessage(msg); });
chan->deleteMessage(msg->id);
});
this->twitch.pubsub->start();
auto RequestModerationActions = [=]() {
2018-07-07 11:41:01 +02:00
this->twitch.server->pubsub->unlistenAllModerationActions();
2018-08-06 21:17:03 +02:00
// TODO(pajlada): Unlisten to all authed topics instead of only
// moderation topics this->twitch.pubsub->UnlistenAllAuthedTopics();
2018-08-06 21:17:03 +02:00
this->twitch.server->pubsub->listenToWhispers(
this->accounts->twitch.getCurrent()); //
};
2018-05-26 20:26:25 +02:00
this->accounts->twitch.currentUserChanged.connect(RequestModerationActions);
RequestModerationActions();
}
Application *getApp()
{
2018-08-02 14:23:27 +02:00
assert(Application::instance != nullptr);
2018-08-02 14:23:27 +02:00
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