Show visual feedback when BTTV and FFZ emotes are loaded (#1671)

Upon joining a channel or pressing F5, BTTV and FFZ emotes are
(re)loaded. This change adds visual feedback of the network requests and
their outcome, in the form of a system message in the associated
channel's chat window. 

Non-error messages are suppressed when joining a
channel (which automatically loads emotes).
This commit is contained in:
thekalio 2020-05-16 06:43:44 -04:00 committed by GitHub
parent dd5455d1cf
commit 56d09ac198
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 26 deletions

View file

@ -8,6 +8,7 @@
#include "messages/Emote.hpp"
#include "messages/Image.hpp"
#include "messages/ImageSet.hpp"
#include "messages/MessageBuilder.hpp"
#include "providers/twitch/TwitchChannel.hpp"
namespace chatterino {
@ -138,17 +139,51 @@ void BttvEmotes::loadEmotes()
.execute();
}
void BttvEmotes::loadChannel(const QString &channelId,
std::function<void(EmoteMap &&)> callback)
void BttvEmotes::loadChannel(std::weak_ptr<Channel> channel,
const QString &channelId,
std::function<void(EmoteMap &&)> callback,
bool manualRefresh)
{
NetworkRequest(QString(bttvChannelEmoteApiUrl) + channelId)
.timeout(3000)
.onSuccess([callback = std::move(callback)](auto result) -> Outcome {
.onSuccess([callback = std::move(callback), channel,
manualRefresh](auto result) -> Outcome {
auto pair = parseChannelEmotes(result.parseJson());
if (pair.first)
callback(std::move(pair.second));
if (auto shared = channel.lock(); manualRefresh)
shared->addMessage(
makeSystemMessage("BetterTTV channel emotes reloaded."));
return pair.first;
})
.onError([channelId, channel, manualRefresh](auto result) {
auto shared = channel.lock();
if (!shared)
return;
if (result.status() == 203)
{
// User does not have any BTTV emotes
if (manualRefresh)
shared->addMessage(makeSystemMessage(
"This channel has no BetterTTV channel emotes."));
}
else if (result.status() == NetworkResult::timedoutStatus)
{
// TODO: Auto retry in case of a timeout, with a delay
qDebug() << "Fetching BTTV emotes for channel" << channelId
<< "failed due to timeout";
shared->addMessage(makeSystemMessage(
"Failed to fetch BetterTTV channel emotes. (timed out)"));
}
else
{
qDebug() << "Error fetching BTTV emotes for channel"
<< channelId << ", error" << result.status();
shared->addMessage(
makeSystemMessage("Failed to fetch BetterTTV channel "
"emotes. (unknown error)"));
}
})
.execute();
}

View file

@ -4,6 +4,7 @@
#include "boost/optional.hpp"
#include "common/Aliases.hpp"
#include "common/Atomic.hpp"
#include "providers/twitch/TwitchChannel.hpp"
namespace chatterino {
@ -24,8 +25,10 @@ public:
std::shared_ptr<const EmoteMap> emotes() const;
boost::optional<EmotePtr> emote(const EmoteName &name) const;
void loadEmotes();
static void loadChannel(const QString &channelId,
std::function<void(EmoteMap &&)> callback);
static void loadChannel(std::weak_ptr<Channel> channel,
const QString &channelId,
std::function<void(EmoteMap &&)> callback,
bool manualRefresh);
private:
Atomic<std::shared_ptr<const EmoteMap>> global_;

View file

@ -6,6 +6,8 @@
#include "common/Outcome.hpp"
#include "messages/Emote.hpp"
#include "messages/Image.hpp"
#include "messages/MessageBuilder.hpp"
#include "providers/twitch/TwitchChannel.hpp"
namespace chatterino {
namespace {
@ -182,8 +184,10 @@ void FfzEmotes::loadEmotes()
}
void FfzEmotes::loadChannel(
const QString &channelId, std::function<void(EmoteMap &&)> emoteCallback,
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback)
std::weak_ptr<Channel> channel, const QString &channelId,
std::function<void(EmoteMap &&)> emoteCallback,
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback,
bool manualRefresh)
{
qDebug() << "[FFZEmotes] Reload FFZ Channel Emotes for channel"
<< channelId;
@ -192,32 +196,47 @@ void FfzEmotes::loadChannel(
.timeout(20000)
.onSuccess([emoteCallback = std::move(emoteCallback),
modBadgeCallback =
std::move(modBadgeCallback)](auto result) -> Outcome {
modBadgeCallback = std::move(modBadgeCallback), channel,
manualRefresh](auto result) -> Outcome {
auto json = result.parseJson();
auto emoteMap = parseChannelEmotes(json);
auto modBadge = parseModBadge(json);
emoteCallback(std::move(emoteMap));
modBadgeCallback(std::move(modBadge));
if (auto shared = channel.lock(); manualRefresh)
shared->addMessage(
makeSystemMessage("FrankerFaceZ channel emotes reloaded."));
return Success;
})
.onError([channelId](NetworkResult result) {
.onError([channelId, channel, manualRefresh](NetworkResult result) {
auto shared = channel.lock();
if (!shared)
return;
if (result.status() == 203)
{
// User does not have any FFZ emotes
if (manualRefresh)
shared->addMessage(makeSystemMessage(
"This channel has no FrankerFaceZ channel emotes."));
}
else if (result.status() == NetworkResult::timedoutStatus)
{
// TODO: Auto retry in case of a timeout, with a delay
qDebug() << "Fetching FFZ emotes for channel" << channelId
<< "failed due to timeout";
shared->addMessage(
makeSystemMessage("Failed to fetch FrankerFaceZ channel "
"emotes. (timed out)"));
}
else
{
qDebug() << "Error fetching FFZ emotes for channel" << channelId
<< ", error" << result.status();
shared->addMessage(
makeSystemMessage("Failed to fetch FrankerFaceZ channel "
"emotes. (unknown error)"));
}
})
.execute();

View file

@ -4,6 +4,7 @@
#include "boost/optional.hpp"
#include "common/Aliases.hpp"
#include "common/Atomic.hpp"
#include "providers/twitch/TwitchChannel.hpp"
namespace chatterino {
@ -23,9 +24,10 @@ public:
boost::optional<EmotePtr> emote(const EmoteName &name) const;
void loadEmotes();
static void loadChannel(
const QString &channelId,
std::weak_ptr<Channel> channel, const QString &channelId,
std::function<void(EmoteMap &&)> emoteCallback,
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback);
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback,
bool manualRefresh);
private:
Atomic<std::shared_ptr<const EmoteMap>> global_;

View file

@ -118,8 +118,8 @@ TwitchChannel::TwitchChannel(const QString &name,
this->refreshLiveStatus();
this->refreshBadges();
this->refreshCheerEmotes();
this->refreshFFZChannelEmotes();
this->refreshBTTVChannelEmotes();
this->refreshFFZChannelEmotes(false);
this->refreshBTTVChannelEmotes(false);
});
// timers
@ -155,20 +155,22 @@ bool TwitchChannel::canSendMessage() const
return !this->isEmpty();
}
void TwitchChannel::refreshBTTVChannelEmotes()
void TwitchChannel::refreshBTTVChannelEmotes(bool manualRefresh)
{
BttvEmotes::loadChannel(
this->roomId(), [this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
weakOf<Channel>(this), this->roomId(),
[this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
if (auto shared = weak.lock())
this->bttvEmotes_.set(
std::make_shared<EmoteMap>(std::move(emoteMap)));
});
},
manualRefresh);
}
void TwitchChannel::refreshFFZChannelEmotes()
void TwitchChannel::refreshFFZChannelEmotes(bool manualRefresh)
{
FfzEmotes::loadChannel(
this->roomId(),
weakOf<Channel>(this), this->roomId(),
[this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
if (auto shared = weak.lock())
this->ffzEmotes_.set(
@ -179,7 +181,8 @@ void TwitchChannel::refreshFFZChannelEmotes()
{
this->ffzCustomModBadge_.set(std::move(modBadge));
}
});
},
manualRefresh);
}
void TwitchChannel::sendMessage(const QString &message)

View file

@ -91,8 +91,8 @@ public:
std::shared_ptr<const EmoteMap> bttvEmotes() const;
std::shared_ptr<const EmoteMap> ffzEmotes() const;
virtual void refreshBTTVChannelEmotes();
virtual void refreshFFZChannelEmotes();
virtual void refreshBTTVChannelEmotes(bool manualRefresh);
virtual void refreshFFZChannelEmotes(bool manualRefresh);
// Badges
boost::optional<EmotePtr> ffzCustomModBadge() const;

View file

@ -725,8 +725,8 @@ void Split::reloadChannelAndSubscriberEmotes()
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()))
{
twitchChannel->refreshBTTVChannelEmotes();
twitchChannel->refreshFFZChannelEmotes();
twitchChannel->refreshBTTVChannelEmotes(true);
twitchChannel->refreshFFZChannelEmotes(true);
}
}

View file

@ -765,8 +765,8 @@ void SplitHeader::reloadChannelEmotes()
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()))
{
twitchChannel->refreshFFZChannelEmotes();
twitchChannel->refreshBTTVChannelEmotes();
twitchChannel->refreshFFZChannelEmotes(true);
twitchChannel->refreshBTTVChannelEmotes(true);
}
}