Refactor the EmotePopup file (#4239)

Flatten the anonymous namespace
Make the `loadEmojis` functions static
Make the `filterEmoteMap` function static
Return an EmoteMap from `filterEmoteMap` instead of an EmoteMap*
Other misc cool changes :-)
This commit is contained in:
pajlada 2022-12-17 18:33:17 +01:00 committed by GitHub
parent f062c793e4
commit b074a8f7eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 207 additions and 188 deletions

View file

@ -22,146 +22,190 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QTabWidget> #include <QTabWidget>
namespace chatterino { #include <utility>
namespace { namespace {
auto makeTitleMessage(const QString &title)
using namespace chatterino;
auto makeTitleMessage(const QString &title)
{
MessageBuilder builder;
builder.emplace<TextElement>(title, MessageElementFlag::Text);
builder->flags.set(MessageFlag::Centered);
return builder.release();
}
auto makeEmoteMessage(const EmoteMap &map, const MessageElementFlag &emoteFlag)
{
MessageBuilder builder;
builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes);
if (map.empty())
{ {
MessageBuilder builder; builder.emplace<TextElement>("no emotes available",
builder.emplace<TextElement>(title, MessageElementFlag::Text); MessageElementFlag::Text,
builder->flags.set(MessageFlag::Centered); MessageColor::System);
return builder.release(); return builder.release();
} }
auto makeEmoteMessage(const EmoteMap &map,
const MessageElementFlag &emoteFlag) std::vector<std::pair<EmoteName, EmotePtr>> vec(map.begin(), map.end());
std::sort(vec.begin(), vec.end(),
[](const std::pair<EmoteName, EmotePtr> &l,
const std::pair<EmoteName, EmotePtr> &r) {
return CompletionModel::compareStrings(l.first.string,
r.first.string);
});
for (const auto &emote : vec)
{ {
builder
.emplace<EmoteElement>(
emote.second,
MessageElementFlags{MessageElementFlag::AlwaysShow, emoteFlag})
->setLink(Link(Link::InsertText, emote.first.string));
}
return builder.release();
}
auto makeEmojiMessage(EmojiMap &emojiMap)
{
MessageBuilder builder;
builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes);
emojiMap.each([&builder](const auto &key, const auto &value) {
(void)key; // unused
builder
.emplace<EmoteElement>(
value->emote,
MessageElementFlags{MessageElementFlag::AlwaysShow,
MessageElementFlag::EmojiAll})
->setLink(
Link(Link::Type::InsertText, ":" + value->shortCodes[0] + ":"));
});
return builder.release();
}
void addTwitchEmoteSets(
std::vector<std::shared_ptr<TwitchAccount::EmoteSet>> sets,
Channel &globalChannel, Channel &subChannel, QString currentChannelName)
{
QMap<QString, QPair<bool, std::vector<MessagePtr>>> mapOfSets;
for (const auto &set : sets)
{
// Some emotes (e.g. follower ones) are only available in their origin channel
if (set->local && currentChannelName != set->channelName)
{
continue;
}
// TITLE
auto channelName = set->channelName;
auto text = set->text.isEmpty() ? "Twitch" : set->text;
// EMOTES
MessageBuilder builder; MessageBuilder builder;
builder->flags.set(MessageFlag::Centered); builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes); builder->flags.set(MessageFlag::DisableCompactEmotes);
if (map.empty()) // If value of map is empty, create init pair and add title.
if (mapOfSets.find(channelName) == mapOfSets.end())
{ {
builder.emplace<TextElement>("no emotes available", std::vector<MessagePtr> b;
MessageElementFlag::Text, b.push_back(makeTitleMessage(text));
MessageColor::System); mapOfSets[channelName] = qMakePair(set->key == "0", b);
return builder.release();
} }
std::vector<std::pair<EmoteName, EmotePtr>> vec(map.begin(), map.end()); for (const auto &emote : set->emotes)
std::sort(vec.begin(), vec.end(),
[](const std::pair<EmoteName, EmotePtr> &l,
const std::pair<EmoteName, EmotePtr> &r) {
return CompletionModel::compareStrings(l.first.string,
r.first.string);
});
for (const auto &emote : vec)
{ {
builder builder
.emplace<EmoteElement>( .emplace<EmoteElement>(
emote.second, getApp()->emotes->twitch.getOrCreateEmote(emote.id,
emote.name),
MessageElementFlags{MessageElementFlag::AlwaysShow, MessageElementFlags{MessageElementFlag::AlwaysShow,
emoteFlag}) MessageElementFlag::TwitchEmote})
->setLink(Link(Link::InsertText, emote.first.string)); ->setLink(Link(Link::InsertText, emote.name.string));
} }
return builder.release(); mapOfSets[channelName].second.push_back(builder.release());
} }
auto makeEmojiMessage(EmojiMap &emojiMap)
// Output to channel all created messages,
// That contain title or emotes.
// Put current channel emotes at the top
auto currentChannelPair = mapOfSets[currentChannelName];
for (const auto &message : currentChannelPair.second)
{ {
MessageBuilder builder; subChannel.addMessage(message);
builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes);
emojiMap.each([&builder](const auto &key, const auto &value) {
builder
.emplace<EmoteElement>(
value->emote,
MessageElementFlags{MessageElementFlag::AlwaysShow,
MessageElementFlag::EmojiAll})
->setLink(Link(Link::Type::InsertText,
":" + value->shortCodes[0] + ":"));
});
return builder.release();
} }
void addEmoteSets( mapOfSets.remove(currentChannelName);
std::vector<std::shared_ptr<TwitchAccount::EmoteSet>> sets,
Channel &globalChannel, Channel &subChannel, QString currentChannelName) for (const auto &pair : mapOfSets)
{ {
QMap<QString, QPair<bool, std::vector<MessagePtr>>> mapOfSets; auto &channel = pair.first ? globalChannel : subChannel;
for (const auto &message : pair.second)
for (const auto &set : sets)
{ {
// Some emotes (e.g. follower ones) are only available in their origin channel channel.addMessage(message);
if (set->local && currentChannelName != set->channelName)
{
continue;
}
// TITLE
auto channelName = set->channelName;
auto text = set->text.isEmpty() ? "Twitch" : set->text;
// EMOTES
MessageBuilder builder;
builder->flags.set(MessageFlag::Centered);
builder->flags.set(MessageFlag::DisableCompactEmotes);
// If value of map is empty, create init pair and add title.
if (mapOfSets.find(channelName) == mapOfSets.end())
{
std::vector<MessagePtr> b;
b.push_back(makeTitleMessage(text));
mapOfSets[channelName] = qMakePair(set->key == "0", b);
}
for (const auto &emote : set->emotes)
{
builder
.emplace<EmoteElement>(
getApp()->emotes->twitch.getOrCreateEmote(emote.id,
emote.name),
MessageElementFlags{MessageElementFlag::AlwaysShow,
MessageElementFlag::TwitchEmote})
->setLink(Link(Link::InsertText, emote.name.string));
}
mapOfSets[channelName].second.push_back(builder.release());
}
// Output to channel all created messages,
// That contain title or emotes.
// Put current channel emotes at the top
auto currentChannelPair = mapOfSets[currentChannelName];
for (auto message : currentChannelPair.second)
{
subChannel.addMessage(message);
}
mapOfSets.remove(currentChannelName);
foreach (auto pair, mapOfSets)
{
auto &channel = pair.first ? globalChannel : subChannel;
for (auto message : pair.second)
{
channel.addMessage(message);
}
} }
} }
void addEmotes(Channel &channel, const EmoteMap &map, const QString &title, }
const MessageElementFlag &emoteFlag)
void addEmotes(Channel &channel, const EmoteMap &map, const QString &title,
const MessageElementFlag &emoteFlag)
{
channel.addMessage(makeTitleMessage(title));
channel.addMessage(makeEmoteMessage(map, emoteFlag));
}
void loadEmojis(ChannelView &view, EmojiMap &emojiMap)
{
ChannelPtr emojiChannel(new Channel("", Channel::Type::None));
emojiChannel->addMessage(makeEmojiMessage(emojiMap));
view.setChannel(emojiChannel);
}
void loadEmojis(Channel &channel, EmojiMap &emojiMap, const QString &title)
{
channel.addMessage(makeTitleMessage(title));
channel.addMessage(makeEmojiMessage(emojiMap));
}
// Create an emote
EmoteMap filterEmoteMap(const QString &text,
std::shared_ptr<const EmoteMap> emotes)
{
EmoteMap filteredMap;
for (const auto &emote : *emotes)
{ {
channel.addMessage(makeTitleMessage(title)); if (emote.first.string.contains(text, Qt::CaseInsensitive))
channel.addMessage(makeEmoteMessage(map, emoteFlag)); {
}; filteredMap.insert(emote);
}
}
return filteredMap;
}
} // namespace } // namespace
namespace chatterino {
EmotePopup::EmotePopup(QWidget *parent) EmotePopup::EmotePopup(QWidget *parent)
: BasePopup(BaseWindow::EnableCustomFrame, parent) : BasePopup(BaseWindow::EnableCustomFrame, parent)
, search_(new QLineEdit())
, notebook_(new Notebook(this))
{ {
this->setStayInScreenRect(true); this->setStayInScreenRect(true);
this->moveTo(this, getApp()->windows->emotePopupPos(), false); this->moveTo(this, getApp()->windows->emotePopupPos(), false);
auto layout = new QVBoxLayout(this); auto *layout = new QVBoxLayout(this);
this->getLayoutContainer()->setLayout(layout); this->getLayoutContainer()->setLayout(layout);
QRegularExpression searchRegex("\\S*"); QRegularExpression searchRegex("\\S*");
@ -170,11 +214,10 @@ EmotePopup::EmotePopup(QWidget *parent)
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0); layout->setSpacing(0);
QHBoxLayout *layout2 = new QHBoxLayout(this); auto *layout2 = new QHBoxLayout(this);
layout2->setContentsMargins(8, 8, 8, 8); layout2->setContentsMargins(8, 8, 8, 8);
layout2->setSpacing(8); layout2->setSpacing(8);
this->search_ = new QLineEdit();
this->search_->setPlaceholderText("Search all emotes..."); this->search_->setPlaceholderText("Search all emotes...");
this->search_->setValidator(new TrimRegExpValidator(searchRegex)); this->search_->setValidator(new TrimRegExpValidator(searchRegex));
this->search_->setClearButtonEnabled(true); this->search_->setClearButtonEnabled(true);
@ -192,7 +235,7 @@ EmotePopup::EmotePopup(QWidget *parent)
}; };
auto makeView = [&](QString tabTitle, bool addToNotebook = true) { auto makeView = [&](QString tabTitle, bool addToNotebook = true) {
auto view = new ChannelView(); auto *view = new ChannelView();
view->setOverrideFlags(MessageElementFlags{ view->setOverrideFlags(MessageElementFlags{
MessageElementFlag::Default, MessageElementFlag::AlwaysShow, MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
@ -202,7 +245,7 @@ EmotePopup::EmotePopup(QWidget *parent)
if (addToNotebook) if (addToNotebook)
{ {
this->notebook_->addPage(view, tabTitle); this->notebook_->addPage(view, std::move(tabTitle));
} }
return view; return view;
@ -212,7 +255,6 @@ EmotePopup::EmotePopup(QWidget *parent)
this->searchView_->hide(); this->searchView_->hide();
layout->addWidget(this->searchView_); layout->addWidget(this->searchView_);
this->notebook_ = new Notebook(this);
layout->addWidget(this->notebook_); layout->addWidget(this->notebook_);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
@ -221,7 +263,7 @@ EmotePopup::EmotePopup(QWidget *parent)
this->globalEmotesView_ = makeView("Global"); this->globalEmotesView_ = makeView("Global");
this->viewEmojis_ = makeView("Emojis"); this->viewEmojis_ = makeView("Emojis");
this->loadEmojis(*this->viewEmojis_, getApp()->emotes->emojis.emojis); loadEmojis(*this->viewEmojis_, getApp()->emotes->emojis.emojis);
this->addShortcuts(); this->addShortcuts();
this->signalHolder_.managedConnect(getApp()->hotkeys->onItemsUpdated, this->signalHolder_.managedConnect(getApp()->hotkeys->onItemsUpdated,
[this]() { [this]() {
@ -237,7 +279,7 @@ void EmotePopup::addShortcuts()
HotkeyController::HotkeyMap actions{ HotkeyController::HotkeyMap actions{
{"openTab", // CTRL + 1-8 to open corresponding tab. {"openTab", // CTRL + 1-8 to open corresponding tab.
[this](std::vector<QString> arguments) -> QString { [this](std::vector<QString> arguments) -> QString {
if (arguments.size() == 0) if (arguments.empty())
{ {
qCWarning(chatterinoHotkeys) qCWarning(chatterinoHotkeys)
<< "openTab shortcut called without arguments. Takes " << "openTab shortcut called without arguments. Takes "
@ -260,7 +302,7 @@ void EmotePopup::addShortcuts()
} }
else else
{ {
bool ok; bool ok{false};
int result = target.toInt(&ok); int result = target.toInt(&ok);
if (ok) if (ok)
{ {
@ -279,20 +321,20 @@ void EmotePopup::addShortcuts()
return ""; return "";
}}, }},
{"delete", {"delete",
[this](std::vector<QString>) -> QString { [this](const std::vector<QString> &) -> QString {
this->close(); this->close();
return ""; return "";
}}, }},
{"scrollPage", {"scrollPage",
[this](std::vector<QString> arguments) -> QString { [this](std::vector<QString> arguments) -> QString {
if (arguments.size() == 0) if (arguments.empty())
{ {
qCWarning(chatterinoHotkeys) qCWarning(chatterinoHotkeys)
<< "scrollPage hotkey called without arguments!"; << "scrollPage hotkey called without arguments!";
return "scrollPage hotkey called without arguments!"; return "scrollPage hotkey called without arguments!";
} }
auto direction = arguments.at(0); auto direction = arguments.at(0);
auto channelView = dynamic_cast<ChannelView *>( auto *channelView = dynamic_cast<ChannelView *>(
this->notebook_->getSelectedPage()); this->notebook_->getSelectedPage());
auto &scrollbar = channelView->getScrollBar(); auto &scrollbar = channelView->getScrollBar();
@ -314,7 +356,7 @@ void EmotePopup::addShortcuts()
{"reject", nullptr}, {"reject", nullptr},
{"accept", nullptr}, {"accept", nullptr},
{"search", {"search",
[this](std::vector<QString>) -> QString { [this](const std::vector<QString> &) -> QString {
this->search_->setFocus(); this->search_->setFocus();
this->search_->selectAll(); this->search_->selectAll();
return ""; return "";
@ -329,7 +371,7 @@ void EmotePopup::loadChannel(ChannelPtr channel)
{ {
BenchmarkGuard guard("loadChannel"); BenchmarkGuard guard("loadChannel");
this->channel_ = channel; this->channel_ = std::move(channel);
this->twitchChannel_ = dynamic_cast<TwitchChannel *>(this->channel_.get()); this->twitchChannel_ = dynamic_cast<TwitchChannel *>(this->channel_.get());
this->setWindowTitle("Emotes in #" + this->channel_->getName()); this->setWindowTitle("Emotes in #" + this->channel_->getName());
@ -344,7 +386,7 @@ void EmotePopup::loadChannel(ChannelPtr channel)
auto channelChannel = std::make_shared<Channel>("", Channel::Type::None); auto channelChannel = std::make_shared<Channel>("", Channel::Type::None);
// twitch // twitch
addEmoteSets( addTwitchEmoteSets(
getApp()->accounts->twitch.getCurrent()->accessEmotes()->emoteSets, getApp()->accounts->twitch.getCurrent()->accessEmotes()->emoteSets,
*globalChannel, *subChannel, this->channel_->getName()); *globalChannel, *subChannel, this->channel_->getName());
@ -399,21 +441,6 @@ void EmotePopup::loadChannel(ChannelPtr channel)
} }
} }
void EmotePopup::loadEmojis(ChannelView &view, EmojiMap &emojiMap)
{
ChannelPtr emojiChannel(new Channel("", Channel::Type::None));
emojiChannel->addMessage(makeEmojiMessage(emojiMap));
view.setChannel(emojiChannel);
}
void EmotePopup::loadEmojis(Channel &channel, EmojiMap &emojiMap,
const QString &title)
{
channel.addMessage(makeTitleMessage(title));
channel.addMessage(makeEmojiMessage(emojiMap));
}
void EmotePopup::filterTwitchEmotes(std::shared_ptr<Channel> searchChannel, void EmotePopup::filterTwitchEmotes(std::shared_ptr<Channel> searchChannel,
const QString &searchText) const QString &searchText)
{ {
@ -432,56 +459,66 @@ void EmotePopup::filterTwitchEmotes(std::shared_ptr<Channel> searchChannel,
}); });
setCopy->emotes.resize(std::distance(setCopy->emotes.begin(), setIt)); setCopy->emotes.resize(std::distance(setCopy->emotes.begin(), setIt));
if (setCopy->emotes.size() > 0) if (!setCopy->emotes.empty())
{
twitchGlobalEmotes.push_back(setCopy); twitchGlobalEmotes.push_back(setCopy);
}
} }
auto bttvGlobalEmotes = this->filterEmoteMap( auto bttvGlobalEmotes =
searchText, getApp()->twitch->getBttvEmotes().emotes()); filterEmoteMap(searchText, getApp()->twitch->getBttvEmotes().emotes());
auto ffzGlobalEmotes = this->filterEmoteMap( auto ffzGlobalEmotes =
searchText, getApp()->twitch->getFfzEmotes().emotes()); filterEmoteMap(searchText, getApp()->twitch->getFfzEmotes().emotes());
auto *seventvGlobalEmotes = this->filterEmoteMap( auto seventvGlobalEmotes = filterEmoteMap(
searchText, getApp()->twitch->getSeventvEmotes().globalEmotes()); searchText, getApp()->twitch->getSeventvEmotes().globalEmotes());
// twitch // twitch
addEmoteSets(twitchGlobalEmotes, *searchChannel, *searchChannel, addTwitchEmoteSets(twitchGlobalEmotes, *searchChannel, *searchChannel,
this->channel_->getName()); this->channel_->getName());
// global // global
if (bttvGlobalEmotes->size() > 0) if (!bttvGlobalEmotes.empty())
addEmotes(*searchChannel, *bttvGlobalEmotes, "BetterTTV (Global)",
MessageElementFlag::BttvEmote);
if (ffzGlobalEmotes->size() > 0)
addEmotes(*searchChannel, *ffzGlobalEmotes, "FrankerFaceZ (Global)",
MessageElementFlag::FfzEmote);
if (!seventvGlobalEmotes->empty())
{ {
addEmotes(*searchChannel, *seventvGlobalEmotes, "SevenTV (Global)", addEmotes(*searchChannel, bttvGlobalEmotes, "BetterTTV (Global)",
MessageElementFlag::BttvEmote);
}
if (!ffzGlobalEmotes.empty())
{
addEmotes(*searchChannel, ffzGlobalEmotes, "FrankerFaceZ (Global)",
MessageElementFlag::FfzEmote);
}
if (!seventvGlobalEmotes.empty())
{
addEmotes(*searchChannel, seventvGlobalEmotes, "SevenTV (Global)",
MessageElementFlag::SevenTVEmote); MessageElementFlag::SevenTVEmote);
} }
if (!this->twitchChannel_) if (this->twitchChannel_ == nullptr)
{ {
return; return;
} }
auto bttvChannelEmotes = auto bttvChannelEmotes =
this->filterEmoteMap(searchText, this->twitchChannel_->bttvEmotes()); filterEmoteMap(searchText, this->twitchChannel_->bttvEmotes());
auto ffzChannelEmotes = auto ffzChannelEmotes =
this->filterEmoteMap(searchText, this->twitchChannel_->ffzEmotes()); filterEmoteMap(searchText, this->twitchChannel_->ffzEmotes());
auto *seventvChannelEmotes = auto seventvChannelEmotes =
this->filterEmoteMap(searchText, this->twitchChannel_->seventvEmotes()); filterEmoteMap(searchText, this->twitchChannel_->seventvEmotes());
// channel // channel
if (bttvChannelEmotes->size() > 0) if (!bttvChannelEmotes.empty())
addEmotes(*searchChannel, *bttvChannelEmotes, "BetterTTV (Channel)",
MessageElementFlag::BttvEmote);
if (ffzChannelEmotes->size() > 0)
addEmotes(*searchChannel, *ffzChannelEmotes, "FrankerFaceZ (Channel)",
MessageElementFlag::FfzEmote);
if (!seventvChannelEmotes->empty())
{ {
addEmotes(*searchChannel, *seventvChannelEmotes, "SevenTV (Channel)", addEmotes(*searchChannel, bttvChannelEmotes, "BetterTTV (Channel)",
MessageElementFlag::BttvEmote);
}
if (!ffzChannelEmotes.empty())
{
addEmotes(*searchChannel, ffzChannelEmotes, "FrankerFaceZ (Channel)",
MessageElementFlag::FfzEmote);
}
if (!seventvChannelEmotes.empty())
{
addEmotes(*searchChannel, seventvChannelEmotes, "SevenTV (Channel)",
MessageElementFlag::SevenTVEmote); MessageElementFlag::SevenTVEmote);
} }
} }
@ -516,7 +553,9 @@ void EmotePopup::filterEmotes(const QString &searchText)
}); });
// emojis // emojis
if (emojiCount > 0) if (emojiCount > 0)
this->loadEmojis(*searchChannel, filteredEmojis, "Emojis"); {
loadEmojis(*searchChannel, filteredEmojis, "Emojis");
}
this->searchView_->setChannel(searchChannel); this->searchView_->setChannel(searchChannel);
@ -524,25 +563,10 @@ void EmotePopup::filterEmotes(const QString &searchText)
this->searchView_->show(); this->searchView_->show();
} }
EmoteMap *EmotePopup::filterEmoteMap(const QString &text,
std::shared_ptr<const EmoteMap> emotes)
{
auto filteredMap = new EmoteMap();
for (const auto &emote : *emotes)
{
if (emote.first.string.contains(text, Qt::CaseInsensitive))
{
filteredMap->insert(emote);
}
}
return filteredMap;
}
void EmotePopup::closeEvent(QCloseEvent *event) void EmotePopup::closeEvent(QCloseEvent *event)
{ {
getApp()->windows->setEmotePopupPos(this->pos()); getApp()->windows->setEmotePopupPos(this->pos());
QWidget::closeEvent(event); BaseWindow::closeEvent(event);
} }
} // namespace chatterino } // namespace chatterino

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "providers/emoji/Emojis.hpp"
#include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchChannel.hpp"
#include "widgets/BasePopup.hpp" #include "widgets/BasePopup.hpp"
#include "widgets/Notebook.hpp" #include "widgets/Notebook.hpp"
@ -22,7 +21,7 @@ public:
void loadChannel(ChannelPtr channel); void loadChannel(ChannelPtr channel);
virtual void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
pajlada::Signals::Signal<Link> linkClicked; pajlada::Signals::Signal<Link> linkClicked;
@ -43,13 +42,9 @@ private:
QLineEdit *search_; QLineEdit *search_;
Notebook *notebook_; Notebook *notebook_;
void loadEmojis(ChannelView &view, EmojiMap &emojiMap);
void loadEmojis(Channel &channel, EmojiMap &emojiMap, const QString &title);
void filterTwitchEmotes(std::shared_ptr<Channel> searchChannel, void filterTwitchEmotes(std::shared_ptr<Channel> searchChannel,
const QString &searchText); const QString &searchText);
void filterEmotes(const QString &text); void filterEmotes(const QString &text);
EmoteMap *filterEmoteMap(const QString &text,
std::shared_ptr<const EmoteMap> emotes);
void addShortcuts() override; void addShortcuts() override;
}; };