diff --git a/resources/buttons/trashCan.png b/resources/buttons/trashCan.png
new file mode 100644
index 00000000..fd1bce3a
Binary files /dev/null and b/resources/buttons/trashCan.png differ
diff --git a/resources/buttons/trashcan.svg b/resources/buttons/trashcan.svg
new file mode 100644
index 00000000..e225ee4e
--- /dev/null
+++ b/resources/buttons/trashcan.svg
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+ Trashcan top
+
+
+
+
+
+
+
diff --git a/resources/resources_autogenerated.qrc b/resources/resources_autogenerated.qrc
index 8aed98b9..96204e34 100644
--- a/resources/resources_autogenerated.qrc
+++ b/resources/resources_autogenerated.qrc
@@ -24,6 +24,7 @@
buttons/modModeEnabled.png
buttons/modModeEnabled2.png
buttons/timeout.png
+ buttons/trashCan.png
buttons/unban.png
buttons/unmod.png
buttons/update.png
diff --git a/src/Application.cpp b/src/Application.cpp
index 2870c6ed..d92e6e89 100644
--- a/src/Application.cpp
+++ b/src/Application.cpp
@@ -264,6 +264,7 @@ void Application::initPubsub()
auto msg = MessageBuilder(action).release();
postToThread([chan, msg] { chan->addMessage(msg); });
+ chan->deleteMessage(msg->id);
});
this->twitch.pubsub->start();
diff --git a/src/autogenerated/ResourcesAutogen.cpp b/src/autogenerated/ResourcesAutogen.cpp
index 34cf039e..59f5fce7 100644
--- a/src/autogenerated/ResourcesAutogen.cpp
+++ b/src/autogenerated/ResourcesAutogen.cpp
@@ -18,6 +18,7 @@ Resources2::Resources2()
this->buttons.modModeEnabled = QPixmap(":/buttons/modModeEnabled.png");
this->buttons.modModeEnabled2 = QPixmap(":/buttons/modModeEnabled2.png");
this->buttons.timeout = QPixmap(":/buttons/timeout.png");
+ this->buttons.trashCan = QPixmap(":/buttons/trashCan.png");
this->buttons.unban = QPixmap(":/buttons/unban.png");
this->buttons.unmod = QPixmap(":/buttons/unmod.png");
this->buttons.update = QPixmap(":/buttons/update.png");
diff --git a/src/autogenerated/ResourcesAutogen.hpp b/src/autogenerated/ResourcesAutogen.hpp
index fbbb2fbf..1c8a0bce 100644
--- a/src/autogenerated/ResourcesAutogen.hpp
+++ b/src/autogenerated/ResourcesAutogen.hpp
@@ -24,6 +24,7 @@ public:
QPixmap modModeEnabled;
QPixmap modModeEnabled2;
QPixmap timeout;
+ QPixmap trashCan;
QPixmap unban;
QPixmap unmod;
QPixmap update;
diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp
index 905bd1b6..caa43275 100644
--- a/src/common/Channel.cpp
+++ b/src/common/Channel.cpp
@@ -212,6 +212,25 @@ void Channel::replaceMessage(MessagePtr message, MessagePtr replacement)
}
}
+void Channel::deleteMessage(QString messageID)
+{
+ LimitedQueueSnapshot snapshot = this->getMessageSnapshot();
+ int snapshotLength = snapshot.size();
+
+ int end = std::max(0, snapshotLength - 200);
+
+ for (int i = snapshotLength - 1; i >= end; --i)
+ {
+ auto &s = snapshot[i];
+
+ if (s->id == messageID)
+ {
+ s->flags.set(MessageFlag::Disabled);
+ break;
+ }
+ }
+}
+
void Channel::addRecentChatter(const MessagePtr &message)
{
}
diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp
index c45d9c97..9abc668e 100644
--- a/src/common/Channel.hpp
+++ b/src/common/Channel.hpp
@@ -62,6 +62,7 @@ public:
void addOrReplaceTimeout(MessagePtr message);
void disableAllMessages();
void replaceMessage(MessagePtr message, MessagePtr replacement);
+ void deleteMessage(QString messageID);
QStringList modList;
diff --git a/src/controllers/moderationactions/ModerationAction.cpp b/src/controllers/moderationactions/ModerationAction.cpp
index 0b6418a5..199ea552 100644
--- a/src/controllers/moderationactions/ModerationAction.cpp
+++ b/src/controllers/moderationactions/ModerationAction.cpp
@@ -73,6 +73,10 @@ ModerationAction::ModerationAction(const QString &action)
{
this->image_ = Image::fromPixmap(getApp()->resources->buttons.ban);
}
+ else if (action.startsWith("/delete"))
+ {
+ this->image_ = Image::fromPixmap(getApp()->resources->buttons.trashCan);
+ }
else
{
QString xD = action;
diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp
index 7e89c6b4..2fda025a 100644
--- a/src/providers/twitch/IrcMessageHandler.cpp
+++ b/src/providers/twitch/IrcMessageHandler.cpp
@@ -266,6 +266,41 @@ void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message)
}
}
+void IrcMessageHandler::handleClearMessageMessage(Communi::IrcMessage *message)
+{
+ // check parameter count
+ if (message->parameters().length() < 1)
+ {
+ return;
+ }
+
+ QString chanName;
+ if (!trimChannelName(message->parameter(0), chanName))
+ {
+ return;
+ }
+
+ auto app = getApp();
+
+ // get channel
+ auto chan = app->twitch.server->getChannelOrEmpty(chanName);
+
+ if (chan->isEmpty())
+ {
+ log("[IrcMessageHandler:handleClearMessageMessage] Twitch channel {} "
+ "not "
+ "found",
+ chanName);
+ return;
+ }
+
+ auto tags = message->tags();
+
+ QString targetID = tags.value("target-msg-id").toString();
+
+ chan->deleteMessage(targetID);
+}
+
void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
{
auto app = getApp();
@@ -516,7 +551,17 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
return;
}
- channel->addMessage(msg);
+ QString tags = message->tags().value("msg-id", "").toString();
+ if (tags == "bad_delete_message_error" || tags == "usage_delete")
+ {
+ channel->addMessage(makeSystemMessage(
+ "Usage: \"/delete \" - can't take more "
+ "than one argument"));
+ }
+ else
+ {
+ channel->addMessage(msg);
+ }
}
}
diff --git a/src/providers/twitch/IrcMessageHandler.hpp b/src/providers/twitch/IrcMessageHandler.hpp
index 0474f097..861ee734 100644
--- a/src/providers/twitch/IrcMessageHandler.hpp
+++ b/src/providers/twitch/IrcMessageHandler.hpp
@@ -27,6 +27,7 @@ public:
void handleRoomStateMessage(Communi::IrcMessage *message);
void handleClearChatMessage(Communi::IrcMessage *message);
+ void handleClearMessageMessage(Communi::IrcMessage *message);
void handleUserStateMessage(Communi::IrcMessage *message);
void handleWhisperMessage(Communi::IrcMessage *message);
diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp
index 204cf6c0..b935a283 100644
--- a/src/providers/twitch/TwitchMessageBuilder.cpp
+++ b/src/providers/twitch/TwitchMessageBuilder.cpp
@@ -580,7 +580,7 @@ void TwitchMessageBuilder::parseMessageID()
if (iterator != this->tags.end())
{
- this->messageID = iterator.value().toString();
+ this->message().id = iterator.value().toString();
}
}
@@ -607,7 +607,7 @@ void TwitchMessageBuilder::parseRoomID()
void TwitchMessageBuilder::appendChannelName()
{
QString channelName("#" + this->channel->getName());
- Link link(Link::Url, this->channel->getName() + "\n" + this->messageID);
+ Link link(Link::Url, this->channel->getName() + "\n" + this->message().id);
this->emplace(channelName, MessageElementFlag::ChannelName,
MessageColor::System) //
diff --git a/src/providers/twitch/TwitchMessageBuilder.hpp b/src/providers/twitch/TwitchMessageBuilder.hpp
index 5aa72b20..da7b3865 100644
--- a/src/providers/twitch/TwitchMessageBuilder.hpp
+++ b/src/providers/twitch/TwitchMessageBuilder.hpp
@@ -41,7 +41,6 @@ public:
MessageParseArgs args;
const QVariantMap tags;
- QString messageID;
QString userName;
bool isIgnored() const;
@@ -55,8 +54,10 @@ private:
void appendUsername();
void parseHighlights(bool isPastMsg);
- void appendTwitchEmote(const QString &emote,
- std::vector> &vec, std::vector &correctPositions);
+ void appendTwitchEmote(
+ const QString &emote,
+ std::vector> &vec,
+ std::vector &correctPositions);
Outcome tryAppendEmote(const EmoteName &name);
void addWords(
diff --git a/src/providers/twitch/TwitchServer.cpp b/src/providers/twitch/TwitchServer.cpp
index 349e4035..eaf90026 100644
--- a/src/providers/twitch/TwitchServer.cpp
+++ b/src/providers/twitch/TwitchServer.cpp
@@ -156,6 +156,10 @@ void TwitchServer::messageReceived(Communi::IrcMessage *message)
{
handler.handleClearChatMessage(message);
}
+ else if (command == "CLEARMSG")
+ {
+ handler.handleClearMessageMessage(message);
+ }
else if (command == "USERSTATE")
{
handler.handleUserStateMessage(message);
diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp
index 9578c352..a1fdf645 100644
--- a/src/widgets/helper/ChannelView.cpp
+++ b/src/widgets/helper/ChannelView.cpp
@@ -1667,7 +1667,9 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
case Link::UserAction:
{
QString value = link.value;
- value.replace("{user}", layout->getMessage()->loginName).replace("{channel}", this->channel_->getName());
+ value.replace("{user}", layout->getMessage()->loginName)
+ .replace("{channel}", this->channel_->getName())
+ .replace("{msg-id}", layout->getMessage()->id);
this->channel_->sendMessage(value);
}
break;
diff --git a/src/widgets/settingspages/ModerationPage.cpp b/src/widgets/settingspages/ModerationPage.cpp
index 3349d2e9..b44e7327 100644
--- a/src/widgets/settingspages/ModerationPage.cpp
+++ b/src/widgets/settingspages/ModerationPage.cpp
@@ -161,7 +161,8 @@ ModerationPage::ModerationPage()
// clang-format off
auto label = modMode.emplace(
"Moderation mode is enabled by clicking in a channel that you moderate. "
- "Moderation buttons can be bound to chat commands such as \"/ban {user}\", \"/timeout {user} 1000\", \"/w someusername !report {user} was bad in channel {channel}\" or any other custom text commands. ");
+ "Moderation buttons can be bound to chat commands such as \"/ban {user}\", \"/timeout {user} 1000\", \"/w someusername !report {user} was bad in channel {channel}\" or any other custom text commands. "
+ "For deleting messages use /delete {msg-id}.");
label->setWordWrap(true);
label->setStyleSheet("color: #bbb");
// clang-format on