Skip to content

Commit 5209e47

Browse files
iProdigyNerixyzpajlada
authored
Improve reply popup after thread update (#4923)
Co-authored-by: nerix <nero.9@hotmail.de> Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
1 parent 9dd83b0 commit 5209e47

File tree

12 files changed

+176
-58
lines changed

12 files changed

+176
-58
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Minor: The account switcher is now styled to match your theme. (#4817)
88
- Minor: Add an invisible resize handle to the bottom of frameless user info popups and reply thread popups. (#4795)
99
- Minor: The installer now checks for the VC Runtime version and shows more info when it's outdated. (#4847)
10+
- Minor: Add menu actions to reply directly to a message or the original thread root. (#4923)
1011
- Minor: The `/reply` command now replies to the latest message of the user. (#4919)
1112
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
1213
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
@@ -29,6 +30,7 @@
2930
- Bugfix: Fixed headers of tables in the settings switching to bold text when selected. (#4913)
3031
- Bugfix: Fixed tooltips appearing too large and/or away from the cursor. (#4920)
3132
- Bugfix: Fixed a crash when clicking `More messages below` button in a usercard and closing it quickly. (#4933)
33+
- Bugfix: Fixed thread popup window missing messages for nested threads. (#4923)
3234
- Dev: Change clang-format from v14 to v16. (#4929)
3335
- Dev: Fixed UTF16 encoding of `modes` file for the installer. (#4791)
3436
- Dev: Temporarily disable High DPI scaling on Qt6 builds on Windows. (#4767)

src/messages/Message.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ enum class MessageFlag : int64_t {
5353
};
5454
using MessageFlags = FlagsEnum<MessageFlag>;
5555

56+
struct Message;
57+
using MessagePtr = std::shared_ptr<const Message>;
5658
struct Message {
5759
Message();
5860
~Message();
@@ -88,12 +90,11 @@ struct Message {
8890
// the reply thread will be cleaned up by the TwitchChannel.
8991
// The root of the thread does not have replyThread set.
9092
std::shared_ptr<MessageThread> replyThread;
93+
MessagePtr replyParent;
9194
uint32_t count = 1;
9295
std::vector<std::unique_ptr<MessageElement>> elements;
9396

9497
ScrollbarHighlight getScrollBarHighlight() const;
9598
};
9699

97-
using MessagePtr = std::shared_ptr<const Message>;
98-
99100
} // namespace chatterino

src/providers/twitch/IrcMessageHandler.cpp

+107-31
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,12 @@ void populateReply(TwitchChannel *channel, Communi::IrcMessage *message,
243243
TwitchMessageBuilder &builder)
244244
{
245245
const auto &tags = message->tags();
246-
if (const auto it = tags.find("reply-parent-msg-id"); it != tags.end())
246+
if (const auto it = tags.find("reply-thread-parent-msg-id");
247+
it != tags.end())
247248
{
248249
const QString replyID = it.value().toString();
249250
auto threadIt = channel->threads().find(replyID);
251+
std::shared_ptr<MessageThread> rootThread;
250252
if (threadIt != channel->threads().end())
251253
{
252254
auto owned = threadIt->second.lock();
@@ -256,43 +258,80 @@ void populateReply(TwitchChannel *channel, Communi::IrcMessage *message,
256258
updateReplyParticipatedStatus(tags, message->nick(), builder,
257259
owned, false);
258260
builder.setThread(owned);
259-
return;
261+
rootThread = owned;
260262
}
261263
}
262264

263-
MessagePtr foundMessage;
264-
265-
// Thread does not yet exist, find root reply and create thread.
266-
// Linear search is justified by the infrequent use of replies
267-
for (const auto &otherMsg : otherLoaded)
265+
if (!rootThread)
268266
{
269-
if (otherMsg->id == replyID)
267+
MessagePtr foundMessage;
268+
269+
// Thread does not yet exist, find root reply and create thread.
270+
// Linear search is justified by the infrequent use of replies
271+
for (const auto &otherMsg : otherLoaded)
270272
{
271-
// Found root reply message
272-
foundMessage = otherMsg;
273-
break;
273+
if (otherMsg->id == replyID)
274+
{
275+
// Found root reply message
276+
foundMessage = otherMsg;
277+
break;
278+
}
274279
}
275-
}
276280

277-
if (!foundMessage)
278-
{
279-
// We didn't find the reply root message in the otherLoaded messages
280-
// which are typically the already-parsed recent messages from the
281-
// Recent Messages API. We could have a really old message that
282-
// still exists being replied to, so check for that here.
283-
foundMessage = channel->findMessage(replyID);
281+
if (!foundMessage)
282+
{
283+
// We didn't find the reply root message in the otherLoaded messages
284+
// which are typically the already-parsed recent messages from the
285+
// Recent Messages API. We could have a really old message that
286+
// still exists being replied to, so check for that here.
287+
foundMessage = channel->findMessage(replyID);
288+
}
289+
290+
if (foundMessage)
291+
{
292+
std::shared_ptr<MessageThread> newThread =
293+
std::make_shared<MessageThread>(foundMessage);
294+
updateReplyParticipatedStatus(tags, message->nick(), builder,
295+
newThread, true);
296+
297+
builder.setThread(newThread);
298+
rootThread = newThread;
299+
// Store weak reference to thread in channel
300+
channel->addReplyThread(newThread);
301+
}
284302
}
285303

286-
if (foundMessage)
304+
if (const auto parentIt = tags.find("reply-parent-msg-id");
305+
parentIt != tags.end())
287306
{
288-
std::shared_ptr<MessageThread> newThread =
289-
std::make_shared<MessageThread>(foundMessage);
290-
updateReplyParticipatedStatus(tags, message->nick(), builder,
291-
newThread, true);
292-
293-
builder.setThread(newThread);
294-
// Store weak reference to thread in channel
295-
channel->addReplyThread(newThread);
307+
const QString parentID = parentIt.value().toString();
308+
if (replyID == parentID)
309+
{
310+
if (rootThread)
311+
{
312+
builder.setParent(rootThread->root());
313+
}
314+
}
315+
else
316+
{
317+
auto parentThreadIt = channel->threads().find(parentID);
318+
if (parentThreadIt != channel->threads().end())
319+
{
320+
auto thread = parentThreadIt->second.lock();
321+
if (thread)
322+
{
323+
builder.setParent(thread->root());
324+
}
325+
}
326+
else
327+
{
328+
auto parent = channel->findMessage(parentID);
329+
if (parent)
330+
{
331+
builder.setParent(parent);
332+
}
333+
}
334+
}
296335
}
297336
}
298337
}
@@ -1283,17 +1322,20 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
12831322
TwitchMessageBuilder builder(chan.get(), message, args, content, isAction);
12841323
builder.setMessageOffset(messageOffset);
12851324

1286-
if (const auto it = tags.find("reply-parent-msg-id"); it != tags.end())
1325+
if (const auto it = tags.find("reply-thread-parent-msg-id");
1326+
it != tags.end())
12871327
{
12881328
const QString replyID = it.value().toString();
1289-
auto threadIt = channel->threads_.find(replyID);
1290-
if (threadIt != channel->threads_.end() && !threadIt->second.expired())
1329+
auto threadIt = channel->threads().find(replyID);
1330+
std::shared_ptr<MessageThread> rootThread;
1331+
if (threadIt != channel->threads().end() && !threadIt->second.expired())
12911332
{
12921333
// Thread already exists (has a reply)
12931334
auto thread = threadIt->second.lock();
12941335
updateReplyParticipatedStatus(tags, message->nick(), builder,
12951336
thread, false);
12961337
builder.setThread(thread);
1338+
rootThread = thread;
12971339
}
12981340
else
12991341
{
@@ -1307,10 +1349,44 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *message,
13071349
newThread, true);
13081350

13091351
builder.setThread(newThread);
1352+
rootThread = newThread;
13101353
// Store weak reference to thread in channel
13111354
channel->addReplyThread(newThread);
13121355
}
13131356
}
1357+
1358+
if (const auto parentIt = tags.find("reply-parent-msg-id");
1359+
parentIt != tags.end())
1360+
{
1361+
const QString parentID = parentIt.value().toString();
1362+
if (replyID == parentID)
1363+
{
1364+
if (rootThread)
1365+
{
1366+
builder.setParent(rootThread->root());
1367+
}
1368+
}
1369+
else
1370+
{
1371+
auto parentThreadIt = channel->threads().find(parentID);
1372+
if (parentThreadIt != channel->threads().end())
1373+
{
1374+
auto thread = parentThreadIt->second.lock();
1375+
if (thread)
1376+
{
1377+
builder.setParent(thread->root());
1378+
}
1379+
}
1380+
else
1381+
{
1382+
auto parent = channel->findMessage(parentID);
1383+
if (parent)
1384+
{
1385+
builder.setParent(parent);
1386+
}
1387+
}
1388+
}
1389+
}
13141390
}
13151391

13161392
if (isSub || !builder.isIgnored())

src/providers/twitch/TwitchMessageBuilder.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -623,15 +623,24 @@ void TwitchMessageBuilder::parseThread()
623623
{
624624
// set references
625625
this->message().replyThread = this->thread_;
626+
this->message().replyParent = this->parent_;
626627
this->thread_->addToThread(this->weakOf());
627628

628629
// enable reply flag
629630
this->message().flags.set(MessageFlag::ReplyMessage);
630631

631-
const auto &threadRoot = this->thread_->root();
632+
MessagePtr threadRoot;
633+
if (!this->parent_)
634+
{
635+
threadRoot = this->thread_->root();
636+
}
637+
else
638+
{
639+
threadRoot = this->parent_;
640+
}
632641

633642
QString usernameText = SharedMessageBuilder::stylizeUsername(
634-
threadRoot->loginName, *threadRoot.get());
643+
threadRoot->loginName, *threadRoot);
635644

636645
this->emplace<ReplyCurveElement>();
637646

@@ -1811,6 +1820,11 @@ void TwitchMessageBuilder::setThread(std::shared_ptr<MessageThread> thread)
18111820
this->thread_ = std::move(thread);
18121821
}
18131822

1823+
void TwitchMessageBuilder::setParent(MessagePtr parent)
1824+
{
1825+
this->parent_ = std::move(parent);
1826+
}
1827+
18141828
void TwitchMessageBuilder::setMessageOffset(int offset)
18151829
{
18161830
this->messageOffset_ = offset;

src/providers/twitch/TwitchMessageBuilder.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class TwitchMessageBuilder : public SharedMessageBuilder
5858
MessagePtr build() override;
5959

6060
void setThread(std::shared_ptr<MessageThread> thread);
61+
void setParent(MessagePtr parent);
6162
void setMessageOffset(int offset);
6263

6364
static void appendChannelPointRewardMessage(
@@ -131,6 +132,7 @@ class TwitchMessageBuilder : public SharedMessageBuilder
131132
bool bitsStacked = false;
132133
bool historicalMessage_ = false;
133134
std::shared_ptr<MessageThread> thread_;
135+
MessagePtr parent_;
134136

135137
/**
136138
* Starting offset to be used on index-based operations on `originalMessage_`.

src/singletons/helper/LoggingChannel.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,17 @@ void LoggingChannel::addMessage(MessagePtr message)
132132
qsizetype colonIndex = messageText.indexOf(':');
133133
if (colonIndex != -1)
134134
{
135-
QString rootMessageChatter =
136-
message->replyThread->root()->loginName;
135+
QString rootMessageChatter;
136+
if (message->replyParent)
137+
{
138+
rootMessageChatter = message->replyParent->loginName;
139+
}
140+
else
141+
{
142+
// we actually want to use 'reply-parent-user-login' tag here,
143+
// but it's not worth storing just for this edge case
144+
rootMessageChatter = message->replyThread->root()->loginName;
145+
}
137146
messageText.insert(colonIndex + 1, " @" + rootMessageChatter);
138147
}
139148
}

src/widgets/dialogs/ReplyThreadPopup.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
189189
void ReplyThreadPopup::setThread(std::shared_ptr<MessageThread> thread)
190190
{
191191
this->thread_ = std::move(thread);
192-
this->ui_.replyInput->setReply(this->thread_);
192+
this->ui_.replyInput->setReply(this->thread_->root());
193193
this->addMessagesFromThread();
194194
this->updateInputUI();
195195

src/widgets/helper/ChannelView.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -2331,6 +2331,10 @@ void ChannelView::addMessageContextMenuItems(QMenu *menu,
23312331

23322332
if (messagePtr->replyThread != nullptr)
23332333
{
2334+
menu->addAction("Reply to &original thread", [this, &messagePtr] {
2335+
this->setInputReply(messagePtr->replyThread->root());
2336+
});
2337+
23342338
menu->addAction("View &thread", [this, &messagePtr] {
23352339
this->showReplyThreadPopup(messagePtr);
23362340
});
@@ -2871,19 +2875,17 @@ void ChannelView::setInputReply(const MessagePtr &message)
28712875
return;
28722876
}
28732877

2874-
auto thread = message->replyThread;
2875-
2876-
if (!thread)
2878+
if (!message->replyThread)
28772879
{
28782880
// Message did not already have a thread attached, try to find or create one
28792881
if (auto *tc =
28802882
dynamic_cast<TwitchChannel *>(this->underlyingChannel_.get()))
28812883
{
2882-
thread = tc->getOrCreateThread(message);
2884+
tc->getOrCreateThread(message);
28832885
}
28842886
else if (auto *tc = dynamic_cast<TwitchChannel *>(this->channel_.get()))
28852887
{
2886-
thread = tc->getOrCreateThread(message);
2888+
tc->getOrCreateThread(message);
28872889
}
28882890
else
28892891
{
@@ -2894,7 +2896,7 @@ void ChannelView::setInputReply(const MessagePtr &message)
28942896
}
28952897
}
28962898

2897-
this->split_->setInputReply(thread);
2899+
this->split_->setInputReply(message);
28982900
}
28992901

29002902
void ChannelView::showReplyThreadPopup(const MessagePtr &message)

src/widgets/splits/Split.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1542,7 +1542,7 @@ void Split::drag()
15421542
stopDraggingSplit();
15431543
}
15441544

1545-
void Split::setInputReply(const std::shared_ptr<MessageThread> &reply)
1545+
void Split::setInputReply(const MessagePtr &reply)
15461546
{
15471547
this->input_->setReply(reply);
15481548
}

src/widgets/splits/Split.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
namespace chatterino {
1616

1717
class ChannelView;
18-
class MessageThread;
1918
class SplitHeader;
2019
class SplitInput;
2120
class SplitContainer;
@@ -75,7 +74,7 @@ class Split : public BaseWidget
7574

7675
void setContainer(SplitContainer *container);
7776

78-
void setInputReply(const std::shared_ptr<MessageThread> &reply);
77+
void setInputReply(const MessagePtr &reply);
7978

8079
static pajlada::Signals::Signal<Qt::KeyboardModifiers>
8180
modifierStatusChanged;

0 commit comments

Comments
 (0)