From 56d09ac198d48c481145b295fdc7fdc8161bdd9a Mon Sep 17 00:00:00 2001 From: thekalio <3989419+thekalio@users.noreply.github.com> Date: Sat, 16 May 2020 06:43:44 -0400 Subject: [PATCH] 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). --- src/providers/bttv/BttvEmotes.cpp | 41 ++++++++++++++++++++++++-- src/providers/bttv/BttvEmotes.hpp | 7 +++-- src/providers/ffz/FfzEmotes.cpp | 29 ++++++++++++++---- src/providers/ffz/FfzEmotes.hpp | 6 ++-- src/providers/twitch/TwitchChannel.cpp | 19 +++++++----- src/providers/twitch/TwitchChannel.hpp | 4 +-- src/widgets/splits/Split.cpp | 4 +-- src/widgets/splits/SplitHeader.cpp | 4 +-- 8 files changed, 88 insertions(+), 26 deletions(-) diff --git a/src/providers/bttv/BttvEmotes.cpp b/src/providers/bttv/BttvEmotes.cpp index d0c4c2a19..f0ef92060 100644 --- a/src/providers/bttv/BttvEmotes.cpp +++ b/src/providers/bttv/BttvEmotes.cpp @@ -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 callback) +void BttvEmotes::loadChannel(std::weak_ptr channel, + const QString &channelId, + std::function 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(); } diff --git a/src/providers/bttv/BttvEmotes.hpp b/src/providers/bttv/BttvEmotes.hpp index 9c16edeff..5844e0858 100644 --- a/src/providers/bttv/BttvEmotes.hpp +++ b/src/providers/bttv/BttvEmotes.hpp @@ -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 emotes() const; boost::optional emote(const EmoteName &name) const; void loadEmotes(); - static void loadChannel(const QString &channelId, - std::function callback); + static void loadChannel(std::weak_ptr channel, + const QString &channelId, + std::function callback, + bool manualRefresh); private: Atomic> global_; diff --git a/src/providers/ffz/FfzEmotes.cpp b/src/providers/ffz/FfzEmotes.cpp index 8589e3a6b..89f3c9361 100644 --- a/src/providers/ffz/FfzEmotes.cpp +++ b/src/providers/ffz/FfzEmotes.cpp @@ -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 emoteCallback, - std::function)> modBadgeCallback) + std::weak_ptr channel, const QString &channelId, + std::function emoteCallback, + std::function)> 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(); diff --git a/src/providers/ffz/FfzEmotes.hpp b/src/providers/ffz/FfzEmotes.hpp index 297ac4257..817341c83 100644 --- a/src/providers/ffz/FfzEmotes.hpp +++ b/src/providers/ffz/FfzEmotes.hpp @@ -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 emote(const EmoteName &name) const; void loadEmotes(); static void loadChannel( - const QString &channelId, + std::weak_ptr channel, const QString &channelId, std::function emoteCallback, - std::function)> modBadgeCallback); + std::function)> modBadgeCallback, + bool manualRefresh); private: Atomic> global_; diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index ac448b309..2f24366c3 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -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(this)](auto &&emoteMap) { + weakOf(this), this->roomId(), + [this, weak = weakOf(this)](auto &&emoteMap) { if (auto shared = weak.lock()) this->bttvEmotes_.set( std::make_shared(std::move(emoteMap))); - }); + }, + manualRefresh); } -void TwitchChannel::refreshFFZChannelEmotes() +void TwitchChannel::refreshFFZChannelEmotes(bool manualRefresh) { FfzEmotes::loadChannel( - this->roomId(), + weakOf(this), this->roomId(), [this, weak = weakOf(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) diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index fc40ad325..4ba7476f3 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -91,8 +91,8 @@ public: std::shared_ptr bttvEmotes() const; std::shared_ptr ffzEmotes() const; - virtual void refreshBTTVChannelEmotes(); - virtual void refreshFFZChannelEmotes(); + virtual void refreshBTTVChannelEmotes(bool manualRefresh); + virtual void refreshFFZChannelEmotes(bool manualRefresh); // Badges boost::optional ffzCustomModBadge() const; diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index 84048191b..6ed57094a 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -725,8 +725,8 @@ void Split::reloadChannelAndSubscriberEmotes() if (auto twitchChannel = dynamic_cast(channel.get())) { - twitchChannel->refreshBTTVChannelEmotes(); - twitchChannel->refreshFFZChannelEmotes(); + twitchChannel->refreshBTTVChannelEmotes(true); + twitchChannel->refreshFFZChannelEmotes(true); } } diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 55ec556e8..b05a34285 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -765,8 +765,8 @@ void SplitHeader::reloadChannelEmotes() if (auto twitchChannel = dynamic_cast(channel.get())) { - twitchChannel->refreshFFZChannelEmotes(); - twitchChannel->refreshBTTVChannelEmotes(); + twitchChannel->refreshFFZChannelEmotes(true); + twitchChannel->refreshBTTVChannelEmotes(true); } }