Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
- Dev: Compile time definitions for `Windows.h` are now conditional based on `WIN32` instead of `MSVC`. (#6534)
- Dev: Refactored split container nodes to use shared pointers. (#6435)
- Dev: Mock headers are now added as a header set if supported by CMake. (#6561)
- Dev: Refactored emotes. (#6570)
- Dev: Set settings directory to temporary one used in tests. (#6584)
- Dev: Check Lua unwinding and version in tests. (#6586)
- Dev: Added method to get the last N messages of a channel. (#6602, #6604)
Expand Down
1 change: 1 addition & 0 deletions mocks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
include/mocks/ChatterinoBadges.hpp
include/mocks/DisabledStreamerMode.hpp
include/mocks/EmoteController.hpp
include/mocks/EmoteProvider.hpp
include/mocks/EmptyApplication.hpp
include/mocks/Helix.hpp
include/mocks/LinkResolver.hpp
Expand Down
6 changes: 6 additions & 0 deletions mocks/include/mocks/EmoteController.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class EmoteController : public chatterino::EmoteController
this->getEmojis()->load();
}

void addProvider(EmoteProviderPtr provider)
{
this->providers_.emplace_back(std::move(provider));
this->sort();
}

void initialize() override
{
}
Expand Down
85 changes: 85 additions & 0 deletions mocks/include/mocks/EmoteProvider.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#include "common/Channel.hpp"
#include "controllers/emotes/EmoteProvider.hpp"

#include <QStringBuilder>

namespace chatterino::mock {

class EmoteProvider : public chatterino::EmoteProvider
{
public:
EmoteProvider(QString name, QString id, uint32_t priority)
: chatterino::EmoteProvider(std::move(name), std::move(id), priority)
{
}

void setGlobalEmotes(EmoteMapPtr map)
{
this->globalEmotes_ = std::move(map);
}

void setChannel(const QString &name, EmoteMapPtr map)
{
this->channels[name] = std::move(map);
}

void setChannelFallback(EmoteMapPtr map)
{
this->channelFallback = std::move(map);
}

void initialize() override
{
}

void reloadGlobalEmotes(
std::function<void(ExpectedStr<void>)> onDone) override
{
onDone({});
}

void loadChannelEmotes(
const std::shared_ptr<Channel> &channel,
std::function<void(ExpectedStr<EmoteLoadResult>)> onDone,
LoadChannelArgs /* args */) override
{
auto it = channels.find(channel->getName());
if (it == this->channels.end())
{
if (this->channelFallback)
{
onDone(EmoteLoadResult{.emotes = this->channelFallback});
}
else
{
onDone(makeUnexpected("No emotes for this channel"));
}
}
else
{
onDone(EmoteLoadResult{.emotes = it->second});
}
}

bool supportsChannel(Channel * /*channel*/) override
{
return true;
}

bool hasChannelEmotes() const override
{
return true;
}

bool hasGlobalEmotes() const override
{
return true;
}

std::unordered_map<QString, EmoteMapPtr> channels;
EmoteMapPtr channelFallback;
};

} // namespace chatterino::mock
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ set(SOURCE_FILES

controllers/emotes/EmoteController.cpp
controllers/emotes/EmoteController.hpp
controllers/emotes/EmoteHolder.cpp
controllers/emotes/EmoteHolder.hpp
controllers/emotes/EmoteProvider.cpp
controllers/emotes/EmoteProvider.hpp

controllers/filters/FilterModel.cpp
controllers/filters/FilterModel.hpp
Expand Down
11 changes: 11 additions & 0 deletions src/common/Channel.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "common/Channel.hpp"

#include "Application.hpp"
#include "controllers/emotes/EmoteHolder.hpp"
#include "messages/Message.hpp"
#include "messages/MessageBuilder.hpp"
#include "messages/MessageSimilarity.hpp"
Expand Down Expand Up @@ -435,6 +436,16 @@ void Channel::messageRemovedFromStart(const MessagePtr &msg)
{
}

EmoteHolder *Channel::emotes()
{
return this->emotes_.get();
}

const EmoteHolder *Channel::emotes() const
{
return this->emotes_.get();
}

//
// Indirect channel
//
Expand Down
7 changes: 7 additions & 0 deletions src/common/Channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ namespace chatterino {
struct Message;
using MessagePtr = std::shared_ptr<const Message>;

class EmoteHolder;

class Channel : public std::enable_shared_from_this<Channel>, public MessageSink
{
public:
Expand Down Expand Up @@ -122,6 +124,9 @@ class Channel : public std::enable_shared_from_this<Channel>, public MessageSink

MessageSinkTraits sinkTraits() const final;

EmoteHolder *emotes();
const EmoteHolder *emotes() const;

// CHANNEL INFO
virtual bool canSendMessage() const;
virtual bool isWritable() const; // whether split input will be usable
Expand All @@ -147,6 +152,8 @@ class Channel : public std::enable_shared_from_this<Channel>, public MessageSink
virtual void messageRemovedFromStart(const MessagePtr &msg);
QString platform_;

std::unique_ptr<EmoteHolder> emotes_;

private:
const QString name_;
LimitedQueue<MessagePtr> messages_;
Expand Down
1 change: 1 addition & 0 deletions src/common/QLogging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Q_LOGGING_CATEGORY(chatterinoCompletion, "chatterino.completion", logThreshold);
Q_LOGGING_CATEGORY(chatterinoCrashhandler, "chatterino.crashhandler",
logThreshold);
Q_LOGGING_CATEGORY(chatterinoEmoji, "chatterino.emoji", logThreshold);
Q_LOGGING_CATEGORY(chatterinoEmotes, "chatterino.emotes", logThreshold);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random thought unrelated to your change here: It would be nice if emote providers would have their own logging category, and if that didn't require us to define something here

Q_LOGGING_CATEGORY(chatterinoEnv, "chatterino.env", logThreshold);
Q_LOGGING_CATEGORY(chatterinoFfzemotes, "chatterino.ffzemotes", logThreshold);
Q_LOGGING_CATEGORY(chatterinoHelper, "chatterino.helper", logThreshold);
Expand Down
1 change: 1 addition & 0 deletions src/common/QLogging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoCommon);
Q_DECLARE_LOGGING_CATEGORY(chatterinoCompletion);
Q_DECLARE_LOGGING_CATEGORY(chatterinoCrashhandler);
Q_DECLARE_LOGGING_CATEGORY(chatterinoEmoji);
Q_DECLARE_LOGGING_CATEGORY(chatterinoEmotes);
Q_DECLARE_LOGGING_CATEGORY(chatterinoEnv);
Q_DECLARE_LOGGING_CATEGORY(chatterinoFfzemotes);
Q_DECLARE_LOGGING_CATEGORY(chatterinoHelper);
Expand Down
11 changes: 10 additions & 1 deletion src/controllers/commands/builtin/twitch/SendWhisper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ bool appendWhisperMessageWordsLocally(const QStringList &words)
const auto &accemotes = *acc->accessEmotes();
const auto *bttvemotes = app->getBttvEmotes();
const auto *ffzemotes = app->getFfzEmotes();
const auto *emoteController = app->getEmotes();
auto emote = std::optional<EmotePtr>{};
for (int i = 2; i < words.length(); i++)
{
Expand All @@ -134,8 +135,16 @@ bool appendWhisperMessageWordsLocally(const QStringList &words)
continue;
}
} // bttv/ffz emote
{ // third party emotes
emote = emoteController->resolveGlobal(EmoteName{words[i]});
if (emote)
{
b.emplace<EmoteElement>(*emote, MessageElementFlag::Emote);
continue;
}
} // third party emotes
{ // emoji/text
for (auto &variant : app->getEmotes()->getEmojis()->parse(words[i]))
for (auto &variant : emoteController->getEmojis()->parse(words[i]))
{
constexpr const static struct {
void operator()(EmotePtr emote, MessageBuilder &b) const
Expand Down
24 changes: 24 additions & 0 deletions src/controllers/completion/sources/EmoteSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "controllers/accounts/AccountController.hpp"
#include "controllers/completion/sources/Helpers.hpp"
#include "controllers/emotes/EmoteController.hpp"
#include "controllers/emotes/EmoteHolder.hpp"
#include "controllers/emotes/EmoteProvider.hpp"
#include "providers/bttv/BttvEmotes.hpp"
#include "providers/emoji/Emojis.hpp"
#include "providers/ffz/FfzEmotes.hpp"
Expand All @@ -13,6 +15,8 @@
#include "providers/twitch/TwitchIrcServer.hpp"
#include "widgets/splits/InputCompletionItem.hpp"

#include <QStringBuilder>

namespace chatterino::completion {

namespace {
Expand Down Expand Up @@ -105,6 +109,20 @@ void EmoteSource::initializeFromChannel(const Channel *channel)
auto user = getApp()->getAccounts()->twitch.getCurrent();
addEmotes(emotes, **user->accessEmotes(), "Twitch Emote");

if (const auto *holder = tc->emotes())
{
for (const auto &data : holder->providerData())
{
auto provider = data.provider.lock();
if (!provider)
{
continue;
}
addEmotes(emotes, *data.emotes,
u"Channel " % provider->name());
}
}

// TODO extract "Channel {BetterTTV,7TV,FrankerFaceZ}" text into a #define.
if (auto bttv = tc->bttvEmotes())
{
Expand All @@ -120,6 +138,12 @@ void EmoteSource::initializeFromChannel(const Channel *channel)
}
}

for (const auto &provider : app->getEmotes()->getProviders())
{
addEmotes(emotes, *provider->globalEmotes(),
u"Global " % provider->name());
}

if (auto bttvG = app->getBttvEmotes()->emotes())
{
addEmotes(emotes, *bttvG, "Global BetterTTV");
Expand Down
57 changes: 57 additions & 0 deletions src/controllers/emotes/EmoteController.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "controllers/emotes/EmoteController.hpp"

#include "controllers/emotes/EmoteProvider.hpp"
#include "providers/emoji/Emojis.hpp"
#include "providers/twitch/TwitchEmotes.hpp"
#include "singletons/helper/GifTimer.hpp"
Expand All @@ -18,6 +19,55 @@ void EmoteController::initialize()
{
this->emojis_->load();
this->gifTimer_->initialize();

this->sort();

for (const auto &provider : this->providers_)
{
provider->initialize();
}
}

EmoteProviderPtr EmoteController::findProviderByName(QStringView name) const
{
auto it = std::ranges::find_if(this->providers_, [&](const auto &provider) {
return provider->name() == name;
});
if (it == this->providers_.end())
{
return nullptr;
}
return *it;
}

EmoteProviderPtr EmoteController::findProviderByID(QStringView id) const
{
auto it = std::ranges::find_if(this->providers_, [&](const auto &provider) {
return provider->id() == id;
});
if (it == this->providers_.end())
{
return nullptr;
}
return *it;
}

EmotePtr EmoteController::resolveGlobal(const EmoteName &query) const
{
for (const auto &provider : this->providers_)
{
auto emote = provider->globalEmote(query);
if (emote)
{
return emote;
}
}
return nullptr;
}

std::span<const EmoteProviderPtr> EmoteController::getProviders() const
{
return this->providers_;
}

TwitchEmotes *EmoteController::getTwitchEmotes() const
Expand All @@ -35,4 +85,11 @@ GIFTimer *EmoteController::getGIFTimer() const
return this->gifTimer_.get();
}

void EmoteController::sort()
{
std::ranges::sort(this->providers_, {}, [](const auto &provider) {
return provider->priority();
});
}

} // namespace chatterino
21 changes: 21 additions & 0 deletions src/controllers/emotes/EmoteController.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
#pragma once

#include "messages/Emote.hpp"

#include <pajlada/signals/signal.hpp>

#include <memory>
#include <span>
#include <vector>

namespace chatterino {

class EmoteProvider;
using EmoteProviderPtr = std::shared_ptr<EmoteProvider>;

class TwitchEmotes;
class Emojis;
class GIFTimer;
Expand All @@ -16,12 +25,24 @@ class EmoteController

virtual void initialize();

EmoteProviderPtr findProviderByName(QStringView name) const;
EmoteProviderPtr findProviderByID(QStringView id) const;

EmotePtr resolveGlobal(const EmoteName &query) const;

std::span<const EmoteProviderPtr> getProviders() const;

TwitchEmotes *getTwitchEmotes() const;

Emojis *getEmojis() const;

GIFTimer *getGIFTimer() const;

protected:
void sort();

std::vector<EmoteProviderPtr> providers_;

private:
std::unique_ptr<TwitchEmotes> twitchEmotes_;
std::unique_ptr<Emojis> emojis_;
Expand Down
Loading
Loading