Add subtitle to Hype Chats (#4715)

* feat: more hype chat

* Add `std::chrono::seconds` overload to formatTime

* Move & rename it to HypeChat + some other mini things

* Add changelog entry

* fix formattime test

---------

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix
2023-07-30 18:54:42 +02:00
committed by GitHub
parent 71594ad0d8
commit 703847c9ba
8 changed files with 207 additions and 8 deletions
@@ -2,6 +2,7 @@
#include "Application.hpp"
#include "common/LinkParser.hpp"
#include "common/Literals.hpp"
#include "common/QLogging.hpp"
#include "controllers/accounts/AccountController.hpp"
#include "controllers/ignores/IgnoreController.hpp"
@@ -28,8 +29,10 @@
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp"
#include "singletons/WindowManager.hpp"
#include "util/FormatTime.hpp"
#include "util/Helpers.hpp"
#include "util/IrcHelpers.hpp"
#include "util/QStringHash.hpp"
#include "util/Qt.hpp"
#include "widgets/Window.hpp"
@@ -38,8 +41,15 @@
#include <QDebug>
#include <QStringRef>
#include <chrono>
#include <unordered_set>
using namespace chatterino::literals;
namespace {
using namespace std::chrono_literals;
const QString regexHelpString("(\\w+)[.,!?;:]*?$");
// matches a mention with punctuation at the end, like "@username," or "@username!!!" where capture group would return "username"
@@ -53,6 +63,19 @@ const QSet<QString> zeroWidthEmotes{
"ReinDeer", "CandyCane", "cvMask", "cvHazmat",
};
struct HypeChatPaidLevel {
std::chrono::seconds duration;
uint8_t numeric;
};
const std::unordered_map<QString, HypeChatPaidLevel> HYPE_CHAT_PAID_LEVEL{
{u"ONE"_s, {30s, 1}}, {u"TWO"_s, {2min + 30s, 2}},
{u"THREE"_s, {5min, 3}}, {u"FOUR"_s, {10min, 4}},
{u"FIVE"_s, {30min, 5}}, {u"SIX"_s, {1h, 6}},
{u"SEVEN"_s, {2h, 7}}, {u"EIGHT"_s, {3h, 8}},
{u"NINE"_s, {4h, 9}}, {u"TEN"_s, {5h, 10}},
};
} // namespace
namespace chatterino {
@@ -1739,6 +1762,45 @@ void TwitchMessageBuilder::listOfUsersSystemMessage(
builder->message().searchText = text;
}
MessagePtr TwitchMessageBuilder::buildHypeChatMessage(
Communi::IrcPrivateMessage *message)
{
auto level = message->tag(u"pinned-chat-paid-level"_s).toString();
auto currency = message->tag(u"pinned-chat-paid-currency"_s).toString();
bool okAmount = false;
auto amount = message->tag(u"pinned-chat-paid-amount"_s).toInt(&okAmount);
bool okExponent = false;
auto exponent =
message->tag(u"pinned-chat-paid-exponent"_s).toInt(&okExponent);
if (!okAmount || !okExponent || currency.isEmpty())
{
return {};
}
// additionally, there's `pinned-chat-paid-is-system-message` which isn't used by Chatterino.
QString subtitle;
auto levelIt = HYPE_CHAT_PAID_LEVEL.find(level);
if (levelIt != HYPE_CHAT_PAID_LEVEL.end())
{
const auto &level = levelIt->second;
subtitle = u"Level %1 Hype Chat (%2) "_s.arg(level.numeric)
.arg(formatTime(level.duration));
}
else
{
subtitle = u"Hype Chat "_s;
}
// actualAmount = amount * 10^(-exponent)
double actualAmount = std::pow(10.0, double(-exponent)) * double(amount);
subtitle += QLocale::system().toCurrencyString(actualAmount, currency);
MessageBuilder builder(systemMessage, parseTagString(subtitle),
calculateMessageTime(message).time());
builder->flags.set(MessageFlag::ElevatedMessage);
return builder.release();
}
void TwitchMessageBuilder::setThread(std::shared_ptr<MessageThread> thread)
{
this->thread_ = std::move(thread);