Open usercard on mention click (#1674)

This commit is contained in:
Daniel
2020-07-18 10:03:51 -04:00
committed by GitHub
parent 276f3e1d98
commit ba06b10135
10 changed files with 175 additions and 70 deletions
+2 -3
View File
@@ -148,9 +148,8 @@ void Channel::addOrReplaceTimeout(MessagePtr message)
int count = s->count + 1;
MessageBuilder replacement(systemMessage,
message->searchText + QString(" (") +
QString::number(count) + " times)");
MessageBuilder replacement(timeoutMessage, message->searchText,
count);
replacement->timeoutUser = message->timeoutUser;
replacement->count = count;
+5
View File
@@ -63,6 +63,11 @@ void UsernameSet::insertPrefix(const QString &value)
string = value;
}
bool UsernameSet::contains(const QString &value) const
{
return this->items.count(value) == 1;
}
//
// Range
//
+2
View File
@@ -76,6 +76,8 @@ public:
std::pair<Iterator, bool> insert(const QString &value);
std::pair<Iterator, bool> insert(QString &&value);
bool contains(const QString &value) const;
private:
void insertPrefix(const QString &string);
+90 -48
View File
@@ -24,6 +24,11 @@ MessagePtr makeSystemMessage(const QString &text)
return MessageBuilder(systemMessage, text).release();
}
MessagePtr makeSystemMessage(const QString &text, const QTime &time)
{
return MessageBuilder(systemMessage, text, time).release();
}
std::pair<MessagePtr, MessagePtr> makeAutomodMessage(
const AutomodAction &action)
{
@@ -93,10 +98,11 @@ MessageBuilder::MessageBuilder()
{
}
MessageBuilder::MessageBuilder(SystemMessageTag, const QString &text)
MessageBuilder::MessageBuilder(SystemMessageTag, const QString &text,
const QTime &time)
: MessageBuilder()
{
this->emplace<TimestampElement>();
this->emplace<TimestampElement>(time);
// check system message for links
// (e.g. needed for sub ticket message in sub only mode)
@@ -120,17 +126,40 @@ MessageBuilder::MessageBuilder(SystemMessageTag, const QString &text)
this->message().searchText = text;
}
MessageBuilder::MessageBuilder(TimeoutMessageTag,
const QString &systemMessageText, int times)
: MessageBuilder()
{
QString username = systemMessageText.split(" ").at(0);
QString remainder = systemMessageText.mid(username.length() + 1);
QString text;
this->emplace<TimestampElement>();
this->emplaceSystemTextAndUpdate(username, text)
->setLink({Link::UserInfo, username});
this->emplaceSystemTextAndUpdate(
QString("%1 (%2 times)").arg(remainder.trimmed()).arg(times), text);
this->message().messageText = text;
this->message().searchText = text;
}
MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username,
const QString &durationInSeconds,
const QString &reason, bool multipleTimes)
: MessageBuilder()
{
QString fullText;
QString text;
text.append(username);
this->emplace<TimestampElement>();
this->emplaceSystemTextAndUpdate(username, fullText)
->setLink({Link::UserInfo, username});
if (!durationInSeconds.isEmpty())
{
text.append(" has been timed out");
text.append("has been timed out");
// TODO: Implement who timed the user out
@@ -144,7 +173,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username,
}
else
{
text.append(" has been permanently banned");
text.append("has been permanently banned");
}
if (reason.length() > 0)
@@ -164,11 +193,10 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username,
this->message().flags.set(MessageFlag::Timeout);
this->message().flags.set(MessageFlag::DoNotTriggerNotification);
this->message().timeoutUser = username;
this->emplace<TimestampElement>();
this->emplace<TextElement>(text, MessageElementFlag::Text,
MessageColor::System);
this->message().messageText = text;
this->message().searchText = text;
this->emplaceSystemTextAndUpdate(text, fullText);
this->message().messageText = fullText;
this->message().searchText = fullText;
}
// XXX: This does not belong in the MessageBuilder, this should be part of the TwitchMessageBuilder
@@ -187,77 +215,82 @@ MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count)
if (action.target.id == current->getUserId())
{
text.append("You were ");
this->emplaceSystemTextAndUpdate("You were", text);
if (action.isBan())
{
text.append("banned");
this->emplaceSystemTextAndUpdate("banned", text);
}
else
{
text.append(
QString("timed out for %1").arg(formatTime(action.duration)));
this->emplaceSystemTextAndUpdate(
QString("timed out for %1").arg(formatTime(action.duration)),
text);
}
if (!action.source.name.isEmpty())
{
text.append(" by ");
text.append(action.source.name);
this->emplaceSystemTextAndUpdate("by", text);
this->emplaceSystemTextAndUpdate(
action.source.name + (action.reason.isEmpty() ? "." : ":"),
text)
->setLink({Link::UserInfo, action.source.name});
}
if (action.reason.isEmpty())
if (!action.reason.isEmpty())
{
text.append(".");
}
else
{
text.append(QString(": \"%1\".").arg(action.reason));
this->emplaceSystemTextAndUpdate(
QString("\"%1\".").arg(action.reason), text);
}
}
else
{
if (action.isBan())
{
this->emplaceSystemTextAndUpdate(action.source.name, text)
->setLink({Link::UserInfo, action.source.name});
this->emplaceSystemTextAndUpdate("banned", text);
if (action.reason.isEmpty())
{
text = QString("%1 banned %2.") //
.arg(action.source.name)
.arg(action.target.name);
this->emplaceSystemTextAndUpdate(action.target.name, text)
->setLink({Link::UserInfo, action.target.name});
}
else
{
text = QString("%1 banned %2: \"%3\".") //
.arg(action.source.name)
.arg(action.target.name)
.arg(action.reason);
this->emplaceSystemTextAndUpdate(action.target.name + ":", text)
->setLink({Link::UserInfo, action.target.name});
this->emplaceSystemTextAndUpdate(
QString("\"%1\".").arg(action.reason), text);
}
}
else
{
this->emplaceSystemTextAndUpdate(action.source.name, text)
->setLink({Link::UserInfo, action.source.name});
this->emplaceSystemTextAndUpdate("timed out", text);
this->emplaceSystemTextAndUpdate(action.target.name, text)
->setLink({Link::UserInfo, action.target.name});
if (action.reason.isEmpty())
{
text = QString("%1 timed out %2 for %3.") //
.arg(action.source.name)
.arg(action.target.name)
.arg(formatTime(action.duration));
this->emplaceSystemTextAndUpdate(
QString("for %1.").arg(formatTime(action.duration)), text);
}
else
{
text = QString("%1 timed out %2 for %3: \"%4\".") //
.arg(action.source.name)
.arg(action.target.name)
.arg(formatTime(action.duration))
.arg(action.reason);
this->emplaceSystemTextAndUpdate(
QString("for %1: \"%2\".")
.arg(formatTime(action.duration))
.arg(action.reason),
text);
}
if (count > 1)
{
text.append(QString(" (%1 times)").arg(count));
this->emplaceSystemTextAndUpdate(
QString("(%1 times)").arg(count), text);
}
}
}
this->emplace<TextElement>(text, MessageElementFlag::Text,
MessageColor::System);
this->message().messageText = text;
this->message().searchText = text;
}
@@ -271,14 +304,15 @@ MessageBuilder::MessageBuilder(const UnbanAction &action)
this->message().timeoutUser = action.target.name;
QString text =
QString("%1 %2 %3.")
.arg(action.source.name)
.arg(QString(action.wasBan() ? "unbanned" : "untimedout"))
.arg(action.target.name);
QString text;
this->emplaceSystemTextAndUpdate(action.source.name, text)
->setLink({Link::UserInfo, action.source.name});
this->emplaceSystemTextAndUpdate(
action.wasBan() ? "unbanned" : "untimedout", text);
this->emplaceSystemTextAndUpdate(action.target.name, text)
->setLink({Link::UserInfo, action.target.name});
this->emplace<TextElement>(text, MessageElementFlag::Text,
MessageColor::System);
this->message().messageText = text;
this->message().searchText = text;
}
@@ -446,4 +480,12 @@ void MessageBuilder::addLink(const QString &origLink,
});
}
TextElement *MessageBuilder::emplaceSystemTextAndUpdate(const QString &text,
QString &toUpdate)
{
toUpdate.append(text + " ");
return this->emplace<TextElement>(text, MessageElementFlag::Text,
MessageColor::System);
}
} // namespace chatterino
+11 -1
View File
@@ -22,6 +22,7 @@ const SystemMessageTag systemMessage{};
const TimeoutMessageTag timeoutMessage{};
MessagePtr makeSystemMessage(const QString &text);
MessagePtr makeSystemMessage(const QString &text, const QTime &time);
std::pair<MessagePtr, MessagePtr> makeAutomodMessage(
const AutomodAction &action);
@@ -37,7 +38,10 @@ class MessageBuilder
{
public:
MessageBuilder();
MessageBuilder(SystemMessageTag, const QString &text);
MessageBuilder(SystemMessageTag, const QString &text,
const QTime &time = QTime::currentTime());
MessageBuilder(TimeoutMessageTag, const QString &systemMessageText,
int times);
MessageBuilder(TimeoutMessageTag, const QString &username,
const QString &durationInSeconds, const QString &reason,
bool multipleTimes);
@@ -67,6 +71,12 @@ public:
}
private:
// Helper method that emplaces some text stylized as system text
// and then appends that text to the QString parameter "toUpdate".
// Returns the TextElement that was emplaced.
TextElement *emplaceSystemTextAndUpdate(const QString &text,
QString &toUpdate);
std::shared_ptr<Message> message_;
};
+19 -1
View File
@@ -634,7 +634,25 @@ std::vector<MessagePtr> IrcMessageHandler::parseNoticeMessage(
{
std::vector<MessagePtr> builtMessages;
builtMessages.emplace_back(makeSystemMessage(message->content()));
if (message->tags().contains("historical"))
{
bool customReceived = false;
qint64 ts = message->tags()
.value("rm-received-ts")
.toLongLong(&customReceived);
if (!customReceived)
{
ts = message->tags().value("tmi-sent-ts").toLongLong();
}
QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(ts);
builtMessages.emplace_back(
makeSystemMessage(message->content(), dateTime.time()));
}
else
{
builtMessages.emplace_back(makeSystemMessage(message->content()));
}
return builtMessages;
}
+41 -17
View File
@@ -27,6 +27,9 @@
namespace {
// matches a mention with punctuation at the end, like "@username," or "@username!!!" where capture group would return "username"
const QRegularExpression mentionRegex("^@(\\w+)[.,!?;]*?$");
const QSet<QString> zeroWidthEmotes{
"SoSnowy", "IceCold", "SantaHat", "TopHat",
"ReinDeer", "CandyCane", "cvMask", "cvHazmat",
@@ -407,29 +410,50 @@ void TwitchMessageBuilder::addTextOrEmoji(const QString &string_)
// Actually just text
auto linkString = this->matchLink(string);
auto link = Link();
auto textColor = this->action_ ? MessageColor(this->usernameColor_)
: MessageColor(MessageColor::Text);
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
if (!linkString.isEmpty())
{
this->addLink(string, linkString);
return;
}
if (string.startsWith('@'))
{
auto match = mentionRegex.match(string);
// Only treat as @mention if valid username
if (match.hasMatch())
{
QString username = match.captured(1);
this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
textColor, FontStyle::ChatMediumBold)
->setLink({Link::UserInfo, username});
this->emplace<TextElement>(
string, MessageElementFlag::NonBoldUsername, textColor)
->setLink({Link::UserInfo, username});
return;
}
}
if (this->twitchChannel != nullptr && getSettings()->findAllUsernames)
{
auto chatters = this->twitchChannel->accessChatters();
if (chatters->contains(string))
{
this->emplace<TextElement>(string, MessageElementFlag::BoldUsername,
textColor, FontStyle::ChatMediumBold)
->setLink({Link::UserInfo, string});
this->emplace<TextElement>(
string, MessageElementFlag::NonBoldUsername, textColor)
->setLink({Link::UserInfo, string});
return;
}
}
this->emplace<TextElement>(string, MessageElementFlag::Text, textColor);
}
void TwitchMessageBuilder::parseMessageID()
+2
View File
@@ -94,6 +94,8 @@ public:
BoolSetting enableSmoothScrollingNewMessages = {
"/appearance/smoothScrollingNewMessages", false};
BoolSetting boldUsernames = {"/appearance/messages/boldUsernames", false};
BoolSetting findAllUsernames = {"/appearance/messages/findAllUsernames",
false};
// BoolSetting customizable splitheader
BoolSetting headerViewerCount = {"/appearance/splitheader/showViewerCount",
false};
@@ -511,6 +511,8 @@ void GeneralPage::initLayout(SettingsLayout &layout)
layout.addCheckbox("Show parted users (< 1000 chatters)", s.showParts);
layout.addCheckbox("Lowercase domains (anti-phishing)", s.lowercaseDomains);
layout.addCheckbox("Bold @usernames", s.boldUsernames);
layout.addCheckbox("Try to find usernames without @ prefix",
s.findAllUsernames);
layout.addDropdown<float>(
"Username font weight", {"50", "Default", "75", "100"}, s.boldScale,
[](auto val) {