diff --git a/src/providers/twitch/twitchserver.cpp b/src/providers/twitch/twitchserver.cpp index 78f45b4b6..8db98dd0b 100644 --- a/src/providers/twitch/twitchserver.cpp +++ b/src/providers/twitch/twitchserver.cpp @@ -5,6 +5,7 @@ #include "providers/twitch/twitchmessagebuilder.hpp" #include "singletons/accountmanager.hpp" #include "util/posttothread.hpp" +#include "singletons/completionmanager.hpp" #include @@ -83,6 +84,9 @@ void TwitchServer::privateMessageReceived(IrcPrivateMessage *message) TwitchMessageBuilder builder(chan.get(), message, args); + auto cm = singletons::CompletionManager::getInstance().createModel(chan->name); + cm->addUser(message->nick()); + if (!builder.isIgnored()) { messages::MessagePtr _message = builder.build(); if (_message->flags & messages::Message::Highlighted) { diff --git a/src/singletons/helper/completionmodel.cpp b/src/singletons/helper/completionmodel.cpp index afe9b2a83..34f9d2f96 100644 --- a/src/singletons/helper/completionmodel.cpp +++ b/src/singletons/helper/completionmodel.cpp @@ -6,6 +6,8 @@ #include "singletons/completionmanager.hpp" #include "singletons/emotemanager.hpp" +#include + namespace chatterino { namespace singletons { CompletionModel::CompletionModel(const QString &_channelName) @@ -18,7 +20,6 @@ void CompletionModel::refresh() // debug::Log("[CompletionModel:{}] Refreshing...]", this->channelName); auto &emoteManager = singletons::EmoteManager::getInstance(); - this->emotes.clear(); // User-specific: Twitch Emotes // TODO: Fix this so it properly updates with the proper api. oauth token needs proper scope @@ -79,13 +80,19 @@ void CompletionModel::refresh() void CompletionModel::addString(const std::string &str) { // Always add a space at the end of completions - this->emotes.push_back(qS(str) + " "); + this->emotes.insert(this->createEmote(str + " ")); } void CompletionModel::addString(const QString &str) { // Always add a space at the end of completions - this->emotes.push_back(str + " "); + this->emotes.insert(this->createEmote(str + " ")); +} + +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 7e62ff3bf..5d156970c 100644 --- a/src/singletons/helper/completionmodel.hpp +++ b/src/singletons/helper/completionmodel.hpp @@ -1,11 +1,13 @@ #pragma once #include -#include +#include #include #include +#include "common.hpp" + namespace chatterino { namespace singletons { class CompletionModel : public QAbstractListModel @@ -21,7 +23,9 @@ public: virtual QVariant data(const QModelIndex &index, int) const override { // TODO: Implement more safely - return QVariant(this->emotes.at(index.row())); + auto it = this->emotes.begin(); + std::advance(it, index.row()); + return QVariant(it->str); } virtual int rowCount(const QModelIndex &) const override @@ -30,14 +34,52 @@ public: } void refresh(); - -private: void addString(const std::string &str); void addString(const QString &str); - QVector emotes; + void addUser(const QString &str); + +private: + struct TaggedString { + QString str; + // emote == true + // username == false + bool isEmote = true; + bool operator<(const TaggedString &that) const + { + 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; + } 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; + } + } + } + }; + TaggedString createEmote(const std::string &str) + { + return TaggedString{qS(str), true}; + } + TaggedString createEmote(const QString &str) + { + return TaggedString{str, true}; + } + TaggedString createUser(const QString &str) + { + return TaggedString{str, false}; + } + std::set emotes; QString channelName; }; -} -} +} // namespace singletons +} // namespace chatterino diff --git a/src/widgets/helper/splitinput.cpp b/src/widgets/helper/splitinput.cpp index 5915a1414..e723aff2e 100644 --- a/src/widgets/helper/splitinput.cpp +++ b/src/widgets/helper/splitinput.cpp @@ -8,6 +8,7 @@ #include "widgets/notebook.hpp" #include "widgets/split.hpp" #include "widgets/splitcontainer.hpp" +#include "util/urlfetch.hpp" #include #include @@ -24,6 +25,20 @@ SplitInput::SplitInput(Split *_chatWidget) // 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()); + } + }); this->ui.textEdit->setCompleter(completer);