diff --git a/chatterino.pro b/chatterino.pro index 2c041f127..ff4a6dad1 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -47,6 +47,7 @@ win32 { SOURCES += \ src/main.cpp \ + src/application.cpp \ src/channel.cpp \ src/colorscheme.cpp \ src/emojis.cpp \ diff --git a/src/application.cpp b/src/application.cpp new file mode 100644 index 000000000..575f9bdd9 --- /dev/null +++ b/src/application.cpp @@ -0,0 +1,42 @@ +#include "application.hpp" +#include "colorscheme.hpp" +#include "settingsmanager.hpp" + +namespace chatterino { + +Application::Application() + : windowManager(this->channelManager) + , emoteManager(this->windowManager, this->resources) + , resources(this->emoteManager, this->windowManager) + , channelManager(this->windowManager, this->emoteManager, this->ircManager) + , ircManager(this->channelManager, this->resources, this->emoteManager, this->windowManager) +{ + // TODO(pajlada): Get rid of all singletons + ColorScheme::getInstance().init(this->windowManager); + + // Initialize everything we need + this->emoteManager.loadGlobalEmotes(); + + // XXX + SettingsManager::getInstance().updateWordTypeMask(); + + this->windowManager.load(); +} + +Application::~Application() +{ + this->windowManager.save(); +} + +int Application::run(QApplication &qtApp) +{ + // Start connecting to the IRC Servers (Twitch only for now) + this->ircManager.connect(); + + // Show main window + this->windowManager.getMainWindow().show(); + + return qtApp.exec(); +} + +} // namespace chatterino diff --git a/src/application.hpp b/src/application.hpp new file mode 100644 index 000000000..93e929600 --- /dev/null +++ b/src/application.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "channelmanager.hpp" +#include "emotemanager.hpp" +#include "ircmanager.hpp" +#include "resources.hpp" +#include "windowmanager.hpp" + +#include + +namespace chatterino { + +class Application +{ +public: + Application(); + ~Application(); + + int run(QApplication &qtApp); + + WindowManager windowManager; + EmoteManager emoteManager; + Resources resources; + ChannelManager channelManager; + IrcManager ircManager; +}; + +} // namespace chatterino diff --git a/src/channel.cpp b/src/channel.cpp index 3e81974eb..4bf0e2afe 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -3,7 +3,6 @@ #include "ircmanager.hpp" #include "logging/loggingmanager.hpp" #include "messages/message.hpp" -#include "util/urlfetch.hpp" #include "windowmanager.hpp" #include @@ -21,8 +20,12 @@ using namespace chatterino::messages; namespace chatterino { -Channel::Channel(const QString &channel) - : _messages() +Channel::Channel(WindowManager &_windowManager, EmoteManager &_emoteManager, + IrcManager &_ircManager, const QString &channel, bool isSpecial) + : windowManager(_windowManager) + , emoteManager(_emoteManager) + , ircManager(_ircManager) + , _messages() , _name((channel.length() > 0 && channel[0] == '#') ? channel.mid(1) : channel) , _bttvChannelEmotes() , _ffzChannelEmotes() @@ -33,7 +36,9 @@ Channel::Channel(const QString &channel) { qDebug() << "Open channel:" << channel << ". Name: " << _name; printf("Channel pointer: %p\n", this); - reloadChannelEmotes(); + if (!isSpecial) { + this->reloadChannelEmotes(); + } } // @@ -121,82 +126,21 @@ void Channel::addMessage(std::shared_ptr message) this->messageAppended(message); - WindowManager::getInstance().repaintVisibleChatWidgets(this); + this->windowManager.repaintVisibleChatWidgets(this); } // private methods void Channel::reloadChannelEmotes() { - reloadBttvEmotes(); - reloadFfzEmotes(); + printf("[Channel:%s] Reloading channel emotes\n", qPrintable(this->_name)); + this->emoteManager.reloadBTTVChannelEmotes(this->_name, this->_bttvChannelEmotes); + this->emoteManager.reloadFFZChannelEmotes(this->_name, this->_ffzChannelEmotes); } void Channel::sendMessage(const QString &message) { qDebug() << "Channel send message: " << message; - IrcManager &instance = IrcManager::getInstance(); - instance.sendMessage(_name, message); -} - -void Channel::reloadBttvEmotes() -{ - util::urlJsonFetch( - "https://api.betterttv.net/2/channels/" + _name, [this](QJsonObject &rootNode) { - auto emotesNode = rootNode.value("emotes").toArray(); - - QString linkTemplate = "https:" + rootNode.value("urlTemplate").toString(); - - for (const QJsonValue &emoteNode : emotesNode) { - QJsonObject emoteObject = emoteNode.toObject(); - - QString id = emoteObject.value("id").toString(); - QString code = emoteObject.value("code").toString(); - // emoteObject.value("imageType").toString(); - - QString link = linkTemplate; - link.detach(); - - link = link.replace("{{id}}", id).replace("{{image}}", "1x"); - - auto emote = EmoteManager::getInstance().getBttvChannelEmoteFromCaches().getOrAdd( - id, [&code, &link] { - return new LazyLoadedImage(link, 1, code, code + "\nChannel Bttv Emote"); - }); - - this->getBttvChannelEmotes().insert(code, emote); - } - }); -} - -void Channel::reloadFfzEmotes() -{ - util::urlJsonFetch("http://api.frankerfacez.com/v1/room/" + _name, [this]( - QJsonObject &rootNode) { - auto setsNode = rootNode.value("sets").toObject(); - - for (const QJsonValue &setNode : setsNode) { - auto emotesNode = setNode.toObject().value("emoticons").toArray(); - - for (const QJsonValue &emoteNode : emotesNode) { - QJsonObject emoteObject = emoteNode.toObject(); - - // margins - - int id = emoteObject.value("id").toInt(); - QString code = emoteObject.value("name").toString(); - - QJsonObject urls = emoteObject.value("urls").toObject(); - QString url1 = "http:" + urls.value("1").toString(); - - auto emote = EmoteManager::getInstance().getFfzChannelEmoteFromCaches().getOrAdd( - id, [&code, &url1] { - return new LazyLoadedImage(url1, 1, code, code + "\nGlobal Ffz Emote"); - }); - - getFfzChannelEmotes().insert(code, emote); - } - } - }); + this->ircManager.sendMessage(_name, message); } } // namespace chatterino diff --git a/src/channel.hpp b/src/channel.hpp index d07aaef2e..3f1f28b4d 100644 --- a/src/channel.hpp +++ b/src/channel.hpp @@ -18,12 +18,15 @@ namespace messages { class Message; } -class ChannelManager; +class WindowManager; +class EmoteManager; +class IrcManager; class Channel { public: - Channel(const QString &channel); + explicit Channel(WindowManager &_windowManager, EmoteManager &_emoteManager, + IrcManager &_ircManager, const QString &channel, bool isSpecial = false); boost::signals2::signal messageRemovedFromStart; boost::signals2::signal messageAppended; @@ -51,6 +54,10 @@ public: void sendMessage(const QString &message); private: + WindowManager &windowManager; + EmoteManager &emoteManager; + IrcManager &ircManager; + // variabeles messages::LimitedQueue _messages; @@ -69,10 +76,6 @@ private: QString _streamStatus; QString _streamGame; // std::shared_ptr _loggingChannel; - - // methods - void reloadBttvEmotes(); - void reloadFfzEmotes(); }; } // namespace chatterino diff --git a/src/channelmanager.cpp b/src/channelmanager.cpp index 35c0d08db..5dfe42de3 100644 --- a/src/channelmanager.cpp +++ b/src/channelmanager.cpp @@ -3,14 +3,14 @@ namespace chatterino { -ChannelManager ChannelManager::instance; - -ChannelManager::ChannelManager() - : _channels() - , _channelsMutex() - , _whispers(new Channel(QString("/whispers"))) - , _mentions(new Channel(QString("/mentions"))) - , _empty(new Channel(QString(""))) +ChannelManager::ChannelManager(WindowManager &_windowManager, EmoteManager &_emoteManager, + IrcManager &_ircManager) + : windowManager(_windowManager) + , emoteManager(_emoteManager) + , ircManager(_ircManager) + , _whispers(new Channel(_windowManager, _emoteManager, _ircManager, "/whispers", true)) + , _mentions(new Channel(_windowManager, _emoteManager, _ircManager, "/mentions", true)) + , _empty(new Channel(_windowManager, _emoteManager, _ircManager, QString(), true)) { } @@ -55,10 +55,11 @@ std::shared_ptr ChannelManager::addChannel(const QString &channel) auto it = _channels.find(channelName); if (it == _channels.end()) { - auto channel = std::shared_ptr(new Channel(channelName)); + auto channel = std::shared_ptr( + new Channel(this->windowManager, this->emoteManager, this->ircManager, channelName)); _channels.insert(channelName, std::make_tuple(channel, 1)); - IrcManager::getInstance().joinChannel(channelName); + this->ircManager.joinChannel(channelName); return channel; } @@ -114,7 +115,7 @@ void ChannelManager::removeChannel(const QString &channel) std::get<1>(a.value())--; if (std::get<1>(a.value()) == 0) { - IrcManager::getInstance().partChannel(c); + this->ircManager.partChannel(c); _channels.remove(c); } } diff --git a/src/channelmanager.hpp b/src/channelmanager.hpp index 289a2b987..2b0e261bf 100644 --- a/src/channelmanager.hpp +++ b/src/channelmanager.hpp @@ -4,13 +4,15 @@ namespace chatterino { +class WindowManager; +class EmoteManager; +class IrcManager; + class ChannelManager { public: - static ChannelManager &getInstance() - { - return instance; - } + explicit ChannelManager(WindowManager &_windowManager, EmoteManager &_emoteManager, + IrcManager &_ircManager); std::shared_ptr getWhispers(); std::shared_ptr getMentions(); @@ -23,9 +25,9 @@ public: void removeChannel(const QString &channel); private: - static ChannelManager instance; - - ChannelManager(); + WindowManager &windowManager; + EmoteManager &emoteManager; + IrcManager &ircManager; QMap, int>> _channels; QMutex _channelsMutex; diff --git a/src/colorscheme.cpp b/src/colorscheme.cpp index 4bb4c13d5..2ae4f5059 100644 --- a/src/colorscheme.cpp +++ b/src/colorscheme.cpp @@ -8,20 +8,25 @@ namespace chatterino { -void ColorScheme::init() +void ColorScheme::init(WindowManager &windowManager) { static bool initiated = false; if (!initiated) { initiated = true; ColorScheme::getInstance().update(); - SettingsManager::getInstance().theme.valueChanged.connect( - [](const QString &) { ColorScheme::getInstance().update(); }); - SettingsManager::getInstance().themeHue.valueChanged.connect( - [](const float &) { ColorScheme::getInstance().update(); }); - ColorScheme::getInstance().updated.connect( - [] { WindowManager::getInstance().repaintVisibleChatWidgets(); }); + SettingsManager::getInstance().theme.valueChanged.connect([](const QString &) { + ColorScheme::getInstance().update(); // + }); + + SettingsManager::getInstance().themeHue.valueChanged.connect([](const float &) { + ColorScheme::getInstance().update(); // + }); + + ColorScheme::getInstance().updated.connect([&windowManager] { + windowManager.repaintVisibleChatWidgets(); // + }); } } diff --git a/src/colorscheme.hpp b/src/colorscheme.hpp index 7b95d437a..91d7d3c07 100644 --- a/src/colorscheme.hpp +++ b/src/colorscheme.hpp @@ -6,6 +6,8 @@ namespace chatterino { +class WindowManager; + class ColorScheme { public: @@ -67,7 +69,7 @@ public: return instance; } - void init(); + void init(WindowManager &windowManager); void normalizeColor(QColor &color); void update(); diff --git a/src/emojis.cpp b/src/emojis.cpp index 3aad860ac..0673b7e18 100644 --- a/src/emojis.cpp +++ b/src/emojis.cpp @@ -46,8 +46,14 @@ void Emojis::parseEmojis(std::vector( - imageCache.getOrAdd( - url, [&url] { return new messages::LazyLoadedImage(url, 0.35); }), + imageCache.getOrAdd(url, + [/*&url*/] { + /* TODO: re-implement + return new messages::LazyLoadedImage(url, + 0.35); // + */ + return nullptr; + }), QString())); i += j - 1; diff --git a/src/emotemanager.cpp b/src/emotemanager.cpp index 3672a6cfe..4b8bbc3b9 100644 --- a/src/emotemanager.cpp +++ b/src/emotemanager.cpp @@ -1,5 +1,7 @@ #include "emotemanager.hpp" #include "resources.hpp" +#include "util/urlfetch.hpp" +#include "windowmanager.hpp" #include #include @@ -18,22 +20,92 @@ using namespace chatterino::messages; namespace chatterino { -EmoteManager EmoteManager::instance; - -EmoteManager::EmoteManager() - : _twitchEmotes() - , _bttvEmotes() - , _ffzEmotes() - , _chatterinoEmotes() - , _bttvChannelEmoteFromCaches() - , _ffzChannelEmoteFromCaches() - , _twitchEmoteFromCache() - , _miscImageFromCache() - , _gifUpdateTimerSignal() - , _gifUpdateTimer() - , _gifUpdateTimerInitiated(false) - , _generation(0) +EmoteManager::EmoteManager(WindowManager &_windowManager, Resources &_resources) + : windowManager(_windowManager) + , resources(_resources) { + // Note: Do not use this->resources in ctor +} + +void EmoteManager::loadGlobalEmotes() +{ + this->loadBTTVEmotes(); + this->loadFFZEmotes(); +} + +void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName, + BTTVEmoteMap &channelEmoteMap) +{ + printf("[EmoteManager] Reload BTTV Channel Emotes for channel %s\n", qPrintable(channelName)); + + QString url("https://api.betterttv.net/2/channels/" + channelName); + util::urlJsonFetch(url, [this, &channelEmoteMap](QJsonObject &rootNode) { + channelEmoteMap.clear(); + + auto emotesNode = rootNode.value("emotes").toArray(); + + QString linkTemplate = "https:" + rootNode.value("urlTemplate").toString(); + + for (const QJsonValue &emoteNode : emotesNode) { + QJsonObject emoteObject = emoteNode.toObject(); + + QString id = emoteObject.value("id").toString(); + QString code = emoteObject.value("code").toString(); + // emoteObject.value("imageType").toString(); + + QString link = linkTemplate; + link.detach(); + + link = link.replace("{{id}}", id).replace("{{image}}", "1x"); + + auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [this, &code, &link] { + return new LazyLoadedImage(*this, this->windowManager, link, 1, code, + code + "\nChannel BTTV Emote"); + }); + + this->bttvChannelEmotes.insert(code, emote); + channelEmoteMap.insert(code, emote); + } + }); +} + +void EmoteManager::reloadFFZChannelEmotes( + const QString &channelName, + ConcurrentMap &channelEmoteMap) +{ + printf("[EmoteManager] Reload FFZ Channel Emotes for channel %s\n", qPrintable(channelName)); + + QString url("http://api.frankerfacez.com/v1/room/" + channelName); + + util::urlJsonFetch(url, [this, &channelEmoteMap](QJsonObject &rootNode) { + channelEmoteMap.clear(); + + auto setsNode = rootNode.value("sets").toObject(); + + for (const QJsonValue &setNode : setsNode) { + auto emotesNode = setNode.toObject().value("emoticons").toArray(); + + for (const QJsonValue &emoteNode : emotesNode) { + QJsonObject emoteObject = emoteNode.toObject(); + + // margins + int id = emoteObject.value("id").toInt(); + QString code = emoteObject.value("name").toString(); + + QJsonObject urls = emoteObject.value("urls").toObject(); + QString url1 = "http:" + urls.value("1").toString(); + + auto emote = + this->getFFZChannelEmoteFromCaches().getOrAdd(id, [this, &code, &url1] { + return new LazyLoadedImage(*this, this->windowManager, url1, 1, code, + code + "\nGlobal FFZ Emote"); + }); + + this->ffzChannelEmotes.insert(code, emote); + channelEmoteMap.insert(code, emote); + } + } + }); } ConcurrentMap &EmoteManager::getTwitchEmotes() @@ -41,12 +113,12 @@ ConcurrentMap &EmoteManager::getTwitchEmotes() return _twitchEmotes; } -ConcurrentMap &EmoteManager::getBttvEmotes() +ConcurrentMap &EmoteManager::getBTTVEmotes() { return _bttvEmotes; } -ConcurrentMap &EmoteManager::getFfzEmotes() +ConcurrentMap &EmoteManager::getFFZEmotes() { return _ffzEmotes; } @@ -56,12 +128,12 @@ ConcurrentMap &EmoteManager::getChatterino return _chatterinoEmotes; } -ConcurrentMap &EmoteManager::getBttvChannelEmoteFromCaches() +ConcurrentMap &EmoteManager::getBTTVChannelEmoteFromCaches() { return _bttvChannelEmoteFromCaches; } -ConcurrentMap &EmoteManager::getFfzChannelEmoteFromCaches() +ConcurrentMap &EmoteManager::getFFZChannelEmoteFromCaches() { return _ffzChannelEmoteFromCaches; } @@ -76,13 +148,7 @@ ConcurrentMap &EmoteManager::getMiscImageF return _miscImageFromCache; } -void EmoteManager::loadGlobalEmotes() -{ - loadBttvEmotes(); - loadFfzEmotes(); -} - -void EmoteManager::loadBttvEmotes() +void EmoteManager::loadBTTVEmotes() { // bttv QNetworkAccessManager *manager = new QNetworkAccessManager(); @@ -111,8 +177,9 @@ void EmoteManager::loadBttvEmotes() tmp.detach(); QString url = tmp.replace("{{id}}", id).replace("{{image}}", "1x"); - EmoteManager::getBttvEmotes().insert( - code, new LazyLoadedImage(url, 1, code, code + "\nGlobal Bttv Emote")); + EmoteManager::getBTTVEmotes().insert( + code, new LazyLoadedImage(*this, this->windowManager, url, 1, code, + code + "\nGlobal BTTV Emote")); } } @@ -121,7 +188,7 @@ void EmoteManager::loadBttvEmotes() }); } -void EmoteManager::loadFfzEmotes() +void EmoteManager::loadFFZEmotes() { // ffz QNetworkAccessManager *manager = new QNetworkAccessManager(); @@ -153,8 +220,9 @@ void EmoteManager::loadFfzEmotes() QJsonObject urls = object.value("urls").toObject(); QString url1 = "http:" + urls.value("1").toString(); - EmoteManager::getBttvEmotes().insert( - code, new LazyLoadedImage(url1, 1, code, code + "\nGlobal Ffz Emote")); + EmoteManager::getBTTVEmotes().insert( + code, new LazyLoadedImage(*this, this->windowManager, url1, 1, code, + code + "\nGlobal FFZ Emote")); } } } @@ -166,11 +234,12 @@ void EmoteManager::loadFfzEmotes() LazyLoadedImage *EmoteManager::getTwitchEmoteById(const QString &name, long id) { - return EmoteManager::_twitchEmoteFromCache.getOrAdd(id, [&name, &id] { + return EmoteManager::_twitchEmoteFromCache.getOrAdd(id, [this, &name, &id] { qDebug() << "added twitch emote: " << id; qreal scale; QString url = getTwitchEmoteLink(id, scale); - return new LazyLoadedImage(url, scale, name, name + "\nTwitch Emote"); + return new LazyLoadedImage(*this, this->windowManager, url, scale, name, + name + "\nTwitch Emote"); }); } @@ -188,24 +257,41 @@ QString EmoteManager::getTwitchEmoteLink(long id, qreal &scale) LazyLoadedImage *EmoteManager::getCheerImage(long long amount, bool animated) { // TODO: fix this xD - return getCheerBadge(amount); + return this->getCheerBadge(amount); } LazyLoadedImage *EmoteManager::getCheerBadge(long long amount) { if (amount >= 100000) { - return Resources::getCheerBadge100000(); + return this->resources.cheerBadge100000; } else if (amount >= 10000) { - return Resources::getCheerBadge10000(); + return this->resources.cheerBadge10000; } else if (amount >= 5000) { - return Resources::getCheerBadge5000(); + return this->resources.cheerBadge5000; } else if (amount >= 1000) { - return Resources::getCheerBadge1000(); + return this->resources.cheerBadge1000; } else if (amount >= 100) { - return Resources::getCheerBadge100(); + return this->resources.cheerBadge100; } else { - return Resources::getCheerBadge1(); + return this->resources.cheerBadge1; } } +boost::signals2::signal &EmoteManager::getGifUpdateSignal() +{ + if (!_gifUpdateTimerInitiated) { + _gifUpdateTimerInitiated = true; + + _gifUpdateTimer.setInterval(30); + _gifUpdateTimer.start(); + + QObject::connect(&_gifUpdateTimer, &QTimer::timeout, [this] { + _gifUpdateTimerSignal(); + this->windowManager.repaintGifEmotes(); + }); + } + + return _gifUpdateTimerSignal; +} + } // namespace chatterino diff --git a/src/emotemanager.hpp b/src/emotemanager.hpp index d9da5cc99..cc68a70c7 100644 --- a/src/emotemanager.hpp +++ b/src/emotemanager.hpp @@ -5,7 +5,6 @@ #include "concurrentmap.hpp" #include "messages/lazyloadedimage.hpp" #include "twitch/emotevalue.hpp" -#include "windowmanager.hpp" #include #include @@ -13,25 +12,33 @@ #include namespace chatterino { + +class WindowManager; +class Resources; + class EmoteManager { public: - static EmoteManager &getInstance() - { - return instance; - } + using FFZEmoteMap = ConcurrentMap; + using BTTVEmoteMap = ConcurrentMap; + using ChatterinoEmoteMap = ConcurrentMap; - ConcurrentMap &getTwitchEmotes(); - ConcurrentMap &getBttvEmotes(); - ConcurrentMap &getFfzEmotes(); - ConcurrentMap &getChatterinoEmotes(); - ConcurrentMap &getBttvChannelEmoteFromCaches(); - ConcurrentMap &getFfzChannelEmoteFromCaches(); - ConcurrentMap &getTwitchEmoteFromCache(); - ConcurrentMap &getMiscImageFromCache(); + EmoteManager(WindowManager &_windowManager, Resources &_resources); void loadGlobalEmotes(); + void reloadBTTVChannelEmotes(const QString &channelName, BTTVEmoteMap &channelEmoteMap); + void reloadFFZChannelEmotes(const QString &channelName, FFZEmoteMap &channelEmoteMap); + + ConcurrentMap &getTwitchEmotes(); + ConcurrentMap &getBTTVEmotes(); + ConcurrentMap &getFFZEmotes(); + ConcurrentMap &getChatterinoEmotes(); + ConcurrentMap &getBTTVChannelEmoteFromCaches(); + ConcurrentMap &getFFZChannelEmoteFromCaches(); + ConcurrentMap &getTwitchEmoteFromCache(); + ConcurrentMap &getMiscImageFromCache(); + messages::LazyLoadedImage *getCheerImage(long long int amount, bool animated); messages::LazyLoadedImage *getCheerBadge(long long int amount); @@ -47,29 +54,15 @@ public: _generation++; } - boost::signals2::signal &getGifUpdateSignal() - { - if (!_gifUpdateTimerInitiated) { - _gifUpdateTimerInitiated = true; - - _gifUpdateTimer.setInterval(30); - _gifUpdateTimer.start(); - - QObject::connect(&_gifUpdateTimer, &QTimer::timeout, [this] { - _gifUpdateTimerSignal(); - WindowManager::getInstance().repaintGifEmotes(); - }); - } - - return _gifUpdateTimerSignal; - } + boost::signals2::signal &getGifUpdateSignal(); private: - static EmoteManager instance; + WindowManager &windowManager; + Resources &resources; - EmoteManager(); + ConcurrentMap bttvChannelEmotes; + ConcurrentMap ffzChannelEmotes; - // variables ConcurrentMap _twitchEmotes; ConcurrentMap _bttvEmotes; ConcurrentMap _ffzEmotes; @@ -81,15 +74,15 @@ private: boost::signals2::signal _gifUpdateTimerSignal; QTimer _gifUpdateTimer; - bool _gifUpdateTimerInitiated; + bool _gifUpdateTimerInitiated = false; - int _generation; + int _generation = 0; // methods static QString getTwitchEmoteLink(long id, qreal &scale); - void loadFfzEmotes(); - void loadBttvEmotes(); + void loadFFZEmotes(); + void loadBTTVEmotes(); }; } // namespace chatterino diff --git a/src/ircmanager.cpp b/src/ircmanager.cpp index b2a3eea0f..a702faed0 100644 --- a/src/ircmanager.cpp +++ b/src/ircmanager.cpp @@ -3,14 +3,15 @@ #include "asyncexec.hpp" #include "channel.hpp" #include "channelmanager.hpp" +#include "emotemanager.hpp" #include "messages/messageparseargs.hpp" #include "twitch/twitchmessagebuilder.hpp" #include "twitch/twitchparsemessage.hpp" #include "twitch/twitchuser.hpp" +#include "windowmanager.hpp" #include #include - #include #include #include @@ -23,12 +24,15 @@ using namespace chatterino::messages; namespace chatterino { -IrcManager IrcManager::instance; - const QString IrcManager::defaultClientId("7ue61iz46fz11y3cugd0l3tawb4taal"); -IrcManager::IrcManager() - : _account(AccountManager::getInstance().getTwitchUser()) +IrcManager::IrcManager(ChannelManager &_channelManager, Resources &_resources, + EmoteManager &_emoteManager, WindowManager &_windowManager) + : channelManager(_channelManager) + , resources(_resources) + , emoteManager(_emoteManager) + , windowManager(_windowManager) + , _account(AccountManager::getInstance().getTwitchUser()) { } @@ -168,7 +172,7 @@ void IrcManager::beginConnecting() this->writeConnection->moveToThread(QCoreApplication::instance()->thread()); this->readConnection->moveToThread(QCoreApplication::instance()->thread()); - for (auto &channel : ChannelManager::getInstance().getItems()) { + for (auto &channel : this->channelManager.getItems()) { this->writeConnection->sendRaw("JOIN #" + channel->getName()); this->readConnection->sendRaw("JOIN #" + channel->getName()); } @@ -231,12 +235,14 @@ void IrcManager::partChannel(const QString &channelName) void IrcManager::messageReceived(Communi::IrcMessage *message) { + /* qDebug() << "Message received: " << message->command(); // qInfo(message->command().toStdString().c_str()); // for (const auto ¶m : message->parameters()) { qDebug() << "Param: " << param; } + */ /* const QString &command = message->command(); @@ -252,12 +258,13 @@ void IrcManager::messageReceived(Communi::IrcMessage *message) void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message) { - auto c = ChannelManager::getInstance().getChannel(message->target().mid(1)); + auto c = this->channelManager.getChannel(message->target().mid(1)); if (c != nullptr) { messages::MessageParseArgs args; - c->addMessage(twitch::TwitchMessageBuilder::parse(message, c.get(), args)); + c->addMessage(twitch::TwitchMessageBuilder::parse(message, c.get(), args, this->resources, + this->emoteManager, this->windowManager)); } } diff --git a/src/ircmanager.hpp b/src/ircmanager.hpp index d701b8ec8..3eaadc345 100644 --- a/src/ircmanager.hpp +++ b/src/ircmanager.hpp @@ -16,15 +16,18 @@ namespace chatterino { +class ChannelManager; +class Resources; +class EmoteManager; +class WindowManager; + class IrcManager : public QObject { Q_OBJECT public: - static IrcManager &getInstance() - { - return instance; - } + IrcManager(ChannelManager &_channelManager, Resources &_resources, EmoteManager &_emoteManager, + WindowManager &_windowManager); static const QString defaultClientId; @@ -48,8 +51,10 @@ public: void setUser(const twitch::TwitchUser &account); private: - static IrcManager instance; - IrcManager(); + ChannelManager &channelManager; + Resources &resources; + EmoteManager &emoteManager; + WindowManager &windowManager; // variables twitch::TwitchUser _account; diff --git a/src/main.cpp b/src/main.cpp index bf6af7c59..635aef483 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include "application.hpp" #include "channelmanager.hpp" #include "colorscheme.hpp" #include "emojis.hpp" @@ -16,9 +17,6 @@ #include #include -using namespace chatterino; -using namespace chatterino::widgets; - namespace { inline bool initSettings(bool portable) @@ -68,28 +66,25 @@ int main(int argc, char *argv[]) } chatterino::logging::init(); - SettingsManager::getInstance().load(); - Resources::load(); - Emojis::loadEmojis(); - EmoteManager::getInstance().loadGlobalEmotes(); + chatterino::SettingsManager::getInstance().load(); + chatterino::Emojis::loadEmojis(); - ColorScheme::getInstance().init(); + int ret = 0; - WindowManager::getInstance().load(); + { + // Initialize application + chatterino::Application app; - MainWindow &w = WindowManager::getInstance().getMainWindow(); - w.show(); + // Start the application + ret = app.run(a); - IrcManager::getInstance().connect(); + // Application will go out of scope here and deinitialize itself + } - int ret = a.exec(); - - SettingsManager::getInstance().save(); + chatterino::SettingsManager::getInstance().save(); // Save settings pajlada::Settings::SettingManager::save(); - WindowManager::getInstance().save(); - return ret; } diff --git a/src/messages/lazyloadedimage.cpp b/src/messages/lazyloadedimage.cpp index 1502be22a..734940a1a 100644 --- a/src/messages/lazyloadedimage.cpp +++ b/src/messages/lazyloadedimage.cpp @@ -1,5 +1,4 @@ #include "messages/lazyloadedimage.hpp" - #include "asyncexec.hpp" #include "emotemanager.hpp" #include "ircmanager.hpp" @@ -18,15 +17,15 @@ namespace chatterino { namespace messages { -LazyLoadedImage::LazyLoadedImage(const QString &url, qreal scale, const QString &name, +LazyLoadedImage::LazyLoadedImage(EmoteManager &_emoteManager, WindowManager &_windowManager, + const QString &url, qreal scale, const QString &name, const QString &tooltip, const QMargins &margin, bool isHat) - : _currentPixmap(nullptr) - , _currentFrame(0) - , _currentFrameOffset(0) + : emoteManager(_emoteManager) + , windowManager(_windowManager) + , _currentPixmap(nullptr) , _url(url) , _name(name) , _tooltip(tooltip) - , _animated(false) , _margin(margin) , _ishat(isHat) , _scale(scale) @@ -34,14 +33,14 @@ LazyLoadedImage::LazyLoadedImage(const QString &url, qreal scale, const QString { } -LazyLoadedImage::LazyLoadedImage(QPixmap *image, qreal scale, const QString &name, +LazyLoadedImage::LazyLoadedImage(EmoteManager &_emoteManager, WindowManager &_windowManager, + QPixmap *image, qreal scale, const QString &name, const QString &tooltip, const QMargins &margin, bool isHat) - : _currentPixmap(image) - , _currentFrame(0) - , _currentFrameOffset(0) + : emoteManager(_emoteManager) + , windowManager(_windowManager) + , _currentPixmap(image) , _name(name) , _tooltip(tooltip) - , _animated(false) , _margin(margin) , _ishat(isHat) , _scale(scale) @@ -81,11 +80,13 @@ void LazyLoadedImage::loadImage() if (_allFrames.size() > 1) { _animated = true; - EmoteManager::getInstance().getGifUpdateSignal().connect([this] { gifUpdateTimout(); }); + this->emoteManager.getGifUpdateSignal().connect([this] { + gifUpdateTimout(); // + }); } - EmoteManager::getInstance().incGeneration(); - WindowManager::getInstance().layoutVisibleChatWidgets(); + this->emoteManager.incGeneration(); + this->windowManager.layoutVisibleChatWidgets(); }); } diff --git a/src/messages/lazyloadedimage.hpp b/src/messages/lazyloadedimage.hpp index 5397e14a6..6c922c8d4 100644 --- a/src/messages/lazyloadedimage.hpp +++ b/src/messages/lazyloadedimage.hpp @@ -4,15 +4,24 @@ #include namespace chatterino { + +class EmoteManager; +class WindowManager; + namespace messages { class LazyLoadedImage : QObject { public: - explicit LazyLoadedImage(const QString &_url, qreal _scale = 1, const QString &_name = "", + LazyLoadedImage() = delete; + + explicit LazyLoadedImage(EmoteManager &_emoteManager, WindowManager &_windowManager, + const QString &_url, qreal _scale = 1, const QString &_name = "", const QString &_tooltip = "", const QMargins &_margin = QMargins(), bool isHat = false); - explicit LazyLoadedImage(QPixmap *_currentPixmap, qreal _scale = 1, const QString &_name = "", + + explicit LazyLoadedImage(EmoteManager &_emoteManager, WindowManager &_windowManager, + QPixmap *_currentPixmap, qreal _scale = 1, const QString &_name = "", const QString &_tooltip = "", const QMargins &_margin = QMargins(), bool isHat = false); @@ -78,6 +87,9 @@ public: } private: + EmoteManager &emoteManager; + WindowManager &windowManager; + struct FrameData { QPixmap *image; int duration; @@ -85,13 +97,13 @@ private: QPixmap *_currentPixmap; std::vector _allFrames; - int _currentFrame; - int _currentFrameOffset; + int _currentFrame = 0; + int _currentFrameOffset = 0; QString _url; QString _name; QString _tooltip; - bool _animated; + bool _animated = false; QMargins _margin; bool _ishat; qreal _scale; diff --git a/src/messages/message.cpp b/src/messages/message.cpp index 90d46a8dc..a016e51c4 100644 --- a/src/messages/message.cpp +++ b/src/messages/message.cpp @@ -21,16 +21,16 @@ namespace chatterino { namespace messages { Message::Message(const QString &text) - : _words() - , _text(text) + : _text(text) + , _words() { _words.push_back( Word(text, Word::Text, ColorScheme::getInstance().SystemMessageColor, text, QString())); } Message::Message(const QString &text, const std::vector &words) - : _words(words) - , _text(text) + : _text(text) + , _words(words) { } diff --git a/src/messages/message.hpp b/src/messages/message.hpp index 7caca9d84..1ca097861 100644 --- a/src/messages/message.hpp +++ b/src/messages/message.hpp @@ -23,8 +23,8 @@ typedef std::shared_ptr SharedMessage; class Message { public: - Message(const QString &text); - Message(const QString &text, const std::vector &words); + explicit Message(const QString &text); + explicit Message(const QString &text, const std::vector &words); bool getCanHighlightTab() const; const QString &getTimeoutUser() const; diff --git a/src/messages/messageref.cpp b/src/messages/messageref.cpp index 402f82be2..28e5efad8 100644 --- a/src/messages/messageref.cpp +++ b/src/messages/messageref.cpp @@ -41,7 +41,11 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) int mediumTextLineHeight = FontManager::getInstance().getFontMetrics(FontManager::Medium).height(); + /* TODO(pajlada): Re-implement bool recalculateImages = _emoteGeneration != EmoteManager::getInstance().getGeneration(); + */ + bool recalculateImages = true; + bool recalculateText = _fontGeneration != FontManager::getInstance().getGeneration(); bool newWordTypes = _currentWordTypes != SettingsManager::getInstance().getWordTypeMask(); @@ -53,7 +57,7 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) return false; } - _emoteGeneration = EmoteManager::getInstance().getGeneration(); + // _emoteGeneration = EmoteManager::getInstance().getGeneration(); _fontGeneration = FontManager::getInstance().getGeneration(); for (auto &word : _message->getWords()) { diff --git a/src/resources.cpp b/src/resources.cpp index fc31b5633..4c87917f3 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -1,60 +1,39 @@ #include "resources.hpp" +#include "emotemanager.hpp" +#include "windowmanager.hpp" #include namespace chatterino { -messages::LazyLoadedImage *Resources::badgeStaff(nullptr); -messages::LazyLoadedImage *Resources::badgeAdmin(nullptr); -messages::LazyLoadedImage *Resources::badgeModerator(nullptr); -messages::LazyLoadedImage *Resources::badgeGlobalmod(nullptr); -messages::LazyLoadedImage *Resources::badgeTurbo(nullptr); -messages::LazyLoadedImage *Resources::badgeBroadcaster(nullptr); -messages::LazyLoadedImage *Resources::badgePremium(nullptr); +namespace { -messages::LazyLoadedImage *Resources::cheerBadge100000(nullptr); -messages::LazyLoadedImage *Resources::cheerBadge10000(nullptr); -messages::LazyLoadedImage *Resources::cheerBadge5000(nullptr); -messages::LazyLoadedImage *Resources::cheerBadge1000(nullptr); -messages::LazyLoadedImage *Resources::cheerBadge100(nullptr); -messages::LazyLoadedImage *Resources::cheerBadge1(nullptr); - -messages::LazyLoadedImage *Resources::buttonBan(nullptr); -messages::LazyLoadedImage *Resources::buttonTimeout(nullptr); - -Resources::Resources() +inline messages::LazyLoadedImage *lli(EmoteManager &emoteManager, WindowManager &windowManager, + const char *pixmapPath, qreal scale = 1) { + return new messages::LazyLoadedImage(emoteManager, windowManager, new QPixmap(pixmapPath), + scale); } -void Resources::load() +} // namespace + +Resources::Resources(EmoteManager &emoteManager, WindowManager &windowManager) + : badgeStaff(lli(emoteManager, windowManager, ":/images/staff_bg.png")) + , badgeAdmin(lli(emoteManager, windowManager, ":/images/admin_bg.png")) + , badgeGlobalModerator(lli(emoteManager, windowManager, ":/images/globalmod_bg.png")) + , badgeModerator(lli(emoteManager, windowManager, ":/images/moderator_bg.png")) + , badgeTurbo(lli(emoteManager, windowManager, ":/images/turbo_bg.png")) + , badgeBroadcaster(lli(emoteManager, windowManager, ":/images/broadcaster_bg.png")) + , badgePremium(lli(emoteManager, windowManager, ":/images/twitchprime_bg.png")) + , cheerBadge100000(lli(emoteManager, windowManager, ":/images/cheer100000")) + , cheerBadge10000(lli(emoteManager, windowManager, ":/images/cheer10000")) + , cheerBadge5000(lli(emoteManager, windowManager, ":/images/cheer5000")) + , cheerBadge1000(lli(emoteManager, windowManager, ":/images/cheer1000")) + , cheerBadge100(lli(emoteManager, windowManager, ":/images/cheer100")) + , cheerBadge1(lli(emoteManager, windowManager, ":/images/cheer1")) + , buttonBan(lli(emoteManager, windowManager, ":/images/button_ban.png", 0.25)) + , buttonTimeout(lli(emoteManager, windowManager, ":/images/button_timeout.png", 0.25)) { - // badges - Resources::badgeStaff = new messages::LazyLoadedImage(new QPixmap(":/images/staff_bg.png")); - Resources::badgeAdmin = new messages::LazyLoadedImage(new QPixmap(":/images/admin_bg.png")); - Resources::badgeModerator = - new messages::LazyLoadedImage(new QPixmap(":/images/moderator_bg.png")); - Resources::badgeGlobalmod = - new messages::LazyLoadedImage(new QPixmap(":/images/globalmod_bg.png")); - Resources::badgeTurbo = new messages::LazyLoadedImage(new QPixmap(":/images/turbo_bg.png")); - Resources::badgeBroadcaster = - new messages::LazyLoadedImage(new QPixmap(":/images/broadcaster_bg.png")); - Resources::badgePremium = - new messages::LazyLoadedImage(new QPixmap(":/images/twitchprime_bg.png")); - - // cheer badges - Resources::cheerBadge100000 = - new messages::LazyLoadedImage(new QPixmap(":/images/cheer100000")); - Resources::cheerBadge10000 = new messages::LazyLoadedImage(new QPixmap(":/images/cheer10000")); - Resources::cheerBadge5000 = new messages::LazyLoadedImage(new QPixmap(":/images/cheer5000")); - Resources::cheerBadge1000 = new messages::LazyLoadedImage(new QPixmap(":/images/cheer1000")); - Resources::cheerBadge100 = new messages::LazyLoadedImage(new QPixmap(":/images/cheer100")); - Resources::cheerBadge1 = new messages::LazyLoadedImage(new QPixmap(":/images/cheer1")); - - // button - Resources::buttonBan = - new messages::LazyLoadedImage(new QPixmap(":/images/button_ban.png"), 0.25); - Resources::buttonTimeout = - new messages::LazyLoadedImage(new QPixmap(":/images/button_timeout.png"), 0.25); } } // namespace chatterino diff --git a/src/resources.hpp b/src/resources.hpp index 2bbee465d..06f93c66a 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -4,108 +4,31 @@ namespace chatterino { +class EmoteManager; +class WindowManager; + class Resources { public: - static void load(); + explicit Resources(EmoteManager &emoteManager, WindowManager &windowManager); - // badges - static messages::LazyLoadedImage *getBadgeStaff() - { - return badgeStaff; - } + messages::LazyLoadedImage *badgeStaff; + messages::LazyLoadedImage *badgeAdmin; + messages::LazyLoadedImage *badgeGlobalModerator; + messages::LazyLoadedImage *badgeModerator; + messages::LazyLoadedImage *badgeTurbo; + messages::LazyLoadedImage *badgeBroadcaster; + messages::LazyLoadedImage *badgePremium; - static messages::LazyLoadedImage *getBadgeAdmin() - { - return badgeAdmin; - } + messages::LazyLoadedImage *cheerBadge100000; + messages::LazyLoadedImage *cheerBadge10000; + messages::LazyLoadedImage *cheerBadge5000; + messages::LazyLoadedImage *cheerBadge1000; + messages::LazyLoadedImage *cheerBadge100; + messages::LazyLoadedImage *cheerBadge1; - static messages::LazyLoadedImage *getBadgeGlobalmod() - { - return badgeGlobalmod; - } - - static messages::LazyLoadedImage *getBadgeModerator() - { - return badgeModerator; - } - - static messages::LazyLoadedImage *getBadgeTurbo() - { - return badgeTurbo; - } - - static messages::LazyLoadedImage *getBadgeBroadcaster() - { - return badgeBroadcaster; - } - - static messages::LazyLoadedImage *getBadgePremium() - { - return badgePremium; - } - - // cheer badges - static messages::LazyLoadedImage *getCheerBadge100000() - { - return cheerBadge100000; - } - - static messages::LazyLoadedImage *getCheerBadge10000() - { - return cheerBadge10000; - } - - static messages::LazyLoadedImage *getCheerBadge5000() - { - return cheerBadge5000; - } - - static messages::LazyLoadedImage *getCheerBadge1000() - { - return cheerBadge1000; - } - - static messages::LazyLoadedImage *getCheerBadge100() - { - return cheerBadge100; - } - - static messages::LazyLoadedImage *getCheerBadge1() - { - return cheerBadge1; - } - - static messages::LazyLoadedImage *getButtonBan() - { - return buttonBan; - } - - static messages::LazyLoadedImage *getButtonTimeout() - { - return buttonTimeout; - } - -private: - Resources(); - - static messages::LazyLoadedImage *badgeStaff; - static messages::LazyLoadedImage *badgeAdmin; - static messages::LazyLoadedImage *badgeGlobalmod; - static messages::LazyLoadedImage *badgeModerator; - static messages::LazyLoadedImage *badgeTurbo; - static messages::LazyLoadedImage *badgeBroadcaster; - static messages::LazyLoadedImage *badgePremium; - - static messages::LazyLoadedImage *cheerBadge100000; - static messages::LazyLoadedImage *cheerBadge10000; - static messages::LazyLoadedImage *cheerBadge5000; - static messages::LazyLoadedImage *cheerBadge1000; - static messages::LazyLoadedImage *cheerBadge100; - static messages::LazyLoadedImage *cheerBadge1; - - static messages::LazyLoadedImage *buttonBan; - static messages::LazyLoadedImage *buttonTimeout; + messages::LazyLoadedImage *buttonBan; + messages::LazyLoadedImage *buttonTimeout; }; } // namespace chatterino diff --git a/src/settingsmanager.hpp b/src/settingsmanager.hpp index 509f636e3..a300ef877 100644 --- a/src/settingsmanager.hpp +++ b/src/settingsmanager.hpp @@ -34,6 +34,7 @@ private: messages::Word::Type _wordTypeMask = messages::Word::Default; // methods +public: // temporary void updateWordTypeMask(); public: diff --git a/src/twitch/twitchmessagebuilder.cpp b/src/twitch/twitchmessagebuilder.cpp index dfff760ab..96ac5a1bb 100644 --- a/src/twitch/twitchmessagebuilder.cpp +++ b/src/twitch/twitchmessagebuilder.cpp @@ -4,6 +4,7 @@ #include "emotemanager.hpp" #include "ircmanager.hpp" #include "resources.hpp" +#include "windowmanager.hpp" using namespace chatterino::messages; @@ -17,45 +18,15 @@ TwitchMessageBuilder::TwitchMessageBuilder() { } -void TwitchMessageBuilder::appendTwitchBadges(const QStringList &badges) -{ - for (QString badge : badges) { - if (badge.startsWith("bits/")) { - long long int cheer = std::strtoll(badge.mid(5).toStdString().c_str(), nullptr, 10); - appendWord(Word(EmoteManager::getInstance().getCheerBadge(cheer), Word::BadgeCheer, - QString(), QString("Twitch Cheer" + QString::number(cheer)))); - } else if (badge == "staff/1") { - appendWord(Word(Resources::getBadgeStaff(), Word::BadgeStaff, QString(), - QString("Twitch Staff"))); - } else if (badge == "admin/1") { - appendWord(Word(Resources::getBadgeAdmin(), Word::BadgeAdmin, QString(), - QString("Twitch Admin"))); - } else if (badge == "global_mod/1") { - appendWord(Word(Resources::getBadgeGlobalmod(), Word::BadgeGlobalMod, QString(), - QString("Global Moderator"))); - } else if (badge == "moderator/1") { - // TODO: implement this xD - appendWord(Word(Resources::getBadgeTurbo(), Word::BadgeModerator, QString(), - QString("Channel Moderator"))); // custom badge - } else if (badge == "turbo/1") { - appendWord(Word(Resources::getBadgeStaff(), Word::BadgeTurbo, QString(), - QString("Turbo Subscriber"))); - } else if (badge == "broadcaster/1") { - appendWord(Word(Resources::getBadgeBroadcaster(), Word::BadgeBroadcaster, QString(), - QString("Channel Broadcaster"))); - } else if (badge == "premium/1") { - appendWord(Word(Resources::getBadgePremium(), Word::BadgePremium, QString(), - QString("Twitch Prime"))); - } - } -} - SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircMessage, - Channel *channel, const MessageParseArgs &args) + Channel *channel, const MessageParseArgs &args, + const Resources &resources, EmoteManager &emoteManager, + WindowManager &windowManager) { TwitchMessageBuilder b; - // timestamp + // The timestamp is always appended to the builder + // Whether or not will be rendered is decided/checked later b.appendTimestamp(); auto tags = ircMessage->tags(); @@ -69,14 +40,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM // timestamps iterator = tags.find("tmi-sent-ts"); - // mod buttons - static QString buttonBanTooltip("Ban user"); - static QString buttonTimeoutTooltip("Timeout user"); - - b.appendWord(Word(Resources::getButtonBan(), Word::ButtonBan, QString(), buttonBanTooltip, - Link(Link::UserBan, ircMessage->account()))); - b.appendWord(Word(Resources::getButtonTimeout(), Word::ButtonTimeout, QString(), - buttonTimeoutTooltip, Link(Link::UserTimeout, ircMessage->account()))); + b.appendModerationWords(ircMessage, resources); // badges iterator = tags.find("badges"); @@ -84,7 +48,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM if (iterator != tags.end()) { auto badges = iterator.value().toString().split(','); - b.appendTwitchBadges(badges); + b.appendTwitchBadges(badges, resources, emoteManager); } // color @@ -124,11 +88,13 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM displayName + (hasLocalizedName ? (" (" + ircMessage->account() + ")") : QString()); if (args.isSentWhisper) { - userDisplayString += IrcManager::getInstance().getUser().getUserName(); + // TODO(pajlada): Re-implement + // userDisplayString += IrcManager::getInstance().getUser().getUserName(); } if (args.isReceivedWhisper) { - userDisplayString += " -> " + IrcManager::getInstance().getUser().getUserName(); + // TODO(pajlada): Re-implement + // userDisplayString += " -> " + IrcManager::getInstance().getUser().getUserName(); } if (!ircMessage->isAction()) { @@ -153,40 +119,11 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM std::vector> twitchEmotes; iterator = tags.find("emotes"); - if (iterator != tags.end()) { - auto emotes = iterator.value().toString().split('/'); + QStringList emoteString = iterator.value().toString().split('/'); - for (QString emote : emotes) { - if (!emote.contains(':')) - continue; - - QStringList parameters = emote.split(':'); - - if (parameters.length() < 2) - continue; - - long int id = std::stol(parameters.at(0).toStdString(), nullptr, 10); - - QStringList occurences = parameters.at(1).split(','); - - for (QString occurence : occurences) { - QStringList coords = occurence.split('-'); - - if (coords.length() < 2) - continue; - - long int start = std::stol(coords.at(0).toStdString(), nullptr, 10); - long int end = std::stol(coords.at(1).toStdString(), nullptr, 10); - - if (start >= end || start < 0 || end > ircMessage->content().length()) - continue; - - QString name = ircMessage->content().mid(start, end - start + 1); - - twitchEmotes.push_back(std::pair( - start, EmoteManager::getInstance().getTwitchEmoteById(name, id))); - } + for (QString emote : emoteString) { + b.appendTwitchEmote(ircMessage, emote, twitchEmotes, emoteManager); } struct { @@ -270,13 +207,15 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM QString bitsLink = QString("http://static-cdn.jtvnw.net/bits/dark/static/" + color + "/1"); - LazyLoadedImage *imageAnimated = - EmoteManager::getInstance().getMiscImageFromCache().getOrAdd( - bitsLinkAnimated, - [&bitsLinkAnimated] { return new LazyLoadedImage(bitsLinkAnimated); }); - LazyLoadedImage *image = - EmoteManager::getInstance().getMiscImageFromCache().getOrAdd( - bitsLink, [&bitsLink] { return new LazyLoadedImage(bitsLink); }); + LazyLoadedImage *imageAnimated = emoteManager.getMiscImageFromCache().getOrAdd( + bitsLinkAnimated, [&emoteManager, &windowManager, &bitsLinkAnimated] { + return new LazyLoadedImage(emoteManager, windowManager, + bitsLinkAnimated); + }); + LazyLoadedImage *image = emoteManager.getMiscImageFromCache().getOrAdd( + bitsLink, [&emoteManager, &windowManager, &bitsLink] { + return new LazyLoadedImage(emoteManager, windowManager, bitsLink); + }); b.appendWord(Word(imageAnimated, Word::BitsAnimated, QString("cheer"), QString("Twitch Cheer"), @@ -302,11 +241,11 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM LazyLoadedImage *bttvEmote; // TODO: Implement this (ignored emotes) - if (EmoteManager::getInstance().getBttvEmotes().tryGet(string, bttvEmote) || + if (emoteManager.getBTTVEmotes().tryGet(string, bttvEmote) || channel->getBttvChannelEmotes().tryGet(string, bttvEmote) || - EmoteManager::getInstance().getFfzEmotes().tryGet(string, bttvEmote) || + emoteManager.getFFZEmotes().tryGet(string, bttvEmote) || channel->getFfzChannelEmotes().tryGet(string, bttvEmote) || - EmoteManager::getInstance().getChatterinoEmotes().tryGet(string, bttvEmote)) { + emoteManager.getChatterinoEmotes().tryGet(string, bttvEmote)) { b.appendWord(Word(bttvEmote, Word::BttvEmoteImage, bttvEmote->getName(), bttvEmote->getTooltip(), Link(Link::Url, bttvEmote->getUrl()))); @@ -340,6 +279,92 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM return b.build(); } +void TwitchMessageBuilder::appendModerationWords(const Communi::IrcPrivateMessage *ircMessage, + const Resources &resources) +{ + // mod buttons + static QString buttonBanTooltip("Ban user"); + static QString buttonTimeoutTooltip("Timeout user"); + + this->appendWord(Word(resources.buttonBan, Word::ButtonBan, QString(), buttonBanTooltip, + Link(Link::UserBan, ircMessage->account()))); + this->appendWord(Word(resources.buttonTimeout, Word::ButtonTimeout, QString(), + buttonTimeoutTooltip, Link(Link::UserTimeout, ircMessage->account()))); +} + +void TwitchMessageBuilder::appendTwitchEmote( + const Communi::IrcPrivateMessage *ircMessage, const QString &emote, + std::vector> &vec, EmoteManager &emoteManager) +{ + if (!emote.contains(':')) { + return; + } + + QStringList parameters = emote.split(':'); + + if (parameters.length() < 2) { + return; + } + + long int id = std::stol(parameters.at(0).toStdString(), nullptr, 10); + + QStringList occurences = parameters.at(1).split(','); + + for (QString occurence : occurences) { + QStringList coords = occurence.split('-'); + + if (coords.length() < 2) { + return; + } + + long int start = std::stol(coords.at(0).toStdString(), nullptr, 10); + long int end = std::stol(coords.at(1).toStdString(), nullptr, 10); + + if (start >= end || start < 0 || end > ircMessage->content().length()) { + return; + } + + QString name = ircMessage->content().mid(start, end - start + 1); + + vec.push_back(std::pair( + start, emoteManager.getTwitchEmoteById(name, id))); + } +} + +void TwitchMessageBuilder::appendTwitchBadges(const QStringList &badges, const Resources &resources, + EmoteManager &emoteManager) +{ + for (QString badge : badges) { + if (badge.startsWith("bits/")) { + long long int cheer = std::strtoll(badge.mid(5).toStdString().c_str(), nullptr, 10); + appendWord(Word(emoteManager.getCheerBadge(cheer), Word::BadgeCheer, QString(), + QString("Twitch Cheer" + QString::number(cheer)))); + } else if (badge == "staff/1") { + appendWord( + Word(resources.badgeStaff, Word::BadgeStaff, QString(), QString("Twitch Staff"))); + } else if (badge == "admin/1") { + appendWord( + Word(resources.badgeAdmin, Word::BadgeAdmin, QString(), QString("Twitch Admin"))); + } else if (badge == "global_mod/1") { + appendWord(Word(resources.badgeGlobalModerator, Word::BadgeGlobalMod, QString(), + QString("Global Moderator"))); + } else if (badge == "moderator/1") { + // TODO: implement this xD + appendWord(Word(resources.badgeTurbo, Word::BadgeModerator, QString(), + QString("Channel Moderator"))); // custom badge + } else if (badge == "turbo/1") { + appendWord(Word(resources.badgeStaff, Word::BadgeTurbo, QString(), + QString("Turbo Subscriber"))); + } else if (badge == "broadcaster/1") { + appendWord(Word(resources.badgeBroadcaster, Word::BadgeBroadcaster, QString(), + QString("Channel Broadcaster"))); + } else if (badge == "premium/1") { + appendWord(Word(resources.badgePremium, Word::BadgePremium, QString(), + QString("Twitch Prime"))); + } + } +} + // bool // sortTwitchEmotes(const std::pair &a, // const std::pair &b) diff --git a/src/twitch/twitchmessagebuilder.hpp b/src/twitch/twitchmessagebuilder.hpp index 9fd4af56c..53938d48d 100644 --- a/src/twitch/twitchmessagebuilder.hpp +++ b/src/twitch/twitchmessagebuilder.hpp @@ -4,8 +4,14 @@ #include "messages/messagebuilder.hpp" #include +#include namespace chatterino { + +class Resources; +class EmoteManager; +class WindowManager; + namespace twitch { class TwitchMessageBuilder : public messages::MessageBuilder @@ -13,17 +19,26 @@ class TwitchMessageBuilder : public messages::MessageBuilder public: TwitchMessageBuilder(); - void appendTwitchBadges(const QStringList &badges); - QString messageId; QString userName; static messages::SharedMessage parse(const Communi::IrcPrivateMessage *ircMessage, - Channel *channel, const messages::MessageParseArgs &args); + Channel *channel, const messages::MessageParseArgs &args, + const Resources &resources, EmoteManager &emoteManager, + WindowManager &windowManager); // static bool sortTwitchEmotes( // const std::pair &a, // const std::pair &b); + +private: + void appendModerationWords(const Communi::IrcPrivateMessage *ircMessage, + const Resources &resources); + void appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage, const QString &emote, + std::vector> &vec, + EmoteManager &emoteManager); + void appendTwitchBadges(const QStringList &badges, const Resources &resources, + EmoteManager &emoteManager); }; } // namespace twitch diff --git a/src/widgets/chatwidget.cpp b/src/widgets/chatwidget.cpp index 3a01c0d32..afe51b67e 100644 --- a/src/widgets/chatwidget.cpp +++ b/src/widgets/chatwidget.cpp @@ -30,9 +30,10 @@ inline void ezShortcut(ChatWidget *w, const char *key, T t) } // namespace -ChatWidget::ChatWidget(QWidget *parent) +ChatWidget::ChatWidget(ChannelManager &_channelManager, QWidget *parent) : QWidget(parent) - , channel(ChannelManager::getInstance().getEmpty()) + , channelManager(_channelManager) + , channel(_channelManager.getEmpty()) , vbox(this) , header(this) , view(this) @@ -90,7 +91,7 @@ void ChatWidget::setChannelName(const QString &_newChannelName) // remove current channel if (!this->channelName.isEmpty()) { - ChannelManager::getInstance().removeChannel(this->channelName); + this->channelManager.removeChannel(this->channelName); this->detachChannel(); } @@ -104,7 +105,7 @@ void ChatWidget::setChannelName(const QString &_newChannelName) if (newChannelName.isEmpty()) { this->channel = nullptr; } else { - this->setChannel(ChannelManager::getInstance().addChannel(newChannelName)); + this->setChannel(this->channelManager.addChannel(newChannelName)); } // update header @@ -240,7 +241,7 @@ void ChatWidget::doChangeChannel() void ChatWidget::doPopup() { // TODO: Copy signals and stuff too - auto widget = new ChatWidget(); + auto widget = new ChatWidget(this->channelManager); widget->setChannelName(this->getChannelName()); widget->show(); } diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index 9104ea68b..2cc359ae0 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -17,6 +17,9 @@ #include namespace chatterino { + +class ChannelManager; + namespace widgets { // Each ChatWidget consists of three sub-elements that handle their own part of the chat widget: @@ -34,7 +37,7 @@ class ChatWidget : public QWidget Q_OBJECT public: - ChatWidget(QWidget *parent = nullptr); + ChatWidget(ChannelManager &_channelManager, QWidget *parent = nullptr); ~ChatWidget(); std::shared_ptr getChannel() const; @@ -53,6 +56,8 @@ protected: void paintEvent(QPaintEvent *) override; private: + ChannelManager &channelManager; + void setChannel(std::shared_ptr newChannel); void detachChannel(); diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index aaa819f1f..f4a423dd9 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -1,4 +1,5 @@ #include "widgets/mainwindow.hpp" +#include "channelmanager.hpp" #include "colorscheme.hpp" #include "settingsmanager.hpp" #include "widgets/chatwidget.hpp" @@ -18,9 +19,10 @@ namespace chatterino { namespace widgets { -MainWindow::MainWindow(QWidget *parent) +MainWindow::MainWindow(ChannelManager &_channelManager, QWidget *parent) : QWidget(parent) - , _notebook(this) + , channelManager(_channelManager) + , notebook(this->channelManager, this) , _loaded(false) , _titleBar() { @@ -31,7 +33,7 @@ MainWindow::MainWindow(QWidget *parent) // layout->addWidget(&_titleBar); // } - layout->addWidget(&_notebook); + layout->addWidget(&this->notebook); setLayout(layout); // set margin @@ -63,7 +65,7 @@ MainWindow::~MainWindow() void MainWindow::layoutVisibleChatWidgets(Channel *channel) { - auto *page = _notebook.getSelectedPage(); + auto *page = this->notebook.getSelectedPage(); if (page == nullptr) { return; @@ -82,7 +84,7 @@ void MainWindow::layoutVisibleChatWidgets(Channel *channel) void MainWindow::repaintVisibleChatWidgets(Channel *channel) { - auto *page = _notebook.getSelectedPage(); + auto *page = this->notebook.getSelectedPage(); if (page == nullptr) { return; @@ -101,7 +103,7 @@ void MainWindow::repaintVisibleChatWidgets(Channel *channel) void MainWindow::repaintGifEmotes() { - auto *page = _notebook.getSelectedPage(); + auto *page = this->notebook.getSelectedPage(); if (page == nullptr) { return; @@ -118,7 +120,7 @@ void MainWindow::repaintGifEmotes() void MainWindow::load(const boost::property_tree::ptree &tree) { - this->_notebook.load(tree); + this->notebook.load(tree); _loaded = true; } @@ -129,14 +131,14 @@ boost::property_tree::ptree MainWindow::save() child.put("type", "main"); - _notebook.save(child); + this->notebook.save(child); return child; } void MainWindow::loadDefaults() { - _notebook.loadDefaults(); + this->notebook.loadDefaults(); _loaded = true; } @@ -148,7 +150,7 @@ bool MainWindow::isLoaded() const Notebook &MainWindow::getNotebook() { - return _notebook; + return this->notebook; } } // namespace widgets diff --git a/src/widgets/mainwindow.hpp b/src/widgets/mainwindow.hpp index 3e41a8f8d..d8c50c1b8 100644 --- a/src/widgets/mainwindow.hpp +++ b/src/widgets/mainwindow.hpp @@ -11,6 +11,9 @@ #include namespace chatterino { + +class ChannelManager; + namespace widgets { class MainWindow : public QWidget @@ -18,7 +21,7 @@ class MainWindow : public QWidget Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); + explicit MainWindow(ChannelManager &_channelManager, QWidget *parent = nullptr); ~MainWindow(); void layoutVisibleChatWidgets(Channel *channel = nullptr); @@ -34,7 +37,9 @@ public: Notebook &getNotebook(); private: - Notebook _notebook; + ChannelManager &channelManager; + + Notebook notebook; bool _loaded; TitleBar _titleBar; }; diff --git a/src/widgets/notebook.cpp b/src/widgets/notebook.cpp index c849b0936..2f56ec4ab 100644 --- a/src/widgets/notebook.cpp +++ b/src/widgets/notebook.cpp @@ -18,8 +18,9 @@ namespace chatterino { namespace widgets { -Notebook::Notebook(QWidget *parent) +Notebook::Notebook(ChannelManager &_channelManager, QWidget *parent) : QWidget(parent) + , channelManager(_channelManager) , _addButton(this) , _settingsButton(this) , _userButton(this) @@ -47,7 +48,7 @@ Notebook::Notebook(QWidget *parent) NotebookPage *Notebook::addPage(bool select) { auto tab = new NotebookTab(this); - auto page = new NotebookPage(this, tab); + auto page = new NotebookPage(this->channelManager, this, tab); tab->show(); diff --git a/src/widgets/notebook.hpp b/src/widgets/notebook.hpp index c9259df50..08491ba18 100644 --- a/src/widgets/notebook.hpp +++ b/src/widgets/notebook.hpp @@ -9,6 +9,9 @@ #include namespace chatterino { + +class ChannelManager; + namespace widgets { class Notebook : public QWidget @@ -18,7 +21,7 @@ class Notebook : public QWidget public: enum HighlightType { none, highlighted, newMessage }; - Notebook(QWidget *parent); + Notebook(ChannelManager &_channelManager, QWidget *parent); NotebookPage *addPage(bool select = false); @@ -46,6 +49,8 @@ public slots: void addPageButtonClicked(); private: + ChannelManager &channelManager; + QList _pages; NotebookButton _addButton; diff --git a/src/widgets/notebookpage.cpp b/src/widgets/notebookpage.cpp index 3e8423c2b..9fae9a3c7 100644 --- a/src/widgets/notebookpage.cpp +++ b/src/widgets/notebookpage.cpp @@ -19,9 +19,10 @@ bool NotebookPage::isDraggingSplit = false; ChatWidget *NotebookPage::draggingSplit = nullptr; std::pair NotebookPage::dropPosition = std::pair(-1, -1); -NotebookPage::NotebookPage(QWidget *parent, NotebookTab *tab) +NotebookPage::NotebookPage(ChannelManager &_channelManager, QWidget *parent, NotebookTab *_tab) : QWidget(parent) - , _tab(tab) + , channelManager(_channelManager) + , tab(_tab) , _parentbox(this) , _chatWidgets() , _preview(this) @@ -46,12 +47,12 @@ const std::vector &NotebookPage::getChatWidgets() const NotebookTab *NotebookPage::getTab() const { - return _tab; + return this->tab; } void NotebookPage::addChat(bool openChannelNameDialog) { - ChatWidget *w = new ChatWidget(); + ChatWidget *w = new ChatWidget(this->channelManager); if (openChannelNameDialog) { w->showChangeChannelPopup(); @@ -143,7 +144,7 @@ void NotebookPage::mouseReleaseEvent(QMouseEvent *event) { if (_hbox.count() == 0 && event->button() == Qt::LeftButton) { // "Add Chat" was clicked - addToLayout(new ChatWidget(), std::pair(-1, -1)); + addToLayout(new ChatWidget(this->channelManager), std::pair(-1, -1)); setCursor(QCursor(Qt::ArrowCursor)); } @@ -275,7 +276,7 @@ void NotebookPage::load(const boost::property_tree::ptree &tree) for (const auto &v : tree.get_child("columns.")) { int row = 0; for (const auto &innerV : v.second.get_child("")) { - auto widget = new ChatWidget(); + auto widget = new ChatWidget(this->channelManager); widget->load(innerV.second); addToLayout(widget, std::pair(column, row)); ++row; diff --git a/src/widgets/notebookpage.hpp b/src/widgets/notebookpage.hpp index 9f71a432d..6ca554b68 100644 --- a/src/widgets/notebookpage.hpp +++ b/src/widgets/notebookpage.hpp @@ -15,6 +15,9 @@ #include namespace chatterino { + +class ChannelManager; + namespace widgets { class NotebookPage : public QWidget @@ -22,7 +25,7 @@ class NotebookPage : public QWidget Q_OBJECT public: - NotebookPage(QWidget *parent, NotebookTab *_tab); + NotebookPage(ChannelManager &_channelManager, QWidget *parent, NotebookTab *_tab); std::pair removeFromLayout(ChatWidget *widget); void addToLayout(ChatWidget *widget, std::pair position); @@ -49,6 +52,8 @@ protected: void dropEvent(QDropEvent *event) override; private: + ChannelManager &channelManager; + struct DropRegion { QRect rect; std::pair position; @@ -60,7 +65,7 @@ private: } }; - NotebookTab *_tab; + NotebookTab *tab; QVBoxLayout _parentbox; QHBoxLayout _hbox; diff --git a/src/widgets/settingsdialog.cpp b/src/widgets/settingsdialog.cpp index 30123ef73..4d1e11171 100644 --- a/src/widgets/settingsdialog.cpp +++ b/src/widgets/settingsdialog.cpp @@ -153,7 +153,9 @@ void SettingsDialog::addTabs() QObject::connect(slider, &QSlider::valueChanged, this, [&settings](int value) { settings.themeHue.set(value / 1000.0); - WindowManager::getInstance().updateAll(); + + // TODO(pajlada): re-implement + // this->windowManager.updateAll(); }); group->setLayout(form); diff --git a/src/widgets/settingsdialog.hpp b/src/widgets/settingsdialog.hpp index 40aac2a55..1e4c5c04a 100644 --- a/src/widgets/settingsdialog.hpp +++ b/src/widgets/settingsdialog.hpp @@ -17,6 +17,7 @@ #include namespace chatterino { + namespace widgets { class SettingsDialog : public QWidget diff --git a/src/windowmanager.cpp b/src/windowmanager.cpp index d97c42923..8bfee6753 100644 --- a/src/windowmanager.cpp +++ b/src/windowmanager.cpp @@ -1,5 +1,6 @@ #include "windowmanager.hpp" #include "appdatapath.hpp" +#include "channelmanager.hpp" #include #include @@ -7,10 +8,9 @@ #include namespace chatterino { -WindowManager WindowManager::instance; -WindowManager::WindowManager() - : _mainWindow(nullptr) +WindowManager::WindowManager(ChannelManager &_channelManager) + : channelManager(_channelManager) { } @@ -23,41 +23,41 @@ static const std::string &getSettingsPath() void WindowManager::layoutVisibleChatWidgets(Channel *channel) { - if (_mainWindow != nullptr) { - _mainWindow->layoutVisibleChatWidgets(channel); + if (this->mainWindow != nullptr) { + this->mainWindow->layoutVisibleChatWidgets(channel); } } void WindowManager::repaintVisibleChatWidgets(Channel *channel) { - if (_mainWindow != nullptr) { - _mainWindow->repaintVisibleChatWidgets(channel); + if (this->mainWindow != nullptr) { + this->mainWindow->repaintVisibleChatWidgets(channel); } } void WindowManager::repaintGifEmotes() { - if (_mainWindow != nullptr) { - _mainWindow->repaintGifEmotes(); + if (this->mainWindow != nullptr) { + this->mainWindow->repaintGifEmotes(); } } void WindowManager::updateAll() { - if (_mainWindow != nullptr) { - _mainWindow->update(); + if (this->mainWindow != nullptr) { + this->mainWindow->update(); } } widgets::MainWindow &WindowManager::getMainWindow() { - std::lock_guard lock(_windowMutex); + std::lock_guard lock(this->windowMutex); - if (_mainWindow == nullptr) { - _mainWindow = new widgets::MainWindow(); + if (this->mainWindow == nullptr) { + this->mainWindow = new widgets::MainWindow(this->channelManager); } - return *_mainWindow; + return *this->mainWindow; } void WindowManager::load() diff --git a/src/windowmanager.hpp b/src/windowmanager.hpp index 88b8e78c8..cf81433a4 100644 --- a/src/windowmanager.hpp +++ b/src/windowmanager.hpp @@ -6,13 +6,12 @@ namespace chatterino { +class ChannelManager; + class WindowManager { public: - static WindowManager &getInstance() - { - return instance; - } + explicit WindowManager(ChannelManager &_channelManager); void layoutVisibleChatWidgets(Channel *channel = nullptr); void repaintVisibleChatWidgets(Channel *channel = nullptr); @@ -25,12 +24,12 @@ public: void save(); private: - static WindowManager instance; + ChannelManager &channelManager; - WindowManager(); + std::mutex windowMutex; - std::mutex _windowMutex; - widgets::MainWindow *_mainWindow; + // TODO(pajlada): Store as a value instead of a pointer + widgets::MainWindow *mainWindow = nullptr; }; } // namespace chatterino