mirror-chatterino2/src/widgets/splits/EmoteInputPopup.cpp
fourtf 50da694fff
Stable (#1905)
* fixed SearchWindow memory leak

* Update CHANGELOG.md

* added DebugCount for BaseWindow

* [Bug Fix] Color of second user highlight cannot be set (#1898)

* Highlighting: Fix bug preventing user highlight from being set

Before this commit, only the row of a clicked cell was checked, but not
the tab it was clicked in.

Since the "Whispers" row is the second row in the "Messages" tab on the
highlighting page, the color picker was not opened for the second entry
in the "Users" tab either. This commit fixes the bug by also checking
tab the cell was clicked in.

* Update CHANGELOG.md

* Emote Popup Improvements (#1895)

* Put exact matching emotes first

* Close GenericListView on Escape press

* smol fix

* fixed emote input when not in the first char

* fixes #1902

* closes #1904

Co-authored-by: Leon Richardt <leon.richardt@gmail.com>
Co-authored-by: Daniel <24928223+dnsge@users.noreply.github.com>
2020-08-23 11:28:22 +02:00

154 lines
4.5 KiB
C++

#include "EmoteInputPopup.hpp"
#include "Application.hpp"
#include "controllers/accounts/AccountController.hpp"
#include "messages/Emote.hpp"
#include "providers/bttv/BttvEmotes.hpp"
#include "providers/ffz/FfzEmotes.hpp"
#include "providers/twitch/TwitchChannel.hpp"
#include "providers/twitch/TwitchIrcServer.hpp"
#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;
QString displayName;
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))
out.push_back(
{emote.second, emote.second->name.string, providerName});
}
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))
out.push_back({emoji->emote, shortCode, "Emoji"});
});
}
} // namespace
EmoteInputPopup::EmoteInputPopup(QWidget *parent)
: BasePopup({BasePopup::EnableCustomFrame, BasePopup::Frameless,
BasePopup::DontFocus},
parent)
, model_(this)
{
this->initLayout();
QObject::connect(&this->redrawTimer_, &QTimer::timeout, this, [this] {
if (this->isVisible())
this->ui_.listView->doItemsLayout();
});
this->redrawTimer_.setInterval(33);
}
void EmoteInputPopup::initLayout()
{
LayoutCreator creator = {this};
auto listView =
creator.emplace<GenericListView>().assign(&this->ui_.listView);
listView->setInvokeActionOnTab(true);
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;
if (auto tc = dynamic_cast<TwitchChannel *>(channel.get()))
{
if (auto user = getApp()->accounts->twitch.getCurrent())
{
auto twitch = user->accessEmotes();
addEmotes(emotes, twitch->emotes, text, "Twitch Emote");
}
// 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");
addEmojis(emotes, getApp()->emotes->emojis.emojis, text);
}
// if there is an exact match, put that emote first
for (size_t i = 1; i < emotes.size(); i++)
{
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)
{
auto emote = emotes[i];
emotes.erase(emotes.begin() + int(i));
emotes.insert(emotes.begin(), emote);
break;
}
}
this->model_.clear();
int count = 0;
for (auto &&emote : emotes)
{
this->model_.addItem(std::make_unique<EmoteInputItem>(
emote.emote, emote.displayName + " - " + emote.providerName,
this->callback_));
if (count++ == maxEmoteCount)
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);
}
void EmoteInputPopup::showEvent(QShowEvent *)
{
this->redrawTimer_.start();
}
void EmoteInputPopup::hideEvent(QHideEvent *)
{
this->redrawTimer_.stop();
}
} // namespace chatterino