mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
feat: notate power-up automatic reward redemptions (#5471)
This commit is contained in:
parent
c01bfcfffe
commit
2ef3306d1d
|
@ -14,6 +14,7 @@
|
|||
- Minor: Moderators can now see when users are warned. (#5441)
|
||||
- Minor: Added support for Brave & google-chrome-stable browsers. (#5452)
|
||||
- Minor: Added drop indicator line while dragging in tables. (#5256)
|
||||
- Minor: Add channel points indication for new bits power-up redemptions. (#5471)
|
||||
- Minor: Added `/warn <username> <reason>` command for mods. This prevents the user from chatting until they acknowledge the warning. (#5474)
|
||||
- Minor: Introduce HTTP API for plugins. (#5383)
|
||||
- Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426)
|
||||
|
|
|
@ -14,6 +14,47 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
|
|||
this->title = reward.value("title").toString();
|
||||
this->cost = reward.value("cost").toInt();
|
||||
this->isUserInputRequired = reward.value("is_user_input_required").toBool();
|
||||
this->isBits = reward.value("pricing_type").toString() == "BITS";
|
||||
|
||||
// accommodate idiosyncrasies of automatic reward redemptions
|
||||
const auto rewardType = reward.value("reward_type").toString();
|
||||
if (rewardType == "SEND_ANIMATED_MESSAGE")
|
||||
{
|
||||
this->id = "animated-message";
|
||||
this->isUserInputRequired = true;
|
||||
this->title = "Message Effects";
|
||||
}
|
||||
else if (rewardType == "SEND_GIGANTIFIED_EMOTE")
|
||||
{
|
||||
this->id = "gigantified-emote-message";
|
||||
this->isUserInputRequired = true;
|
||||
this->title = "Gigantify an Emote";
|
||||
}
|
||||
else if (rewardType == "CELEBRATION")
|
||||
{
|
||||
this->id = rewardType;
|
||||
this->title = "On-Screen Celebration";
|
||||
const auto metadata =
|
||||
redemption.value("redemption_metadata").toObject();
|
||||
const auto emote = metadata.value("celebration_emote_metadata")
|
||||
.toObject()
|
||||
.value("emote")
|
||||
.toObject();
|
||||
this->emoteId = emote.value("id").toString();
|
||||
this->emoteName = emote.value("token").toString();
|
||||
}
|
||||
|
||||
// use bits cost when channel points were not used
|
||||
if (cost == 0)
|
||||
{
|
||||
this->cost = reward.value("bits_cost").toInt();
|
||||
}
|
||||
|
||||
// workaround twitch bug where bits_cost is always 0 in practice
|
||||
if (cost == 0)
|
||||
{
|
||||
this->cost = reward.value("default_bits_cost").toInt();
|
||||
}
|
||||
|
||||
// We don't need to store user information for rewards with user input
|
||||
// because we will get the user info from a corresponding IRC message
|
||||
|
@ -27,6 +68,13 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
|
|||
}
|
||||
|
||||
auto imageValue = reward.value("image");
|
||||
|
||||
// automatic reward redemptions have specialized default images
|
||||
if (imageValue.isNull() && this->isBits)
|
||||
{
|
||||
imageValue = reward.value("default_image");
|
||||
}
|
||||
|
||||
// From Twitch docs
|
||||
// The size is only an estimation, the actual size might vary.
|
||||
constexpr QSize baseSize(28, 28);
|
||||
|
|
|
@ -19,6 +19,9 @@ struct ChannelPointReward {
|
|||
int cost;
|
||||
ImageSet image;
|
||||
bool isUserInputRequired = false;
|
||||
bool isBits = false;
|
||||
QString emoteId; // currently only for celebrations
|
||||
QString emoteName; // currently only for celebrations
|
||||
|
||||
struct {
|
||||
QString id;
|
||||
|
|
|
@ -1338,21 +1338,30 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
|
|||
auto *channel = dynamic_cast<TwitchChannel *>(chan.get());
|
||||
|
||||
const auto &tags = message->tags();
|
||||
QString rewardId;
|
||||
if (const auto it = tags.find("custom-reward-id"); it != tags.end())
|
||||
{
|
||||
const auto rewardId = it.value().toString();
|
||||
if (!rewardId.isEmpty() &&
|
||||
!channel->isChannelPointRewardKnown(rewardId))
|
||||
{
|
||||
// Need to wait for pubsub reward notification
|
||||
qCDebug(chatterinoTwitch) << "TwitchChannel reward added ADD "
|
||||
"callback since reward is not known:"
|
||||
<< rewardId;
|
||||
channel->addQueuedRedemption(rewardId, originalContent, message);
|
||||
return;
|
||||
}
|
||||
args.channelPointRewardId = rewardId;
|
||||
rewardId = it.value().toString();
|
||||
}
|
||||
else if (const auto typeIt = tags.find("msg-id"); typeIt != tags.end())
|
||||
{
|
||||
// slight hack to treat bits power-ups as channel point redemptions
|
||||
const auto msgId = typeIt.value().toString();
|
||||
if (msgId == "animated-message" || msgId == "gigantified-emote-message")
|
||||
{
|
||||
rewardId = msgId;
|
||||
}
|
||||
}
|
||||
if (!rewardId.isEmpty() && !channel->isChannelPointRewardKnown(rewardId))
|
||||
{
|
||||
// Need to wait for pubsub reward notification
|
||||
qCDebug(chatterinoTwitch) << "TwitchChannel reward added ADD "
|
||||
"callback since reward is not known:"
|
||||
<< rewardId;
|
||||
channel->addQueuedRedemption(rewardId, originalContent, message);
|
||||
return;
|
||||
}
|
||||
args.channelPointRewardId = rewardId;
|
||||
|
||||
QString content = originalContent;
|
||||
int messageOffset = stripLeadingReplyMention(tags, content);
|
||||
|
|
|
@ -1181,6 +1181,8 @@ void PubSub::handleMessageResponse(const PubSubMessageMessage &message)
|
|||
|
||||
switch (innerMessage.type)
|
||||
{
|
||||
case PubSubCommunityPointsChannelV1Message::Type::
|
||||
AutomaticRewardRedeemed:
|
||||
case PubSubCommunityPointsChannelV1Message::Type::RewardRedeemed: {
|
||||
auto redemption =
|
||||
innerMessage.data.value("redemption").toObject();
|
||||
|
|
|
@ -1594,6 +1594,15 @@ void TwitchMessageBuilder::appendChannelPointRewardMessage(
|
|||
}
|
||||
builder->emplace<TextElement>(redeemed,
|
||||
MessageElementFlag::ChannelPointReward);
|
||||
if (reward.id == "CELEBRATION")
|
||||
{
|
||||
const auto emotePtr =
|
||||
getIApp()->getEmotes()->getTwitchEmotes()->getOrCreateEmote(
|
||||
EmoteId{reward.emoteId}, EmoteName{reward.emoteName});
|
||||
builder->emplace<EmoteElement>(emotePtr,
|
||||
MessageElementFlag::ChannelPointReward,
|
||||
MessageColor::Text);
|
||||
}
|
||||
builder->emplace<TextElement>(
|
||||
reward.title, MessageElementFlag::ChannelPointReward,
|
||||
MessageColor::Text, FontStyle::ChatMediumBold);
|
||||
|
@ -1602,6 +1611,12 @@ void TwitchMessageBuilder::appendChannelPointRewardMessage(
|
|||
builder->emplace<TextElement>(
|
||||
QString::number(reward.cost), MessageElementFlag::ChannelPointReward,
|
||||
MessageColor::Text, FontStyle::ChatMediumBold);
|
||||
if (reward.isBits)
|
||||
{
|
||||
builder->emplace<TextElement>(
|
||||
"bits", MessageElementFlag::ChannelPointReward, MessageColor::Text,
|
||||
FontStyle::ChatMediumBold);
|
||||
}
|
||||
if (reward.isUserInputRequired)
|
||||
{
|
||||
builder->emplace<LinebreakElement>(
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace chatterino {
|
|||
|
||||
struct PubSubCommunityPointsChannelV1Message {
|
||||
enum class Type {
|
||||
AutomaticRewardRedeemed,
|
||||
RewardRedeemed,
|
||||
|
||||
INVALID,
|
||||
|
@ -30,6 +31,9 @@ constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<
|
|||
{
|
||||
switch (value)
|
||||
{
|
||||
case chatterino::PubSubCommunityPointsChannelV1Message::Type::
|
||||
AutomaticRewardRedeemed:
|
||||
return "automatic-reward-redeemed";
|
||||
case chatterino::PubSubCommunityPointsChannelV1Message::Type::
|
||||
RewardRedeemed:
|
||||
return "reward-redeemed";
|
||||
|
|
Loading…
Reference in a new issue