fix: Display Sent IRC Messages Like Received Ones (#4027)

This commit is contained in:
nerix 2022-10-01 17:36:22 +02:00 committed by GitHub
parent a275a1793a
commit ba586f01d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 230 additions and 186 deletions

View file

@ -49,6 +49,7 @@
- Minor: Migrated /untimeout to Helix API. (#4026) - Minor: Migrated /untimeout to Helix API. (#4026)
- Minor: Migrated /unban to Helix API. (#4026) - Minor: Migrated /unban to Helix API. (#4026)
- Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716) - Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716)
- Bugfix: Fixed `Smooth scrolling on new messages` setting sometimes hiding messages. (#4028)
- Bugfix: Fixed a crash that can occur when closing and quickly reopening a split, then running a command. (#3852) - Bugfix: Fixed a crash that can occur when closing and quickly reopening a split, then running a command. (#3852)
- Bugfix: Fixed a crash that can occur when changing channels. (#3799) - Bugfix: Fixed a crash that can occur when changing channels. (#3799)
- Bugfix: Fixed viewers list search not working when used before loading finishes. (#3774) - Bugfix: Fixed viewers list search not working when used before loading finishes. (#3774)
@ -71,8 +72,8 @@
- Bugfix: Fixed crash related to logging IRC channels (#3918) - Bugfix: Fixed crash related to logging IRC channels (#3918)
- Bugfix: Mentions of "You" in timeouts will link to your own user now instead of the user "You". (#3922) - Bugfix: Mentions of "You" in timeouts will link to your own user now instead of the user "You". (#3922)
- Bugfix: Fixed emoji popup not being shown in IRC channels (#4021) - Bugfix: Fixed emoji popup not being shown in IRC channels (#4021)
- Bugfix: Display sent IRC messages like received ones (#4027)
- Bugfix: Fixed non-global FrankerFaceZ emotes from being loaded as global emotes. (#3921) - Bugfix: Fixed non-global FrankerFaceZ emotes from being loaded as global emotes. (#3921)
- Bugfix: Fixed `Smooth scrolling on new messages` setting sometimes hiding messages. (#4028)
- Dev: Removed official support for QMake. (#3839, #3883) - Dev: Removed official support for QMake. (#3839, #3883)
- Dev: Rewrote LimitedQueue (#3798) - Dev: Rewrote LimitedQueue (#3798)
- Dev: Overhauled highlight system by moving all checks into a Controller allowing for easier tests. (#3399, #3801, #3835) - Dev: Overhauled highlight system by moving all checks into a Controller allowing for easier tests. (#3399, #3801, #3835)

View file

@ -1,6 +1,7 @@
#include "MessageBuilder.hpp" #include "MessageBuilder.hpp"
#include "Application.hpp" #include "Application.hpp"
#include "common/IrcColors.hpp"
#include "common/LinkParser.hpp" #include "common/LinkParser.hpp"
#include "controllers/accounts/AccountController.hpp" #include "controllers/accounts/AccountController.hpp"
#include "messages/Image.hpp" #include "messages/Image.hpp"
@ -16,6 +17,14 @@
#include <QDateTime> #include <QDateTime>
namespace {
QRegularExpression IRC_COLOR_PARSE_REGEX(
"(\u0003(\\d{1,2})?(,(\\d{1,2}))?|\u000f)",
QRegularExpression::UseUnicodePropertiesOption);
} // namespace
namespace chatterino { namespace chatterino {
MessagePtr makeSystemMessage(const QString &text) MessagePtr makeSystemMessage(const QString &text)
@ -579,6 +588,163 @@ void MessageBuilder::addLink(const QString &origLink,
}); });
} }
void MessageBuilder::addIrcMessageText(const QString &text)
{
this->message().messageText = text;
auto words = text.split(' ');
MessageColor defaultColorType = MessageColor::Text;
const auto &defaultColor = defaultColorType.getColor(*getApp()->themes);
QColor textColor = defaultColor;
int fg = -1;
int bg = -1;
for (const auto &word : words)
{
if (word.isEmpty())
{
continue;
}
auto string = QString(word);
// Actually just text
auto linkString = this->matchLink(string);
auto link = Link();
if (!linkString.isEmpty())
{
this->addLink(string, linkString);
continue;
}
// Does the word contain a color changer? If so, split on it.
// Add color indicators, then combine into the same word with the color being changed
auto i = IRC_COLOR_PARSE_REGEX.globalMatch(string);
if (!i.hasNext())
{
this->addIrcWord(string, textColor);
continue;
}
int lastPos = 0;
while (i.hasNext())
{
auto match = i.next();
if (lastPos != match.capturedStart() && match.capturedStart() != 0)
{
if (fg >= 0 && fg <= 98)
{
textColor = IRC_COLORS[fg];
getApp()->themes->normalizeColor(textColor);
}
else
{
textColor = defaultColor;
}
this->addIrcWord(
string.mid(lastPos, match.capturedStart() - lastPos),
textColor, false);
lastPos = match.capturedStart() + match.capturedLength();
}
if (!match.captured(1).isEmpty())
{
fg = -1;
bg = -1;
}
if (!match.captured(2).isEmpty())
{
fg = match.captured(2).toInt(nullptr);
}
else
{
fg = -1;
}
if (!match.captured(4).isEmpty())
{
bg = match.captured(4).toInt(nullptr);
}
else if (fg == -1)
{
bg = -1;
}
lastPos = match.capturedStart() + match.capturedLength();
}
if (fg >= 0 && fg <= 98)
{
textColor = IRC_COLORS[fg];
getApp()->themes->normalizeColor(textColor);
}
else
{
textColor = defaultColor;
}
this->addIrcWord(string.mid(lastPos), textColor);
}
this->message().elements.back()->setTrailingSpace(false);
}
void MessageBuilder::addTextOrEmoji(EmotePtr emote)
{
this->emplace<EmoteElement>(emote, MessageElementFlag::EmojiAll);
}
void MessageBuilder::addTextOrEmoji(const QString &string_)
{
auto string = QString(string_);
// Actually just text
auto linkString = this->matchLink(string);
auto link = Link();
auto &&textColor = this->textColor_;
if (linkString.isEmpty())
{
if (string.startsWith('@'))
{
this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
textColor, FontStyle::ChatMediumBold);
this->emplace<TextElement>(
string, MessageElementFlag::NonBoldUsername, textColor);
}
else
{
this->emplace<TextElement>(string, MessageElementFlag::Text,
textColor);
}
}
else
{
this->addLink(string, linkString);
}
}
void MessageBuilder::addIrcWord(const QString &text, const QColor &color,
bool addSpace)
{
this->textColor_ = color;
for (auto &variant : getApp()->emotes->emojis.parse(text))
{
boost::apply_visitor(
[&](auto &&arg) {
this->addTextOrEmoji(arg);
},
variant);
if (!addSpace)
{
this->message().elements.back()->setTrailingSpace(false);
}
}
}
TextElement *MessageBuilder::emplaceSystemTextAndUpdate(const QString &text, TextElement *MessageBuilder::emplaceSystemTextAndUpdate(const QString &text,
QString &toUpdate) QString &toUpdate)
{ {

View file

@ -64,6 +64,13 @@ public:
QString matchLink(const QString &string); QString matchLink(const QString &string);
void addLink(const QString &origLink, const QString &matchedLink); void addLink(const QString &origLink, const QString &matchedLink);
/**
* Adds the text, applies irc colors, adds links,
* and updates the message's messageText.
* See https://modern.ircdocs.horse/formatting.html
*/
void addIrcMessageText(const QString &text);
template <typename T, typename... Args> template <typename T, typename... Args>
// clang-format off // clang-format off
// clang-format can be enabled once clang-format v11+ has been installed in CI // clang-format can be enabled once clang-format v11+ has been installed in CI
@ -79,6 +86,12 @@ public:
return pointer; return pointer;
} }
protected:
virtual void addTextOrEmoji(EmotePtr emote);
virtual void addTextOrEmoji(const QString &value);
MessageColor textColor_ = MessageColor::Text;
private: private:
// Helper method that emplaces some text stylized as system text // Helper method that emplaces some text stylized as system text
// and then appends that text to the QString parameter "toUpdate". // and then appends that text to the QString parameter "toUpdate".
@ -86,6 +99,17 @@ private:
TextElement *emplaceSystemTextAndUpdate(const QString &text, TextElement *emplaceSystemTextAndUpdate(const QString &text,
QString &toUpdate); QString &toUpdate);
/**
* This will add the text and replace any emojis
* with an emoji emote-element.
*
* @param text Text to add
* @param color Color of the text
* @param addSpace true if a trailing space should be added after emojis
*/
void addIrcWord(const QString &text, const QColor &color,
bool addSpace = true);
std::shared_ptr<Message> message_; std::shared_ptr<Message> message_;
}; };

View file

@ -181,41 +181,6 @@ void SharedMessageBuilder::parseHighlights()
} }
} }
void SharedMessageBuilder::addTextOrEmoji(EmotePtr emote)
{
this->emplace<EmoteElement>(emote, MessageElementFlag::EmojiAll);
}
void SharedMessageBuilder::addTextOrEmoji(const QString &string_)
{
auto string = QString(string_);
// Actually just text
auto linkString = this->matchLink(string);
auto link = Link();
auto &&textColor = this->textColor_;
if (linkString.isEmpty())
{
if (string.startsWith('@'))
{
this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
textColor, FontStyle::ChatMediumBold);
this->emplace<TextElement>(
string, MessageElementFlag::NonBoldUsername, textColor);
}
else
{
this->emplace<TextElement>(string, MessageElementFlag::Text,
textColor);
}
}
else
{
this->addLink(string, linkString);
}
}
void SharedMessageBuilder::appendChannelName() void SharedMessageBuilder::appendChannelName()
{ {
QString channelName("#" + this->channel->getName()); QString channelName("#" + this->channel->getName());

View file

@ -53,9 +53,6 @@ protected:
// parseHighlights only updates the visual state of the message, but leaves the playing of alerts and sounds to the triggerHighlights function // parseHighlights only updates the visual state of the message, but leaves the playing of alerts and sounds to the triggerHighlights function
virtual void parseHighlights(); virtual void parseHighlights();
virtual void addTextOrEmoji(EmotePtr emote);
virtual void addTextOrEmoji(const QString &value);
void appendChannelName(); void appendChannelName();
Channel *channel; Channel *channel;
@ -67,7 +64,6 @@ protected:
const bool action_{}; const bool action_{};
QColor usernameColor_ = {153, 153, 153}; QColor usernameColor_ = {153, 153, 153};
MessageColor textColor_ = MessageColor::Text;
bool highlightAlert_ = false; bool highlightAlert_ = false;
bool highlightSound_ = false; bool highlightSound_ = false;

View file

@ -4,7 +4,9 @@
#include "messages/Message.hpp" #include "messages/Message.hpp"
#include "messages/MessageBuilder.hpp" #include "messages/MessageBuilder.hpp"
#include "providers/irc/IrcCommands.hpp" #include "providers/irc/IrcCommands.hpp"
#include "providers/irc/IrcMessageBuilder.hpp"
#include "providers/irc/IrcServer.hpp" #include "providers/irc/IrcServer.hpp"
#include "util/Helpers.hpp"
namespace chatterino { namespace chatterino {
@ -33,20 +35,42 @@ void IrcChannel::sendMessage(const QString &message)
} }
else else
{ {
if (this->server()) if (this->server() != nullptr)
{
this->server()->sendMessage(this->getName(), message); this->server()->sendMessage(this->getName(), message);
MessageBuilder builder; MessageBuilder builder;
builder.emplace<TimestampElement>();
const auto &nick = this->server()->nick(); builder
builder.emplace<TextElement>(nick + ":", MessageElementFlag::Username) .emplace<TextElement>("#" + this->getName(),
->setLink({Link::UserInfo, nick}); MessageElementFlag::ChannelName,
builder.emplace<TextElement>(message, MessageElementFlag::Text); MessageColor::System)
builder.message().messageText = message; ->setLink({Link::JumpToChannel, this->getName()});
builder.message().searchText = nick + ": " + message;
builder.message().loginName = nick; auto now = QDateTime::currentDateTime();
builder.message().displayName = nick; builder.emplace<TimestampElement>(now.time());
this->addMessage(builder.release()); builder.message().serverReceivedTime = now;
auto username = this->server()->nick();
builder
.emplace<TextElement>(
username + ":", MessageElementFlag::Username,
getRandomColor(username), FontStyle::ChatMediumBold)
->setLink({Link::UserInfo, username});
builder.message().loginName = username;
builder.message().displayName = username;
// message
builder.addIrcMessageText(message);
builder.message().messageText = message;
builder.message().searchText = username + ": " + message;
this->addMessage(builder.release());
}
else
{
this->addMessage(makeSystemMessage("You are not connected."));
}
} }
} }

View file

@ -16,14 +16,6 @@
#include "util/IrcHelpers.hpp" #include "util/IrcHelpers.hpp"
#include "widgets/Window.hpp" #include "widgets/Window.hpp"
namespace {
QRegularExpression IRC_COLOR_PARSE_REGEX(
"(\u0003(\\d{1,2})?(,(\\d{1,2}))?|\u000f)",
QRegularExpression::UseUnicodePropertiesOption);
} // namespace
namespace chatterino { namespace chatterino {
IrcMessageBuilder::IrcMessageBuilder( IrcMessageBuilder::IrcMessageBuilder(
@ -63,10 +55,9 @@ MessagePtr IrcMessageBuilder::build()
this->appendUsername(); this->appendUsername();
// words // message
this->addWords(this->originalMessage_.split(' ')); this->addIrcMessageText(this->originalMessage_);
this->message().messageText = this->originalMessage_;
this->message().searchText = this->message().localizedName + " " + this->message().searchText = this->message().localizedName + " " +
this->userName + ": " + this->originalMessage_; this->userName + ": " + this->originalMessage_;
@ -82,125 +73,6 @@ MessagePtr IrcMessageBuilder::build()
return this->release(); return this->release();
} }
void IrcMessageBuilder::addWords(const QStringList &words)
{
MessageColor defaultColorType = this->textColor_;
auto defaultColor = defaultColorType.getColor(*getApp()->themes);
QColor textColor = defaultColor;
int fg = -1;
int bg = -1;
for (auto word : words)
{
if (word.isEmpty())
{
continue;
}
auto string = QString(word);
// Actually just text
auto linkString = this->matchLink(string);
auto link = Link();
if (!linkString.isEmpty())
{
this->addLink(string, linkString);
continue;
}
// Does the word contain a color changer? If so, split on it.
// Add color indicators, then combine into the same word with the color being changed
auto i = IRC_COLOR_PARSE_REGEX.globalMatch(string);
if (!i.hasNext())
{
this->addText(string, textColor);
continue;
}
int lastPos = 0;
while (i.hasNext())
{
auto match = i.next();
if (lastPos != match.capturedStart() && match.capturedStart() != 0)
{
if (fg >= 0 && fg <= 98)
{
textColor = IRC_COLORS[fg];
getApp()->themes->normalizeColor(textColor);
}
else
{
textColor = defaultColor;
}
this->addText(
string.mid(lastPos, match.capturedStart() - lastPos),
textColor, false);
lastPos = match.capturedStart() + match.capturedLength();
}
if (!match.captured(1).isEmpty())
{
fg = -1;
bg = -1;
}
if (!match.captured(2).isEmpty())
{
fg = match.captured(2).toInt(nullptr);
}
else
{
fg = -1;
}
if (!match.captured(4).isEmpty())
{
bg = match.captured(4).toInt(nullptr);
}
else if (fg == -1)
{
bg = -1;
}
lastPos = match.capturedStart() + match.capturedLength();
}
if (fg >= 0 && fg <= 98)
{
textColor = IRC_COLORS[fg];
getApp()->themes->normalizeColor(textColor);
}
else
{
textColor = defaultColor;
}
this->addText(string.mid(lastPos), textColor);
}
this->message().elements.back()->setTrailingSpace(false);
}
void IrcMessageBuilder::addText(const QString &text, const QColor &color,
bool addSpace)
{
this->textColor_ = color;
for (auto &variant : getApp()->emotes->emojis.parse(text))
{
boost::apply_visitor(
[&](auto &&arg) {
this->addTextOrEmoji(arg);
},
variant);
if (!addSpace)
{
this->message().elements.back()->setTrailingSpace(false);
}
}
}
void IrcMessageBuilder::appendUsername() void IrcMessageBuilder::appendUsername()
{ {
QString username = this->userName; QString username = this->userName;

View file

@ -40,10 +40,6 @@ public:
private: private:
void appendUsername(); void appendUsername();
void addWords(const QStringList &words);
void addText(const QString &text, const QColor &color,
bool addSpace = true);
}; };
} // namespace chatterino } // namespace chatterino