2020-08-15 18:59:17 +02:00
|
|
|
#include "EmoteInputPopup.hpp"
|
|
|
|
|
|
|
|
#include "Application.hpp"
|
2020-08-15 21:14:07 +02:00
|
|
|
#include "controllers/accounts/AccountController.hpp"
|
2020-08-15 18:59:17 +02:00
|
|
|
#include "messages/Emote.hpp"
|
|
|
|
#include "providers/bttv/BttvEmotes.hpp"
|
|
|
|
#include "providers/ffz/FfzEmotes.hpp"
|
|
|
|
#include "providers/twitch/TwitchChannel.hpp"
|
2020-08-15 21:14:07 +02:00
|
|
|
#include "providers/twitch/TwitchIrcServer.hpp"
|
2020-08-15 18:59:17 +02:00
|
|
|
#include "singletons/Emotes.hpp"
|
|
|
|
#include "util/LayoutCreator.hpp"
|
|
|
|
#include "widgets/listview/GenericListView.hpp"
|
|
|
|
#include "widgets/splits/EmoteInputItem.hpp"
|
|
|
|
|
|
|
|
namespace chatterino {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct _Emote {
|
|
|
|
EmotePtr emote;
|
2020-08-22 23:17:56 +02:00
|
|
|
QString displayName;
|
2020-08-15 18:59:17 +02:00
|
|
|
QString providerName;
|
|
|
|
};
|
|
|
|
|
|
|
|
void addEmotes(std::vector<_Emote> &out, const EmoteMap &map,
|
|
|
|
const QString &text, const QString &providerName)
|
|
|
|
{
|
|
|
|
for (auto &&emote : map)
|
|
|
|
if (emote.first.string.contains(text, Qt::CaseInsensitive))
|
2020-08-22 23:17:56 +02:00
|
|
|
out.push_back(
|
|
|
|
{emote.second, emote.second->name.string, providerName});
|
2020-08-15 18:59:17 +02:00
|
|
|
}
|
2020-08-15 20:22:12 +02:00
|
|
|
|
|
|
|
void addEmojis(std::vector<_Emote> &out, const EmojiMap &map,
|
|
|
|
const QString &text)
|
|
|
|
{
|
|
|
|
map.each([&](const QString &, const std::shared_ptr<EmojiData> &emoji) {
|
|
|
|
for (auto &&shortCode : emoji->shortCodes)
|
|
|
|
if (shortCode.contains(text, Qt::CaseInsensitive))
|
2020-08-22 23:17:56 +02:00
|
|
|
out.push_back({emoji->emote, shortCode, "Emoji"});
|
2020-08-15 20:22:12 +02:00
|
|
|
});
|
|
|
|
}
|
2020-08-15 18:59:17 +02:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
EmoteInputPopup::EmoteInputPopup(QWidget *parent)
|
|
|
|
: BasePopup({BasePopup::EnableCustomFrame, BasePopup::Frameless,
|
|
|
|
BasePopup::DontFocus},
|
|
|
|
parent)
|
|
|
|
, model_(this)
|
|
|
|
{
|
|
|
|
this->initLayout();
|
|
|
|
|
2020-08-15 21:34:57 +02:00
|
|
|
QObject::connect(&this->redrawTimer_, &QTimer::timeout, this, [this] {
|
|
|
|
if (this->isVisible())
|
|
|
|
this->ui_.listView->doItemsLayout();
|
|
|
|
});
|
|
|
|
this->redrawTimer_.setInterval(33);
|
2020-08-15 18:59:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void EmoteInputPopup::initLayout()
|
|
|
|
{
|
|
|
|
LayoutCreator creator = {this};
|
|
|
|
|
|
|
|
auto listView =
|
|
|
|
creator.emplace<GenericListView>().assign(&this->ui_.listView);
|
2020-08-23 11:28:22 +02:00
|
|
|
listView->setInvokeActionOnTab(true);
|
2020-08-15 18:59:17 +02:00
|
|
|
|
|
|
|
listView->setModel(&this->model_);
|
|
|
|
QObject::connect(listView.getElement(), &GenericListView::closeRequested,
|
|
|
|
this, [this] { this->close(); });
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmoteInputPopup::updateEmotes(const QString &text, ChannelPtr channel)
|
|
|
|
{
|
|
|
|
std::vector<_Emote> emotes;
|
2020-10-17 15:59:15 +02:00
|
|
|
auto tc = dynamic_cast<TwitchChannel *>(channel.get());
|
|
|
|
auto wc = channel.get()->getType() == Channel::Type::TwitchWhispers;
|
|
|
|
if (tc || wc)
|
2020-08-15 18:59:17 +02:00
|
|
|
{
|
2020-08-15 21:14:07 +02:00
|
|
|
if (auto user = getApp()->accounts->twitch.getCurrent())
|
|
|
|
{
|
|
|
|
auto twitch = user->accessEmotes();
|
|
|
|
addEmotes(emotes, twitch->emotes, text, "Twitch Emote");
|
|
|
|
}
|
|
|
|
|
2020-10-17 15:59:15 +02:00
|
|
|
if (tc)
|
|
|
|
{
|
|
|
|
// TODO extract "Channel BetterTTV" text into a #define.
|
|
|
|
if (auto bttv = tc->bttvEmotes())
|
|
|
|
addEmotes(emotes, *bttv, text, "Channel BetterTTV");
|
|
|
|
if (auto ffz = tc->ffzEmotes())
|
|
|
|
addEmotes(emotes, *ffz, text, "Channel FrankerFaceZ");
|
|
|
|
|
|
|
|
if (auto bttvG = tc->globalBttv().emotes())
|
|
|
|
addEmotes(emotes, *bttvG, text, "Global BetterTTV");
|
|
|
|
if (auto ffzG = tc->globalFfz().emotes())
|
|
|
|
addEmotes(emotes, *ffzG, text, "Global FrankerFaceZ");
|
|
|
|
}
|
2020-08-15 20:22:12 +02:00
|
|
|
|
|
|
|
addEmojis(emotes, getApp()->emotes->emojis.emojis, text);
|
2020-08-15 18:59:17 +02:00
|
|
|
}
|
|
|
|
|
2020-08-22 23:17:56 +02:00
|
|
|
// if there is an exact match, put that emote first
|
2020-08-22 23:22:00 +02:00
|
|
|
for (size_t i = 1; i < emotes.size(); i++)
|
2020-08-22 23:17:56 +02:00
|
|
|
{
|
|
|
|
auto emoteText = emotes.at(i).displayName;
|
|
|
|
|
|
|
|
// test for match or match with colon at start for emotes like ":)"
|
|
|
|
if (emoteText.compare(text, Qt::CaseInsensitive) == 0 ||
|
|
|
|
emoteText.compare(":" + text, Qt::CaseInsensitive) == 0)
|
|
|
|
{
|
2020-08-22 23:22:00 +02:00
|
|
|
auto emote = emotes[i];
|
|
|
|
emotes.erase(emotes.begin() + int(i));
|
|
|
|
emotes.insert(emotes.begin(), emote);
|
2020-08-22 23:17:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-15 18:59:17 +02:00
|
|
|
this->model_.clear();
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
for (auto &&emote : emotes)
|
|
|
|
{
|
|
|
|
this->model_.addItem(std::make_unique<EmoteInputItem>(
|
2020-08-22 23:17:56 +02:00
|
|
|
emote.emote, emote.displayName + " - " + emote.providerName,
|
2020-08-15 18:59:17 +02:00
|
|
|
this->callback_));
|
|
|
|
|
2020-08-15 21:20:23 +02:00
|
|
|
if (count++ == maxEmoteCount)
|
2020-08-15 18:59:17 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!emotes.empty())
|
|
|
|
{
|
|
|
|
this->ui_.listView->setCurrentIndex(this->model_.index(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EmoteInputPopup::eventFilter(QObject *watched, QEvent *event)
|
|
|
|
{
|
|
|
|
return this->ui_.listView->eventFilter(watched, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmoteInputPopup::setInputAction(ActionCallback callback)
|
|
|
|
{
|
|
|
|
this->callback_ = std::move(callback);
|
|
|
|
}
|
|
|
|
|
2020-08-15 21:34:57 +02:00
|
|
|
void EmoteInputPopup::showEvent(QShowEvent *)
|
|
|
|
{
|
|
|
|
this->redrawTimer_.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EmoteInputPopup::hideEvent(QHideEvent *)
|
|
|
|
{
|
|
|
|
this->redrawTimer_.stop();
|
|
|
|
}
|
|
|
|
|
2020-08-15 18:59:17 +02:00
|
|
|
} // namespace chatterino
|