Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis #2999

Merged
merged 10 commits into from
Jul 17, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unversioned

- Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999)
- Bugfix: Fixed "smiley" emotes being unable to be "Tabbed" with autocompletion, introduced in v2.3.3. (#3010)
- Dev: Ubuntu packages are now available (#2936)

Expand Down
170 changes: 88 additions & 82 deletions src/common/CompletionModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,124 +73,130 @@ int CompletionModel::rowCount(const QModelIndex &) const

void CompletionModel::refresh(const QString &prefix, bool isFirstWord)
{
std::function<void(const QString &, TaggedString::Type)> addString;
std::lock_guard<std::mutex> guard(this->itemsMutex_);
this->items_.clear();

if (prefix.length() < 2 || !this->channel_.isTwitchChannel())
{
return;
}

// Twitch channel
auto tc = dynamic_cast<TwitchChannel *>(&this->channel_);

std::function<void(const QString &str, TaggedString::Type type)> addString;
if (getSettings()->prefixOnlyEmoteCompletion)
{
addString = [&](const QString &str, TaggedString::Type type) {
addString = [=](const QString &str, TaggedString::Type type) {
if (str.startsWith(prefix, Qt::CaseInsensitive))
this->items_.emplace(str + " ", type);
};
}
else
{
addString = [&](const QString &str, TaggedString::Type type) {
addString = [=](const QString &str, TaggedString::Type type) {
if (str.contains(prefix, Qt::CaseInsensitive))
this->items_.emplace(str + " ", type);
};
}

std::lock_guard<std::mutex> guard(this->itemsMutex_);
this->items_.clear();

if (prefix.length() < 2)
return;

if (auto channel = dynamic_cast<TwitchChannel *>(&this->channel_))
if (auto account = getApp()->accounts->twitch.getCurrent())
{
if (auto account = getApp()->accounts->twitch.getCurrent())
// Twitch Emotes available globally
for (const auto &emote : account->accessEmotes()->emotes)
{
// Twitch Emotes available globally
for (const auto &emote : account->accessEmotes()->emotes)
{
addString(emote.first.string, TaggedString::TwitchGlobalEmote);
}
addString(emote.first.string, TaggedString::TwitchGlobalEmote);
}

// Twitch Emotes available locally
auto localEmoteData = account->accessLocalEmotes();
if (localEmoteData->find(channel->roomId()) !=
localEmoteData->end())
// Twitch Emotes available locally
auto localEmoteData = account->accessLocalEmotes();
if (tc && localEmoteData->find(tc->roomId()) != localEmoteData->end())
{
for (const auto &emote : localEmoteData->at(tc->roomId()))
{
for (const auto &emote : localEmoteData->at(channel->roomId()))
{
addString(emote.first.string,
TaggedString::Type::TwitchLocalEmote);
}
addString(emote.first.string,
TaggedString::Type::TwitchLocalEmote);
}
}
}

// Bttv Global
for (auto &emote : *getApp()->twitch2->getBttvEmotes().emotes())
{
addString(emote.first.string, TaggedString::Type::BTTVChannelEmote);
}

// Usernames
QString usernamePostfix =
isFirstWord && getSettings()->mentionUsersWithComma ? ","
: QString();
// Ffz Global
for (auto &emote : *getApp()->twitch2->getFfzEmotes().emotes())
{
addString(emote.first.string, TaggedString::Type::FFZChannelEmote);
}

if (prefix.startsWith("@"))
// Emojis
if (prefix.startsWith(":"))
{
const auto &emojiShortCodes = getApp()->emotes->emojis.shortCodes;
for (auto &m : emojiShortCodes)
{
QString usernamePrefix = prefix;
usernamePrefix.remove(0, 1);
addString(QString(":%1:").arg(m), TaggedString::Type::Emoji);
}
}

auto chatters =
channel->accessChatters()->filterByPrefix(usernamePrefix);
//
// Stuff below is available only in regular Twitch channels
if (!tc)
{
return;
}

for (const auto &name : chatters)
{
addString("@" + name + usernamePostfix,
TaggedString::Type::Username);
}
}
else if (!getSettings()->userCompletionOnlyWithAt)
{
auto chatters = channel->accessChatters()->filterByPrefix(prefix);
// Usernames
QString usernamePostfix =
isFirstWord && getSettings()->mentionUsersWithComma ? "," : QString();

for (const auto &name : chatters)
{
addString(name + usernamePostfix, TaggedString::Type::Username);
}
}
if (prefix.startsWith("@"))
{
QString usernamePrefix = prefix;
usernamePrefix.remove(0, 1);

// Bttv Global
for (auto &emote : *getApp()->twitch2->getBttvEmotes().emotes())
{
addString(emote.first.string, TaggedString::Type::BTTVChannelEmote);
}
auto chatters = tc->accessChatters()->filterByPrefix(usernamePrefix);

// Ffz Global
for (auto &emote : *getApp()->twitch2->getFfzEmotes().emotes())
for (const auto &name : chatters)
{
addString(emote.first.string, TaggedString::Type::FFZChannelEmote);
addString("@" + name + usernamePostfix,
TaggedString::Type::Username);
}
}
else if (!getSettings()->userCompletionOnlyWithAt)
{
auto chatters = tc->accessChatters()->filterByPrefix(prefix);

// Bttv Channel
for (auto &emote : *channel->bttvEmotes())
for (const auto &name : chatters)
{
addString(emote.first.string, TaggedString::Type::BTTVGlobalEmote);
addString(name + usernamePostfix, TaggedString::Type::Username);
}
}

// Ffz Channel
for (auto &emote : *channel->ffzEmotes())
{
addString(emote.first.string, TaggedString::Type::BTTVGlobalEmote);
}
// Bttv Channel
for (auto &emote : *tc->bttvEmotes())
{
addString(emote.first.string, TaggedString::Type::BTTVGlobalEmote);
}

// Emojis
if (prefix.startsWith(":"))
{
const auto &emojiShortCodes = getApp()->emotes->emojis.shortCodes;
for (auto &m : emojiShortCodes)
{
addString(":" + m + ":", TaggedString::Type::Emoji);
}
}
// Ffz Channel
for (auto &emote : *tc->ffzEmotes())
{
addString(emote.first.string, TaggedString::Type::BTTVGlobalEmote);
}

// Commands
for (auto &command : getApp()->commands->items_)
{
addString(command.name, TaggedString::Command);
}
// Commands
for (auto &command : getApp()->commands->items_)
{
addString(command.name, TaggedString::Command);
}

for (auto &command : getApp()->commands->getDefaultTwitchCommandList())
{
addString(command, TaggedString::Command);
}
for (auto &command : getApp()->commands->getDefaultTwitchCommandList())
{
addString(command, TaggedString::Command);
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/common/CompletionModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ class CompletionModel : public QAbstractListModel
static bool compareStrings(const QString &a, const QString &b);

private:
TaggedString createUser(const QString &str);

std::set<TaggedString> items_;
mutable std::mutex itemsMutex_;
Channel &channel_;
Expand Down