Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Twitch's Chat Replies #3722

Merged
merged 92 commits into from
Jul 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
d9af39c
Add MessageThread functionality
dnsge May 10, 2022
74152dd
Add SingleLineTextElement
dnsge May 10, 2022
64c4661
Add reply message rendering
dnsge May 10, 2022
c9c9c97
Add flags.reply to filters
dnsge May 10, 2022
13262b7
Remove @username prefix from reply
dnsge May 10, 2022
6123740
Fix 'class' -> 'struct'
dnsge May 10, 2022
ce257eb
Add reply assets
dnsge May 10, 2022
2e2f04b
Add floating button rendering
dnsge May 10, 2022
500903d
Add simple ReplyThreadPopup
dnsge May 11, 2022
d6ff6a8
Conditional reply button rendering, some fixes
dnsge May 11, 2022
1c369db
Add mostly functional reply sending
dnsge May 11, 2022
db6c547
Automatically add new replies to popup
dnsge May 11, 2022
5344ea1
Add reply placeholder text
dnsge May 11, 2022
f546e84
Add reply context menu item
dnsge May 11, 2022
f18f43f
Add setting to hide/show message buttons
dnsge May 11, 2022
85688fa
Update CHANGELOG.md
dnsge May 11, 2022
47aab27
buildfix: Add QSize with operator+
dnsge May 11, 2022
32af6f5
buildfix: include QPainterPath
dnsge May 11, 2022
49a783b
buildfix: Maybe check if your build fix works before pushing?
dnsge May 11, 2022
a1ce259
Exclude replied message from copy
dnsge May 11, 2022
306f7a7
Don't omit @username in reply
dnsge May 11, 2022
51e478d
Conditionally show reply input
dnsge May 11, 2022
90f0b72
Consistent vbox spacing
dnsge May 11, 2022
2e7d10f
Render emojis properly in replies
dnsge May 11, 2022
327c461
Fix reply selection with mouse
dnsge May 11, 2022
fd6e520
Clicking replies brings up thread
dnsge May 11, 2022
90d1cfa
Add ChannelView Context to hide replies in thread
dnsge May 11, 2022
063276f
Change reply button render default to off
dnsge May 11, 2022
b060aa8
Autoclose reply popup, set reply popup title
dnsge May 11, 2022
18f8403
Autofocus reply input
dnsge May 11, 2022
77244aa
Reword reply button setting
dnsge May 11, 2022
77f4d77
Add /reply command
dnsge May 11, 2022
26c877f
Remove /r alias for message threads
dnsge May 14, 2022
2fc361f
Merge branch 'master' into reply-threads
dnsge May 14, 2022
936ae06
Style changes
dnsge May 17, 2022
47aa13a
Simply with setVisible
dnsge May 18, 2022
464851b
Share more logic in ReplyInput
dnsge May 18, 2022
46370c2
Readd newlines at end of resource files
dnsge May 19, 2022
5a35495
Only show option to reply when it makes sense
dnsge May 23, 2022
262ad7c
Merge branch 'master' into reply-threads
dnsge May 23, 2022
aca21a2
Use display name for inline repliess
dnsge May 24, 2022
24a44c7
Merge branch 'master' into reply-threads
dnsge May 26, 2022
f20538f
Respect username display setting
dnsge May 29, 2022
271c685
Add more resources
dnsge May 30, 2022
4aef01f
Add inline message replies
dnsge May 30, 2022
bb70d95
Move cancel reply button to right
dnsge May 30, 2022
699b277
Add discord-like reply curve
dnsge May 30, 2022
cc2bb0f
Fix rendering in reply thread popup
dnsge May 30, 2022
1ecee5c
Render reply curve using bezier curve
dnsge May 30, 2022
e6194d9
Merge branch 'master' into reply-threads
dnsge May 30, 2022
9d49406
Fix include for QPen
dnsge May 30, 2022
5af3358
Add replies for historical messages
dnsge Jun 1, 2022
b828468
Many small changes
dnsge Jun 1, 2022
9df01c4
Use std::move and change constness
dnsge Jun 5, 2022
635afde
Render replies to messages that aren't found
dnsge Jun 5, 2022
792d027
Merge branch 'master' into reply-threads
dnsge Jun 5, 2022
8c75363
Merge branch 'master' into reply-threads
dnsge Jun 7, 2022
860d17b
Merge branch 'master' into reply-threads
dnsge Jul 1, 2022
a4940ca
Avoid unneeded snapshot for finding reply
dnsge Jul 1, 2022
08fa6cb
Submodules, how do they work
dnsge Jul 1, 2022
37d9178
[/reply] Use `stripChannelName` for massaging username
pajlada Jul 2, 2022
1b97afa
[/reply] Unfuck the reversed snapshot message loop
pajlada Jul 2, 2022
ee8de91
Parse tag strings in the reply body to ensure spaces are rendered as …
pajlada Jul 2, 2022
b5d0bee
[ReplyThreadPopup] use same message flag logic as UserInfoPopup
pajlada Jul 2, 2022
f0e1bbc
Merge remote-tracking branch 'origin/master' into reply-threads
pajlada Jul 2, 2022
00533cf
Allow Escape to be used to close the reply thread popup
pajlada Jul 2, 2022
5e279d2
Hide reply button/reply context menu where needed
dnsge Jul 2, 2022
30a1c8d
Fix comment copy/paste artifact
dnsge Jul 2, 2022
cdad5a7
Extract draggable popup behavior to DraggablePopup
dnsge Jul 2, 2022
60f4cae
Use circular element for reply button
dnsge Jul 2, 2022
ca96622
Fix qmake sources
dnsge Jul 2, 2022
d2d94a2
Use proper settings listener for updating reply button visibility
dnsge Jul 3, 2022
7bbcec7
Remove floating element concept
dnsge Jul 10, 2022
3723d18
Add explanation comment to appease GitHub reviews
dnsge Jul 10, 2022
95051c0
Merge branch 'master' into reply-threads
dnsge Jul 10, 2022
e0cabce
Apply various style and optimization changes
dnsge Jul 10, 2022
c3af3fe
More code review
dnsge Jul 12, 2022
71841ca
Merge branch 'master' into reply-threads
pajlada Jul 23, 2022
becadbd
Remove ReplyCurveElement custom constructors
dnsge Jul 23, 2022
bc54625
Remove ReplyInput
dnsge Jul 23, 2022
1560671
Fix spacing and background when reply label is visible
dnsge Jul 23, 2022
ea033ff
Correctly detect changes to reply @name prefixes
dnsge Jul 23, 2022
841b3d2
Revert hotkey handler extraction
dnsge Jul 23, 2022
c0049f0
Check for empty reply like with regular messages
dnsge Jul 23, 2022
9c933cc
Merge branch 'master' into reply-threads
dnsge Jul 23, 2022
8f6b943
Attempt fix tab/autocomplete focus lose issue
dnsge Jul 24, 2022
567576b
Change autoCloseThreadPopup default to false
dnsge Jul 30, 2022
6203b6a
Fix copy/paste error
dnsge Jul 30, 2022
de18ebc
Update changelog entry
pajlada Jul 30, 2022
2ea0d8c
Merge remote-tracking branch 'origin/master' into reply-threads
pajlada Jul 30, 2022
6776417
Merge branch 'master' into reply-threads
pajlada Jul 31, 2022
db7c5eb
add warnings back
pajlada Jul 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unversioned

- Major: Added support for Twitch's Chat Replies. [Wiki Page](https://wiki.chatterino.com/Features/#message-replies) (#3722)
- Major: Added multi-channel searching to search dialog via keyboard shortcut. (Ctrl+Shift+F by default) (#3694, #3875)
- Minor: Added option to display tabs on the right and bottom. (#3847)
- Minor: Added `is:first-msg` search option. (#3700)
Expand Down
1 change: 1 addition & 0 deletions resources/buttons/cancel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/buttons/cancelDark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/buttons/replyDark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/buttons/replyDark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/buttons/replyThreadDark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/buttons/replyThreadDark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions resources/resources_autogenerated.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<file>buttons/addSplitDark.png</file>
<file>buttons/ban.png</file>
<file>buttons/banRed.png</file>
<file>buttons/cancel.svg</file>
<file>buttons/cancelDark.svg</file>
<file>buttons/clearSearch.png</file>
<file>buttons/copyDark.png</file>
<file>buttons/copyDark.svg</file>
Expand All @@ -34,6 +36,10 @@
<file>buttons/modModeDisabled2.png</file>
<file>buttons/modModeEnabled.png</file>
<file>buttons/modModeEnabled2.png</file>
<file>buttons/replyDark.png</file>
<file>buttons/replyDark.svg</file>
<file>buttons/replyThreadDark.png</file>
<file>buttons/replyThreadDark.svg</file>
<file>buttons/search.png</file>
<file>buttons/timeout.png</file>
<file>buttons/trashCan.png</file>
Expand Down
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ set(SOURCE_FILES
messages/MessageContainer.hpp
messages/MessageElement.cpp
messages/MessageElement.hpp
messages/MessageThread.cpp
messages/MessageThread.hpp

messages/SharedMessageBuilder.cpp
messages/SharedMessageBuilder.hpp
Expand Down Expand Up @@ -347,6 +349,8 @@ set(SOURCE_FILES
widgets/BaseWidget.hpp
widgets/BaseWindow.cpp
widgets/BaseWindow.hpp
widgets/DraggablePopup.cpp
widgets/DraggablePopup.hpp
widgets/FramelessEmbedWindow.cpp
widgets/FramelessEmbedWindow.hpp
widgets/Label.cpp
Expand Down Expand Up @@ -383,6 +387,8 @@ set(SOURCE_FILES
widgets/dialogs/NotificationPopup.hpp
widgets/dialogs/QualityPopup.cpp
widgets/dialogs/QualityPopup.hpp
widgets/dialogs/ReplyThreadPopup.cpp
widgets/dialogs/ReplyThreadPopup.hpp
widgets/dialogs/SelectChannelDialog.cpp
widgets/dialogs/SelectChannelDialog.hpp
widgets/dialogs/SelectChannelFiltersDialog.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/autogenerated/ResourcesAutogen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Resources2::Resources2()
this->buttons.modModeDisabled2 = QPixmap(":/buttons/modModeDisabled2.png");
this->buttons.modModeEnabled = QPixmap(":/buttons/modModeEnabled.png");
this->buttons.modModeEnabled2 = QPixmap(":/buttons/modModeEnabled2.png");
this->buttons.replyDark = QPixmap(":/buttons/replyDark.png");
this->buttons.replyThreadDark = QPixmap(":/buttons/replyThreadDark.png");
this->buttons.search = QPixmap(":/buttons/search.png");
this->buttons.timeout = QPixmap(":/buttons/timeout.png");
this->buttons.trashCan = QPixmap(":/buttons/trashCan.png");
Expand Down
2 changes: 2 additions & 0 deletions src/autogenerated/ResourcesAutogen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class Resources2 : public Singleton
QPixmap modModeDisabled2;
QPixmap modModeEnabled;
QPixmap modModeEnabled2;
QPixmap replyDark;
QPixmap replyThreadDark;
QPixmap search;
QPixmap timeout;
QPixmap trashCan;
Expand Down
7 changes: 7 additions & 0 deletions src/common/Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,13 @@ bool Channel::canSendMessage() const
return false;
}

bool Channel::isWritable() const
{
using Type = Channel::Type;
auto type = this->getType();
return type != Type::TwitchMentions && type != Type::TwitchLive;
}

void Channel::sendMessage(const QString &message)
{
}
Expand Down
4 changes: 4 additions & 0 deletions src/common/Channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class Channel : public std::enable_shared_from_this<Channel>
// SIGNALS
pajlada::Signals::Signal<const QString &, const QString &, bool &>
sendMessageSignal;
pajlada::Signals::Signal<const QString &, const QString &, const QString &,
bool &>
sendReplySignal;
pajlada::Signals::Signal<MessagePtr &> messageRemovedFromStart;
pajlada::Signals::Signal<MessagePtr &, boost::optional<MessageFlags>>
messageAppended;
Expand Down Expand Up @@ -84,6 +87,7 @@ class Channel : public std::enable_shared_from_this<Channel>

// CHANNEL INFO
virtual bool canSendMessage() const;
virtual bool isWritable() const; // whether split input will be usable
virtual void sendMessage(const QString &message);
virtual bool isMod() const;
virtual bool isBroadcaster() const;
Expand Down
1 change: 1 addition & 0 deletions src/common/Common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ using MessagePtr = std::shared_ptr<const Message>;

enum class CopyMode {
Everything,
EverythingButReplies,
OnlyTextAndEmotes,
};

Expand Down
54 changes: 53 additions & 1 deletion src/controllers/commands/CommandController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "util/StreamLink.hpp"
#include "util/Twitch.hpp"
#include "widgets/Window.hpp"
#include "widgets/dialogs/ReplyThreadPopup.hpp"
#include "widgets/dialogs/UserInfoPopup.hpp"
#include "widgets/splits/Split.hpp"

Expand Down Expand Up @@ -687,7 +688,8 @@ void CommandController::initialize(Settings &, Paths &paths)

auto *userPopup = new UserInfoPopup(
getSettings()->autoCloseUserPopup,
static_cast<QWidget *>(&(getApp()->windows->getMainWindow())));
static_cast<QWidget *>(&(getApp()->windows->getMainWindow())),
nullptr);
userPopup->setData(userName, channel);
userPopup->move(QCursor::pos());
userPopup->show();
Expand Down Expand Up @@ -1114,6 +1116,56 @@ void CommandController::initialize(Settings &, Paths &paths)
return "";
});

this->registerCommand(
"/reply", [](const QStringList &words, ChannelPtr channel) {
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel == nullptr)
{
channel->addMessage(makeSystemMessage(
"The /reply command only works in Twitch channels"));
return "";
}

if (words.size() < 3)
{
channel->addMessage(
makeSystemMessage("Usage: /reply <username> <message>"));
return "";
}

QString username = words[1];
stripChannelName(username);

auto snapshot = twitchChannel->getMessageSnapshot();
for (auto it = snapshot.rbegin(); it != snapshot.rend(); ++it)
{
const auto &msg = *it;
if (msg->loginName.compare(username, Qt::CaseInsensitive) == 0)
{
std::shared_ptr<MessageThread> thread;
// found most recent message by user
if (msg->replyThread == nullptr)
{
thread = std::make_shared<MessageThread>(msg);
twitchChannel->addReplyThread(thread);
}
else
{
thread = msg->replyThread;
}

QString reply = words.mid(2).join(" ");
twitchChannel->sendReply(reply, thread->rootId());
return "";
}
}

channel->addMessage(
makeSystemMessage("A message from that user wasn't found"));

return "";
});

#ifndef NDEBUG
this->registerCommand(
"/fakemsg",
Expand Down
1 change: 1 addition & 0 deletions src/controllers/filters/parser/FilterParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ ContextMap buildContextMap(const MessagePtr &m, chatterino::Channel *channel)
m->flags.has(MessageFlag::RedeemedChannelPointReward)},
{"flags.first_message", m->flags.has(MessageFlag::FirstMessage)},
{"flags.whisper", m->flags.has(MessageFlag::Whisper)},
{"flags.reply", m->flags.has(MessageFlag::ReplyMessage)},

{"message.content", m->messageText},
{"message.length", m->messageText.length()},
Expand Down
1 change: 1 addition & 0 deletions src/controllers/filters/parser/Tokenizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ static const QMap<QString, QString> validIdentifiersMap = {
{"flags.reward_message", "channel point reward message?"},
{"flags.first_message", "first message?"},
{"flags.whisper", "whisper message?"},
{"flags.reply", "reply message?"},
{"message.content", "message text"},
{"message.length", "message length"}};

Expand Down
2 changes: 2 additions & 0 deletions src/messages/Link.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ struct Link {
JumpToChannel,
Reconnect,
CopyToClipboard,
ReplyToMessage,
ViewThread,
};

Link();
Expand Down
6 changes: 6 additions & 0 deletions src/messages/Message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace chatterino {
class MessageElement;
class MessageThread;

enum class MessageFlag : uint32_t {
None = 0,
Expand Down Expand Up @@ -40,6 +41,7 @@ enum class MessageFlag : uint32_t {
RedeemedChannelPointReward = (1 << 21),
ShowInMentions = (1 << 22),
FirstMessage = (1 << 23),
ReplyMessage = (1 << 24),
};
using MessageFlags = FlagsEnum<MessageFlag>;

Expand Down Expand Up @@ -68,6 +70,10 @@ struct Message : boost::noncopyable {
std::vector<Badge> badges;
std::unordered_map<QString, QString> badgeInfos;
std::shared_ptr<QColor> highlightColor;
// Each reply holds a reference to the thread. When every reply is dropped,
// the reply thread will be cleaned up by the TwitchChannel.
// The root of the thread does not have replyThread set.
std::shared_ptr<MessageThread> replyThread;
uint32_t count = 1;
std::vector<std::unique_ptr<MessageElement>> elements;

Expand Down
Loading