diff --git a/chatterino.pro b/chatterino.pro index b972b2f2d..4f64107f2 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -114,7 +114,6 @@ SOURCES += \ src/singletons/accountmanager.cpp \ src/singletons/channelmanager.cpp \ src/singletons/commandmanager.cpp \ - src/singletons/completionmanager.cpp \ src/singletons/emotemanager.cpp \ src/singletons/fontmanager.cpp \ src/singletons/helper/completionmodel.cpp \ @@ -208,7 +207,6 @@ HEADERS += \ src/singletons/accountmanager.hpp \ src/singletons/channelmanager.hpp \ src/singletons/commandmanager.hpp \ - src/singletons/completionmanager.hpp \ src/singletons/emotemanager.hpp \ src/singletons/fontmanager.hpp \ src/singletons/helper/chatterinosetting.hpp \ diff --git a/src/channel.cpp b/src/channel.cpp index 58a65d9a3..08265f395 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -20,6 +20,7 @@ namespace chatterino { Channel::Channel(const QString &_name) : name(_name) + , completionModel(this->name) { } diff --git a/src/channel.hpp b/src/channel.hpp index 1b06f4bf2..dd520f734 100644 --- a/src/channel.hpp +++ b/src/channel.hpp @@ -3,6 +3,7 @@ #include "messages/image.hpp" #include "messages/limitedqueue.hpp" #include "messages/message.hpp" +#include "singletons/helper/completionmodel.hpp" #include "util/concurrentmap.hpp" #include @@ -64,6 +65,8 @@ public: static std::shared_ptr getEmpty(); + singletons::CompletionModel completionModel; + protected: virtual void onConnected(); diff --git a/src/providers/twitch/twitchchannel.cpp b/src/providers/twitch/twitchchannel.cpp index 281f92ebc..adb7cfe32 100644 --- a/src/providers/twitch/twitchchannel.cpp +++ b/src/providers/twitch/twitchchannel.cpp @@ -16,6 +16,7 @@ namespace chatterino { namespace providers { namespace twitch { + TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection *_readConnection) : Channel(channelName) , bttvChannelEmotes(new util::EmoteMap) @@ -47,6 +48,27 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection this->messageSuffix.append(' '); this->messageSuffix.append(QChar(0x206D)); + + static QStringList jsonLabels = {"moderators", "staff", "admins", "global_mods", "viewers"}; + auto refreshChatters = [=](QJsonObject obj) { + QJsonObject chattersObj = obj.value("chatters").toObject(); + for (int i = 0; i < jsonLabels.size(); i++) { + foreach (const QJsonValue &v, chattersObj.value(jsonLabels.at(i)).toArray()) { + this->completionModel.addUser(v.toString()); + } + } + }; + + auto doRefreshChatters = [=]() { + util::twitch::get("https://tmi.twitch.tv/group/user/" + this->name + "/chatters", + QThread::currentThread(), refreshChatters); + }; + + doRefreshChatters(); + + this->chattersListTimer = new QTimer; + QObject::connect(this->chattersListTimer, &QTimer::timeout, doRefreshChatters); + this->chattersListTimer->start(5 * 60 * 1000); } TwitchChannel::~TwitchChannel() @@ -55,6 +77,9 @@ TwitchChannel::~TwitchChannel() this->liveStatusTimer->stop(); this->liveStatusTimer->deleteLater(); + + this->chattersListTimer->stop(); + this->chattersListTimer->deleteLater(); } bool TwitchChannel::isEmpty() const @@ -104,7 +129,7 @@ void TwitchChannel::sendMessage(const QString &message) parsedMessage.append(this->messageSuffix); this->lastSentMessage = ""; - } + } } this->lastSentMessage = parsedMessage; diff --git a/src/providers/twitch/twitchchannel.hpp b/src/providers/twitch/twitchchannel.hpp index 90d077a70..c0aba110b 100644 --- a/src/providers/twitch/twitchchannel.hpp +++ b/src/providers/twitch/twitchchannel.hpp @@ -11,10 +11,13 @@ namespace chatterino { namespace providers { namespace twitch { + class TwitchServer; + class TwitchChannel final : public Channel { QTimer *liveStatusTimer; + QTimer *chattersListTimer; public: ~TwitchChannel(); @@ -69,6 +72,7 @@ private: friend class TwitchServer; }; + } // namespace twitch } // namespace providers } // namespace chatterino diff --git a/src/providers/twitch/twitchserver.cpp b/src/providers/twitch/twitchserver.cpp index 8db98dd0b..c45b5193a 100644 --- a/src/providers/twitch/twitchserver.cpp +++ b/src/providers/twitch/twitchserver.cpp @@ -5,7 +5,6 @@ #include "providers/twitch/twitchmessagebuilder.hpp" #include "singletons/accountmanager.hpp" #include "util/posttothread.hpp" -#include "singletons/completionmanager.hpp" #include @@ -84,8 +83,8 @@ void TwitchServer::privateMessageReceived(IrcPrivateMessage *message) TwitchMessageBuilder builder(chan.get(), message, args); - auto cm = singletons::CompletionManager::getInstance().createModel(chan->name); - cm->addUser(message->nick()); + // XXX: Thread-safety + chan->completionModel.addUser(message->nick()); if (!builder.isIgnored()) { messages::MessagePtr _message = builder.build(); diff --git a/src/singletons/completionmanager.cpp b/src/singletons/completionmanager.cpp deleted file mode 100644 index bb7326eae..000000000 --- a/src/singletons/completionmanager.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "singletons/completionmanager.hpp" -#include "common.hpp" -#include "debug/log.hpp" -#include "singletons/channelmanager.hpp" -#include "singletons/emotemanager.hpp" - -namespace chatterino { -namespace singletons { - -CompletionManager &CompletionManager::getInstance() -{ - static CompletionManager instance; - return instance; -} - -CompletionModel *CompletionManager::createModel(const QString &channelName) -{ - auto it = this->models.find(channelName); - if (it != this->models.end()) { - return it->second; - } - - CompletionModel *ret = new CompletionModel(channelName); - this->models[channelName] = ret; - - return ret; -} - -} // namespace singletons -} // namespace chatterino diff --git a/src/singletons/completionmanager.hpp b/src/singletons/completionmanager.hpp deleted file mode 100644 index 3efd7b828..000000000 --- a/src/singletons/completionmanager.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "helper/completionmodel.hpp" - -namespace chatterino { -namespace singletons { -class CompletionManager -{ - CompletionManager() = default; - -public: - static CompletionManager &getInstance(); - - CompletionModel *createModel(const QString &channelName); - -private: - std::map models; -}; - -} // namespace singletons -} // namespace chatterino diff --git a/src/singletons/helper/completionmodel.cpp b/src/singletons/helper/completionmodel.cpp index 9c6c3df1a..02c3be467 100644 --- a/src/singletons/helper/completionmodel.cpp +++ b/src/singletons/helper/completionmodel.cpp @@ -3,13 +3,13 @@ #include "common.hpp" #include "debug/log.hpp" #include "singletons/channelmanager.hpp" -#include "singletons/completionmanager.hpp" #include "singletons/emotemanager.hpp" #include namespace chatterino { namespace singletons { + CompletionModel::CompletionModel(const QString &_channelName) : channelName(_channelName) { @@ -94,5 +94,6 @@ void CompletionModel::addUser(const QString &str) // Always add a space at the end of completions this->emotes.insert(this->createUser(str + " ")); } + } // namespace singletons } // namespace chatterino diff --git a/src/singletons/helper/completionmodel.hpp b/src/singletons/helper/completionmodel.hpp index 5d156970c..6c7bef633 100644 --- a/src/singletons/helper/completionmodel.hpp +++ b/src/singletons/helper/completionmodel.hpp @@ -1,15 +1,16 @@ #pragma once -#include -#include - -#include -#include - #include "common.hpp" +#include + +#include +#include +#include + namespace chatterino { namespace singletons { + class CompletionModel : public QAbstractListModel { public: @@ -50,17 +51,23 @@ private: if (this->isEmote) { if (that.isEmote) { int k = QString::compare(this->str, that.str, Qt::CaseInsensitive); - if (k == 0) return this->str > that.str; - else return k < 0; + if (k == 0) { + return this->str > that.str; + } else { + return k < 0; + } } else return true; } else { if (that.isEmote) return false; else { - int k = QString::compare(this->str, that.str, Qt::CaseInsensitive);; - if (k == 0) return this->str > that.str; - else return k < 0; + int k = QString::compare(this->str, that.str, Qt::CaseInsensitive); + if (k == 0) { + return this->str > that.str; + } else { + return k < 0; + } } } } @@ -81,5 +88,6 @@ private: QString channelName; }; + } // namespace singletons } // namespace chatterino diff --git a/src/widgets/helper/resizingtextedit.cpp b/src/widgets/helper/resizingtextedit.cpp index 28db51819..89a55fdcb 100644 --- a/src/widgets/helper/resizingtextedit.cpp +++ b/src/widgets/helper/resizingtextedit.cpp @@ -1,6 +1,6 @@ #include "widgets/helper/resizingtextedit.hpp" #include "common.hpp" -#include "singletons/completionmanager.hpp" +#include "singletons/helper/completionmodel.hpp" ResizingTextEdit::ResizingTextEdit() { diff --git a/src/widgets/helper/splitinput.cpp b/src/widgets/helper/splitinput.cpp index e723aff2e..18ddb6528 100644 --- a/src/widgets/helper/splitinput.cpp +++ b/src/widgets/helper/splitinput.cpp @@ -1,14 +1,13 @@ #include "widgets/helper/splitinput.hpp" #include "singletons/commandmanager.hpp" -#include "singletons/completionmanager.hpp" #include "singletons/ircmanager.hpp" #include "singletons/settingsmanager.hpp" #include "singletons/thememanager.hpp" #include "util/layoutcreator.hpp" +#include "util/urlfetch.hpp" #include "widgets/notebook.hpp" #include "widgets/split.hpp" #include "widgets/splitcontainer.hpp" -#include "util/urlfetch.hpp" #include #include @@ -22,26 +21,14 @@ SplitInput::SplitInput(Split *_chatWidget) { this->initLayout(); - // auto completion - auto completer = new QCompleter( - singletons::CompletionManager::getInstance().createModel(this->chatWidget->channelName)); - auto cc = singletons::CompletionManager::getInstance().createModel(this->chatWidget->channelName); - cc->refresh(); - - - static QStringList jsonLabels = {"moderators", "staff", "admins", "global_mods", "viewers"}; - util::twitch::get("https://tmi.twitch.tv/group/user/" + this->chatWidget->channelName + "/chatters", this, - [cc](QJsonObject obj) { - QJsonObject chattersObj = obj.value("chatters").toObject(); - for (int i = 0; i < jsonLabels.size(); i++) { - foreach (const QJsonValue &v, - chattersObj.value(jsonLabels.at(i)).toArray()) - cc->addUser(v.toString()); - } - }); - + auto completer = new QCompleter(&this->chatWidget->getChannel()->completionModel); this->ui.textEdit->setCompleter(completer); + this->chatWidget->channelChanged.connect([this] { + auto completer = new QCompleter(&this->chatWidget->getChannel()->completionModel); + this->ui.textEdit->setCompleter(completer); + }); + // misc this->installKeyPressedEvent(); this->themeRefreshEvent();