From 18c4815ad74bc794b952a3a787d59477952b91a7 Mon Sep 17 00:00:00 2001
From: iProdigy <8106344+iProdigy@users.noreply.github.com>
Date: Tue, 22 Oct 2024 16:42:19 +0000
Subject: [PATCH] feat: add shared chat badge (#5661)
---
CHANGELOG.md | 2 +-
mocks/include/mocks/BaseApplication.hpp | 7 ++++
mocks/include/mocks/TwitchUsers.hpp | 24 ++++++++++++
resources/twitch/sharedChat.png | Bin 0 -> 1026 bytes
src/messages/MessageBuilder.cpp | 35 ++++++++++++++++++
src/messages/MessageElement.hpp | 6 ++-
src/singletons/WindowManager.cpp | 1 +
src/widgets/helper/ChannelView.cpp | 5 +++
.../shared-chat-announcement.json | 18 +++++++++
.../IrcMessageHandler/shared-chat-emotes.json | 18 +++++++++
.../IrcMessageHandler/shared-chat-known.json | 18 +++++++++
.../shared-chat-unknown.json | 18 +++++++++
12 files changed, 150 insertions(+), 2 deletions(-)
create mode 100644 mocks/include/mocks/TwitchUsers.hpp
create mode 100644 resources/twitch/sharedChat.png
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c95aa2df7..7497e46dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@
- Major: Improve high-DPI support on Windows. (#4868, #5391, #5664, #5666)
- Major: Added transparent overlay window (default keybind: CTRL + ALT + N). (#4746, #5643, #5659)
- Minor: Removed the Ctrl+Shift+L hotkey for toggling the "live only" tab visibility state. (#5530)
-- Minor: Add support for Shared Chat messages. Shared chat messages can be filtered with the `flags.shared` filter variable, or with search using `is:shared`. Some messages like subscriptions are filtered on purpose to avoid confusion for the broadcaster. If you have both channels participating in Shared Chat open, only one of the message triggering your highlight will trigger. (#5606, #5625)
+- Minor: Add support for Shared Chat messages. Shared chat messages can be filtered with the `flags.shared` filter variable, or with search using `is:shared`. Some messages like subscriptions are filtered on purpose to avoid confusion for the broadcaster. If you have both channels participating in Shared Chat open, only one of the message triggering your highlight will trigger. (#5606, #5625, #5661)
- Minor: Moved tab visibility control to a submenu, without any toggle actions. (#5530)
- Minor: Add option to customise Moderation buttons with images. (#5369)
- Minor: Colored usernames now update on the fly when changing the "Color @usernames" setting. (#5300)
diff --git a/mocks/include/mocks/BaseApplication.hpp b/mocks/include/mocks/BaseApplication.hpp
index 2ba9f949c..619203afc 100644
--- a/mocks/include/mocks/BaseApplication.hpp
+++ b/mocks/include/mocks/BaseApplication.hpp
@@ -3,6 +3,7 @@
#include "common/Args.hpp"
#include "mocks/DisabledStreamerMode.hpp"
#include "mocks/EmptyApplication.hpp"
+#include "mocks/TwitchUsers.hpp"
#include "providers/bttv/BttvLiveUpdates.hpp"
#include "singletons/Fonts.hpp"
#include "singletons/Settings.hpp"
@@ -55,6 +56,11 @@ public:
return &this->fonts;
}
+ ITwitchUsers *getTwitchUsers() override
+ {
+ return &this->twitchUsers;
+ }
+
BttvLiveUpdates *getBttvLiveUpdates() override
{
return nullptr;
@@ -71,6 +77,7 @@ public:
DisabledStreamerMode streamerMode;
Theme theme;
Fonts fonts;
+ TwitchUsers twitchUsers;
};
} // namespace chatterino::mock
diff --git a/mocks/include/mocks/TwitchUsers.hpp b/mocks/include/mocks/TwitchUsers.hpp
new file mode 100644
index 000000000..14f6bf7e6
--- /dev/null
+++ b/mocks/include/mocks/TwitchUsers.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "providers/twitch/TwitchUser.hpp"
+#include "providers/twitch/TwitchUsers.hpp"
+
+namespace chatterino::mock {
+
+class TwitchUsers : public ITwitchUsers
+{
+public:
+ TwitchUsers() = default;
+
+ std::shared_ptr resolveID(const UserId &id)
+ {
+ TwitchUser u = {
+ .id = id.string,
+ .name = {},
+ .displayName = {},
+ };
+ return std::make_shared(u);
+ }
+};
+
+} // namespace chatterino::mock
diff --git a/resources/twitch/sharedChat.png b/resources/twitch/sharedChat.png
new file mode 100644
index 0000000000000000000000000000000000000000..f9a66b17c8f1307a811337d4095cfaf1d5133515
GIT binary patch
literal 1026
zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAk#;Q*fy*NU|NG(!LX|Nr^(e@*uP
zd$<4p{rms?ng1U@{9iif|L@=buU-Cs`TYM?i~qlU^Z)U~|I@nvSEm0zxaa@IRsSb6
z|9}4M|DnDA`x^h>xcYzj{QnbM|9}7X|M;Q*i)Q|xH}(Il{{MA(|DQei-(LCu#q<=zrK9*{>1C^clU0Xn)vbhy!sVAg*UfUI2;J^GsxzPd&a=P
zbkWnrF(l&f+Z#8_RvCz}J>ckI4mh6Gp1eq8rcA-QsO;bW{7YvAziCqwl*&8j`oBAl
z;kEY6ZQZ^9?nM4g+q+Op)#OKEfM=le*R<1Bdz{PpV=u4BdMY%jF<|AI&}yKVL)iAq
z*Rn-j#e%d;1qMUNOJ@efullHzz!@eBYZ|ugHAyz{Ar#Yi*Qyz}~3Ed=5s7FH2cv
zWr!A}C}>R$gQXeipB1Fb4wiI2
z)>(dif#tKbx}Ez~3nu2QcM!HS*|~?m)L~YaVmrU($G6wNJY6cGRMTu|=CWKQEhf`u($Zu_j(ksaa11KN_h^Z&GV=o?ZM?@%@Y-&FVjXfAll)^oi9wdK|>goDW=gNNsxji~kMF<|(h3uuOo{TaS6teGKZnoa~OJoN)-YzWg&zh?9*|LBGHGu!>011cstd
z7EdO$@Uf^g+_5=l@$$e`5tTVg`cFGl8s@Q{yFH<>LdZdwQRMIJ?w$$E4%%nV&s^u1
z=G3rk#(d$s`ZE<7I*)yGDlbU;!&35OowTjU;fv2t);@Yte7&cQq4VFy>Lo%p^SJJK
zI2~3Euc}K_xyIP>?9VjsB-v$7^Y-YR^mnqe@L74c%_h^RTXkDcgRw__*SV&Nv%^kk
zG&CBdvfN`gls~>aVLzvA((NOh=D#0&F;%tW>_5rgulTY3gV~p2*(FT#Ute&T;CII%
zBV%e((49*^vNnknYTa7fH_LYKGA#v9%d6GQTYZ?NqBi;M%~e{R`fb5cHO8qcFTY&u
zzFO4$?}U`}H{bT%eHpdo^>xE9O0o8L4SrvH93SN4boPM9;wQjdz~JfX=d#Wzp$Pys
C^A0Qk
literal 0
HcmV?d00001
diff --git a/src/messages/MessageBuilder.cpp b/src/messages/MessageBuilder.cpp
index a17f955a9..601ba8ec9 100644
--- a/src/messages/MessageBuilder.cpp
+++ b/src/messages/MessageBuilder.cpp
@@ -32,6 +32,7 @@
#include "providers/twitch/TwitchChannel.hpp"
#include "providers/twitch/TwitchIrc.hpp"
#include "providers/twitch/TwitchIrcServer.hpp"
+#include "providers/twitch/TwitchUsers.hpp"
#include "singletons/Emotes.hpp"
#include "singletons/Resources.hpp"
#include "singletons/Settings.hpp"
@@ -380,6 +381,18 @@ EmotePtr makeAutoModBadge()
Url{"https://dashboard.twitch.tv/settings/moderation/automod"}});
}
+EmotePtr makeSharedChatBadge(const QString &sourceName)
+{
+ return std::make_shared(Emote{
+ .name = EmoteName{},
+ .images = ImageSet{Image::fromResourcePixmap(
+ getResources().twitch.sharedChat, 0.25)},
+ .tooltip = Tooltip{"Shared Message" +
+ (sourceName.isEmpty() ? "" : " from " + sourceName)},
+ .homePage = Url{"https://link.twitch.tv/SharedChatViewer"},
+ });
+}
+
std::tuple, MessageElementFlags, bool> parseEmote(
TwitchChannel *twitchChannel, const EmoteName &name)
{
@@ -2751,6 +2764,28 @@ void MessageBuilder::appendTwitchBadges(const QVariantMap &tags,
return;
}
+ if (this->message().flags.has(MessageFlag::SharedMessage))
+ {
+ const QString sourceId = tags["source-room-id"].toString();
+ QString sourceName;
+ if (sourceId.isEmpty())
+ {
+ sourceName = "";
+ }
+ else if (twitchChannel->roomId() == sourceId)
+ {
+ sourceName = twitchChannel->getName();
+ }
+ else
+ {
+ sourceName =
+ getApp()->getTwitchUsers()->resolveID({sourceId})->displayName;
+ }
+
+ this->emplace(makeSharedChatBadge(sourceName),
+ MessageElementFlag::BadgeSharedChannel);
+ }
+
auto badgeInfos = parseBadgeInfoTag(tags);
auto badges = parseBadgeTag(tags);
appendBadges(this, badges, badgeInfos, twitchChannel);
diff --git a/src/messages/MessageElement.hpp b/src/messages/MessageElement.hpp
index 0e6c07b93..c19ed5c0c 100644
--- a/src/messages/MessageElement.hpp
+++ b/src/messages/MessageElement.hpp
@@ -66,6 +66,10 @@ enum class MessageElementFlag : int64_t {
BitsStatic = (1LL << 11),
BitsAnimated = (1LL << 12),
+ // Slot 0: Twitch
+ // - Shared Channel indicator badge
+ BadgeSharedChannel = (1LL << 37),
+
// Slot 1: Twitch
// - Staff badge
// - Admin badge
@@ -119,7 +123,7 @@ enum class MessageElementFlag : int64_t {
Badges = BadgeGlobalAuthority | BadgePredictions | BadgeChannelAuthority |
BadgeSubscription | BadgeVanity | BadgeChatterino | BadgeSevenTV |
- BadgeFfz,
+ BadgeFfz | BadgeSharedChannel,
ChannelName = (1LL << 20),
diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp
index f64eb47e7..88d5ec565 100644
--- a/src/singletons/WindowManager.cpp
+++ b/src/singletons/WindowManager.cpp
@@ -195,6 +195,7 @@ void WindowManager::updateWordTypeMask()
flags.set(settings->animateEmotes ? MEF::BitsAnimated : MEF::BitsStatic);
// badges
+ flags.set(MEF::BadgeSharedChannel);
flags.set(settings->showBadgesGlobalAuthority ? MEF::BadgeGlobalAuthority
: MEF::None);
flags.set(settings->showBadgesPredictions ? MEF::BadgePredictions
diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp
index 066085030..50f6d1acc 100644
--- a/src/widgets/helper/ChannelView.cpp
+++ b/src/widgets/helper/ChannelView.cpp
@@ -2408,6 +2408,11 @@ void ChannelView::handleMouseClick(QMouseEvent *event,
return;
}
+ if (link.value.startsWith("id:"))
+ {
+ return;
+ }
+
// Insert @username into split input
const bool commaMention =
getSettings()->mentionUsersWithComma;
diff --git a/tests/snapshots/IrcMessageHandler/shared-chat-announcement.json b/tests/snapshots/IrcMessageHandler/shared-chat-announcement.json
index 9c6fa2f65..a6877c365 100644
--- a/tests/snapshots/IrcMessageHandler/shared-chat-announcement.json
+++ b/tests/snapshots/IrcMessageHandler/shared-chat-announcement.json
@@ -64,6 +64,24 @@
"trailingSpace": true,
"type": "TwitchModerationElement"
},
+ {
+ "emote": {
+ "homePage": "https://link.twitch.tv/SharedChatViewer",
+ "images": {
+ "1x": ""
+ },
+ "name": "",
+ "tooltip": "Shared Message"
+ },
+ "flags": "BadgeSharedChannel",
+ "link": {
+ "type": "None",
+ "value": ""
+ },
+ "tooltip": "Shared Message",
+ "trailingSpace": true,
+ "type": "BadgeElement"
+ },
{
"emote": {
"homePage": "https://www.twitch.tv/jobs?ref=chat_badge",
diff --git a/tests/snapshots/IrcMessageHandler/shared-chat-emotes.json b/tests/snapshots/IrcMessageHandler/shared-chat-emotes.json
index b7f9256d4..ba6485c21 100644
--- a/tests/snapshots/IrcMessageHandler/shared-chat-emotes.json
+++ b/tests/snapshots/IrcMessageHandler/shared-chat-emotes.json
@@ -64,6 +64,24 @@
"trailingSpace": true,
"type": "TwitchModerationElement"
},
+ {
+ "emote": {
+ "homePage": "https://link.twitch.tv/SharedChatViewer",
+ "images": {
+ "1x": ""
+ },
+ "name": "",
+ "tooltip": "Shared Message from twitchdev"
+ },
+ "flags": "BadgeSharedChannel",
+ "link": {
+ "type": "None",
+ "value": ""
+ },
+ "tooltip": "Shared Message from twitchdev",
+ "trailingSpace": true,
+ "type": "BadgeElement"
+ },
{
"color": "#ffff0000",
"flags": "Username",
diff --git a/tests/snapshots/IrcMessageHandler/shared-chat-known.json b/tests/snapshots/IrcMessageHandler/shared-chat-known.json
index 6a13adcb4..c4a3f3e2f 100644
--- a/tests/snapshots/IrcMessageHandler/shared-chat-known.json
+++ b/tests/snapshots/IrcMessageHandler/shared-chat-known.json
@@ -64,6 +64,24 @@
"trailingSpace": true,
"type": "TwitchModerationElement"
},
+ {
+ "emote": {
+ "homePage": "https://link.twitch.tv/SharedChatViewer",
+ "images": {
+ "1x": ""
+ },
+ "name": "",
+ "tooltip": "Shared Message from twitchdev"
+ },
+ "flags": "BadgeSharedChannel",
+ "link": {
+ "type": "None",
+ "value": ""
+ },
+ "tooltip": "Shared Message from twitchdev",
+ "trailingSpace": true,
+ "type": "BadgeElement"
+ },
{
"emote": {
"homePage": "https://www.twitch.tv/jobs?ref=chat_badge",
diff --git a/tests/snapshots/IrcMessageHandler/shared-chat-unknown.json b/tests/snapshots/IrcMessageHandler/shared-chat-unknown.json
index accbb76b0..6ea80b2ce 100644
--- a/tests/snapshots/IrcMessageHandler/shared-chat-unknown.json
+++ b/tests/snapshots/IrcMessageHandler/shared-chat-unknown.json
@@ -64,6 +64,24 @@
"trailingSpace": true,
"type": "TwitchModerationElement"
},
+ {
+ "emote": {
+ "homePage": "https://link.twitch.tv/SharedChatViewer",
+ "images": {
+ "1x": ""
+ },
+ "name": "",
+ "tooltip": "Shared Message"
+ },
+ "flags": "BadgeSharedChannel",
+ "link": {
+ "type": "None",
+ "value": ""
+ },
+ "tooltip": "Shared Message",
+ "trailingSpace": true,
+ "type": "BadgeElement"
+ },
{
"emote": {
"homePage": "https://www.twitch.tv/jobs?ref=chat_badge",