Skip to content

Commit

Permalink
feat: add channel for messages caught by AutoMod (#4986)
Browse files Browse the repository at this point in the history
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
  • Loading branch information
iProdigy and pajlada committed Dec 3, 2023
1 parent 812186d commit 44abe6b
Show file tree
Hide file tree
Showing 17 changed files with 107 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unversioned

- Major: Allow use of Twitch follower emotes in other channels if subscribed. (#4922)
- Major: Add `/automod` split to track automod caught messages across all open channels the user moderates. (#4986)
- Minor: Migrate to the new Get Channel Followers Helix endpoint, fixing follower count not showing up in usercards. (#4809)
- Minor: The account switcher is now styled to match your theme. (#4817)
- Minor: Add an invisible resize handle to the bottom of frameless user info popups and reply thread popups. (#4795)
Expand Down
10 changes: 8 additions & 2 deletions src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,15 @@ void Application::initPubSub()
msg.senderUserID, msg.senderUserLogin,
senderDisplayName, senderColor};
postToThread([chan, action] {
const auto p = makeAutomodMessage(action);
const auto p =
makeAutomodMessage(action, chan->getName());
chan->addMessage(p.first);
chan->addMessage(p.second);

getApp()->twitch->automodChannel->addMessage(
p.first);
getApp()->twitch->automodChannel->addMessage(
p.second);
});
}
// "ALLOWED" and "DENIED" statuses remain unimplemented
Expand All @@ -573,7 +579,7 @@ void Application::initPubSub()
}

postToThread([chan, action] {
const auto p = makeAutomodMessage(action);
const auto p = makeAutomodMessage(action, chan->getName());
chan->addMessage(p.first);
chan->addMessage(p.second);
});
Expand Down
6 changes: 4 additions & 2 deletions src/common/Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ bool Channel::isWritable() const
{
using Type = Channel::Type;
auto type = this->getType();
return type != Type::TwitchMentions && type != Type::TwitchLive;
return type != Type::TwitchMentions && type != Type::TwitchLive &&
type != Type::TwitchAutomod;
}

void Channel::sendMessage(const QString &message)
Expand Down Expand Up @@ -330,7 +331,8 @@ bool Channel::isLive() const

bool Channel::shouldIgnoreHighlights() const
{
return this->type_ == Type::TwitchMentions ||
return this->type_ == Type::TwitchAutomod ||
this->type_ == Type::TwitchMentions ||
this->type_ == Type::TwitchWhispers;
}

Expand Down
1 change: 1 addition & 0 deletions src/common/Channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Channel : public std::enable_shared_from_this<Channel>
TwitchWatching,
TwitchMentions,
TwitchLive,
TwitchAutomod,
TwitchEnd,
Irc,
Misc
Expand Down
2 changes: 1 addition & 1 deletion src/common/WindowDescriptors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace chatterino {
enum class WindowType;

struct SplitDescriptor {
// Twitch or mentions or watching or whispers or IRC
// Twitch or mentions or watching or live or automod or whispers or IRC
QString type_;

// Twitch Channel name or IRC channel name
Expand Down
9 changes: 8 additions & 1 deletion src/messages/MessageBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,14 @@ MessagePtr makeAutomodInfoMessage(const AutomodInfoAction &action)
}

std::pair<MessagePtr, MessagePtr> makeAutomodMessage(
const AutomodAction &action)
const AutomodAction &action, const QString &channelName)
{
MessageBuilder builder, builder2;

//
// Builder for AutoMod message with explanation
builder.message().loginName = "automod";
builder.message().channelName = channelName;
builder.message().flags.set(MessageFlag::PubSub);
builder.message().flags.set(MessageFlag::Timeout);
builder.message().flags.set(MessageFlag::AutoMod);
Expand Down Expand Up @@ -193,6 +194,12 @@ std::pair<MessagePtr, MessagePtr> makeAutomodMessage(

//
// Builder for offender's message
builder2.message().channelName = channelName;
builder2
.emplace<TextElement>("#" + channelName,
MessageElementFlag::ChannelName,
MessageColor::System)
->setLink({Link::JumpToChannel, channelName});
builder2.emplace<TimestampElement>();
builder2.emplace<TwitchModerationElement>();
builder2.message().loginName = action.target.login;
Expand Down
2 changes: 1 addition & 1 deletion src/messages/MessageBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const ImageUploaderResultTag imageUploaderResultMessage{};
MessagePtr makeSystemMessage(const QString &text);
MessagePtr makeSystemMessage(const QString &text, const QTime &time);
std::pair<MessagePtr, MessagePtr> makeAutomodMessage(
const AutomodAction &action);
const AutomodAction &action, const QString &channelName);
MessagePtr makeAutomodInfoMessage(const AutomodInfoAction &action);

struct MessageParseArgs {
Expand Down
7 changes: 7 additions & 0 deletions src/providers/twitch/TwitchIrcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ TwitchIrcServer::TwitchIrcServer()
: whispersChannel(new Channel("/whispers", Channel::Type::TwitchWhispers))
, mentionsChannel(new Channel("/mentions", Channel::Type::TwitchMentions))
, liveChannel(new Channel("/live", Channel::Type::TwitchLive))
, automodChannel(new Channel("/automod", Channel::Type::TwitchAutomod))
, watchingChannel(Channel::getEmpty(), Channel::Type::TwitchWatching)
{
this->initializeIrc();
Expand Down Expand Up @@ -272,6 +273,11 @@ std::shared_ptr<Channel> TwitchIrcServer::getCustomChannel(
return this->liveChannel;
}

if (channelName == "/automod")
{
return this->automodChannel;
}

static auto getTimer = [](ChannelPtr channel, int msBetweenMessages,
bool addInitialMessages) {
if (addInitialMessages)
Expand Down Expand Up @@ -383,6 +389,7 @@ void TwitchIrcServer::forEachChannelAndSpecialChannels(
func(this->whispersChannel);
func(this->mentionsChannel);
func(this->liveChannel);
func(this->automodChannel);
}

std::shared_ptr<Channel> TwitchIrcServer::getChannelOrEmptyByID(
Expand Down
1 change: 1 addition & 0 deletions src/providers/twitch/TwitchIrcServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class TwitchIrcServer final : public AbstractIrcServer,
const ChannelPtr whispersChannel;
const ChannelPtr mentionsChannel;
const ChannelPtr liveChannel;
const ChannelPtr automodChannel;
IndirectChannel watchingChannel;

PubSub *pubsub;
Expand Down
8 changes: 8 additions & 0 deletions src/singletons/WindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,10 @@ void WindowManager::encodeChannel(IndirectChannel channel, QJsonObject &obj)
obj.insert("name", channel.get()->getName());
}
break;
case Channel::Type::TwitchAutomod: {
obj.insert("type", "automod");
}
break;
case Channel::Type::TwitchMentions: {
obj.insert("type", "mentions");
}
Expand Down Expand Up @@ -676,6 +680,10 @@ IndirectChannel WindowManager::decodeChannel(const SplitDescriptor &descriptor)
{
return app->twitch->liveChannel;
}
else if (descriptor.type_ == "automod")
{
return app->twitch->automodChannel;
}
else if (descriptor.type_ == "irc")
{
return Irc::instance().getOrAddChannel(descriptor.server_,
Expand Down
7 changes: 6 additions & 1 deletion src/singletons/helper/LoggingChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ LoggingChannel::LoggingChannel(const QString &_channelName,
{
this->subDirectory = "Live";
}
else if (channelName.startsWith("/automod"))
{
this->subDirectory = "AutoMod";
}
else
{
this->subDirectory =
Expand Down Expand Up @@ -96,7 +100,8 @@ void LoggingChannel::addMessage(MessagePtr message)
}

QString str;
if (channelName.startsWith("/mentions"))
if (channelName.startsWith("/mentions") ||
channelName.startsWith("/automod"))
{
str.append("#" + message->channelName + " ");
}
Expand Down
5 changes: 3 additions & 2 deletions src/widgets/Notebook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1313,8 +1313,9 @@ SplitNotebook::SplitNotebook(Window *parent)
{
for (auto *split : sc->getSplits())
{
if (split->getChannel()->getType() !=
Channel::Type::TwitchMentions)
auto type = split->getChannel()->getType();
if (type != Channel::Type::TwitchMentions &&
type != Channel::Type::TwitchAutomod)
{
if (split->getChannelView().scrollToMessage(
message))
Expand Down
35 changes: 31 additions & 4 deletions src/widgets/dialogs/SelectChannelDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,35 @@ SelectChannelDialog::SelectChannelDialog(QWidget *parent)
live_lbl->setVisible(enabled);
});

// automod_btn
auto automod_btn = vbox.emplace<QRadioButton>("AutoMod").assign(
&this->ui_.twitch.automod);
auto automod_lbl =
vbox.emplace<QLabel>("Shows when AutoMod catches a message in any "
"channel you moderate.")
.hidden();

automod_lbl->setWordWrap(true);
automod_btn->installEventFilter(&this->tabFilter_);

QObject::connect(automod_btn.getElement(), &QRadioButton::toggled,
[=](bool enabled) mutable {
automod_lbl->setVisible(enabled);
});

vbox->addStretch(1);

// tabbing order
QWidget::setTabOrder(live_btn.getElement(), channel_btn.getElement());
QWidget::setTabOrder(automod_btn.getElement(),
channel_btn.getElement());
QWidget::setTabOrder(channel_btn.getElement(),
whispers_btn.getElement());
QWidget::setTabOrder(whispers_btn.getElement(),
mentions_btn.getElement());
QWidget::setTabOrder(mentions_btn.getElement(),
watching_btn.getElement());
QWidget::setTabOrder(watching_btn.getElement(), live_btn.getElement());
QWidget::setTabOrder(live_btn.getElement(), automod_btn.getElement());

// tab
auto tab = notebook->addPage(obj.getElement());
Expand Down Expand Up @@ -311,6 +329,11 @@ void SelectChannelDialog::setSelectedChannel(IndirectChannel _channel)
this->ui_.twitch.live->setFocus();
}
break;
case Channel::Type::TwitchAutomod: {
this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui_.twitch.automod->setFocus();
}
break;
case Channel::Type::Irc: {
this->ui_.notebook->selectIndex(TAB_IRC);
this->ui_.irc.channel->setText(_channel.get()->getName());
Expand Down Expand Up @@ -378,6 +401,10 @@ IndirectChannel SelectChannelDialog::getSelectedChannel() const
{
return app->twitch->liveChannel;
}
else if (this->ui_.twitch.automod->isChecked())
{
return app->twitch->automodChannel;
}
}
break;
case TAB_IRC: {
Expand Down Expand Up @@ -442,9 +469,9 @@ bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched,
this->dialog->ui_.twitch.whispers->setFocus();
return true;
}
else if (widget == this->dialog->ui_.twitch.live)
else if (widget == this->dialog->ui_.twitch.automod)
{
// Special case for when current selection is "Live" (the last entry in the list), next wrap is Channel, but we need to select its edit box
// Special case for when current selection is "AutoMod" (the last entry in the list), next wrap is Channel, but we need to select its edit box
this->dialog->ui_.twitch.channel->setFocus();
return true;
}
Expand All @@ -463,7 +490,7 @@ bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched,
if (widget == this->dialog->ui_.twitch.channelName)
{
// Special case for when current selection is the "Channel" entry's edit box since the Edit box actually has the focus
this->dialog->ui_.twitch.live->setFocus();
this->dialog->ui_.twitch.automod->setFocus();
return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/widgets/dialogs/SelectChannelDialog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class SelectChannelDialog final : public BaseWindow
QRadioButton *mentions;
QRadioButton *watching;
QRadioButton *live;
QRadioButton *automod;
} twitch;
struct {
QLineEdit *channel;
Expand Down
23 changes: 15 additions & 8 deletions src/widgets/helper/ChannelView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1282,14 +1282,16 @@ MessageElementFlags ChannelView::getFlags() const
flags.set(MessageElementFlag::ModeratorTools);
}
if (this->underlyingChannel_ == app->twitch->mentionsChannel ||
this->underlyingChannel_ == app->twitch->liveChannel)
this->underlyingChannel_ == app->twitch->liveChannel ||
this->underlyingChannel_ == app->twitch->automodChannel)
{
flags.set(MessageElementFlag::ChannelName);
flags.unset(MessageElementFlag::ChannelPointReward);
}
}

if (this->sourceChannel_ == app->twitch->mentionsChannel)
if (this->sourceChannel_ == app->twitch->mentionsChannel ||
this->sourceChannel_ == app->twitch->automodChannel)
{
flags.set(MessageElementFlag::ChannelName);
}
Expand Down Expand Up @@ -2347,11 +2349,13 @@ void ChannelView::addMessageContextMenuItems(QMenu *menu,
this->split_;
bool isMentions =
this->channel()->getType() == Channel::Type::TwitchMentions;
if (isSearch || isMentions || isReplyOrUserCard)
bool isAutomod = this->channel()->getType() == Channel::Type::TwitchAutomod;
if (isSearch || isMentions || isReplyOrUserCard || isAutomod)
{
const auto &messagePtr = layout->getMessagePtr();
menu->addAction("&Go to message", [this, &messagePtr, isSearch,
isMentions, isReplyOrUserCard] {
isMentions, isReplyOrUserCard,
isAutomod] {
if (isSearch)
{
if (const auto &search =
Expand All @@ -2360,16 +2364,17 @@ void ChannelView::addMessageContextMenuItems(QMenu *menu,
search->goToMessage(messagePtr);
}
}
else if (isMentions)
else if (isMentions || isAutomod)
{
getApp()->windows->scrollToMessage(messagePtr);
}
else if (isReplyOrUserCard)
{
// If the thread is in the mentions channel,
// If the thread is in the mentions or automod channel,
// we need to find the original split.
if (this->split_->getChannel()->getType() ==
Channel::Type::TwitchMentions)
const auto type = this->split_->getChannel()->getType();
if (type == Channel::Type::TwitchMentions ||
type == Channel::Type::TwitchAutomod)
{
getApp()->windows->scrollToMessage(messagePtr);
}
Expand Down Expand Up @@ -2606,6 +2611,8 @@ bool ChannelView::mayContainMessage(const MessagePtr &message)
return message->flags.has(MessageFlag::Highlighted);
case Channel::Type::TwitchLive:
return message->flags.has(MessageFlag::System);
case Channel::Type::TwitchAutomod:
return message->flags.has(MessageFlag::AutoMod);
case Channel::Type::TwitchEnd: // TODO: not used?
case Channel::Type::None: // Unspecific
case Channel::Type::Misc: // Unspecific
Expand Down
8 changes: 7 additions & 1 deletion src/widgets/helper/SearchPopup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ void SearchPopup::goToMessage(const MessagePtr &message)
{
for (const auto &view : this->searchChannels_)
{
if (view.get().channel()->getType() == Channel::Type::TwitchMentions)
const auto type = view.get().channel()->getType();
if (type == Channel::Type::TwitchMentions ||
type == Channel::Type::TwitchAutomod)
{
getApp()->windows->scrollToMessage(message);
return;
Expand Down Expand Up @@ -166,6 +168,10 @@ void SearchPopup::updateWindowTitle()
{
historyName = "multiple channels'";
}
else if (this->channelName_ == "/automod")
{
historyName = "automod";
}
else if (this->channelName_ == "/mentions")
{
historyName = "mentions";
Expand Down
5 changes: 4 additions & 1 deletion src/widgets/splits/Split.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,10 @@ void Split::showSearch(bool singleChannel)
auto container = dynamic_cast<SplitContainer *>(notebook.getPageAt(i));
for (auto split : container->getSplits())
{
popup->addChannel(split->getChannelView());
if (split->channel_.getType() != Channel::Type::TwitchAutomod)
{
popup->addChannel(split->getChannelView());
}
}
}

Expand Down

0 comments on commit 44abe6b

Please sign in to comment.