Compare commits

...

3 commits

Author SHA1 Message Date
Rasmus Karlsson
a04b593e05 Add changelog entry 2024-01-17 21:07:47 +01:00
Rasmus Karlsson
32a51ecad6 Merge remote-tracking branch 'origin/master' into fix/normalize-input-margin-between-light-and-dark-mode 2024-01-17 21:07:16 +01:00
pajlada
9eeea8f203
refactor: Fix a bunch of minor things (#5094) 2024-01-17 21:05:44 +01:00
12 changed files with 195 additions and 137 deletions

View file

@ -23,6 +23,7 @@
- Minor: Added missing periods at various moderator messages and commands. (#5061)
- Minor: Improved color selection and display. (#5057)
- Minor: Improved Streamlink documentation in the settings dialog. (#5076)
- Minor: Normalized the input padding between light & dark themes. (#5095)
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
- Bugfix: Trimmed custom streamlink paths on all platforms making sure you don't accidentally add spaces at the beginning or end of its path. (#4834)

View file

@ -16,7 +16,7 @@ struct Emote {
ImageSet images;
Tooltip tooltip;
Url homePage;
bool zeroWidth;
bool zeroWidth{};
EmoteId id;
EmoteAuthor author;
/**

View file

@ -54,6 +54,7 @@ protected:
virtual Outcome tryAppendEmote(const EmoteName &name)
{
(void)name;
return Failure;
}

View file

@ -23,6 +23,10 @@ public:
enum ConnectionType { Read = 1, Write = 2, Both = 3 };
~AbstractIrcServer() override = default;
AbstractIrcServer(const AbstractIrcServer &) = delete;
AbstractIrcServer(AbstractIrcServer &&) = delete;
AbstractIrcServer &operator=(const AbstractIrcServer &) = delete;
AbstractIrcServer &operator=(AbstractIrcServer &&) = delete;
// initializeIrc must be called from the derived class
// this allows us to initialize the abstract IRC server based on the derived class's parameters
@ -57,7 +61,11 @@ protected:
// initializeConnectionSignals is called on a connection once in its lifetime.
// it can be used to connect signals to your class
virtual void initializeConnectionSignals(IrcConnection *connection,
ConnectionType type){};
ConnectionType type)
{
(void)connection;
(void)type;
}
// initializeConnection is called every time before we try to connect to the IRC server
virtual void initializeConnection(IrcConnection *connection,

View file

@ -74,9 +74,9 @@ void PubSubClient::close(const std::string &reason,
});
}
bool PubSubClient::listen(PubSubListenMessage msg)
bool PubSubClient::listen(const PubSubListenMessage &msg)
{
int numRequestedListens = msg.topics.size();
auto numRequestedListens = msg.topics.size();
if (this->numListens_ + numRequestedListens > PubSubClient::MAX_LISTENS)
{
@ -84,11 +84,19 @@ bool PubSubClient::listen(PubSubListenMessage msg)
return false;
}
this->numListens_ += numRequestedListens;
DebugCount::increase("PubSub topic pending listens", numRequestedListens);
DebugCount::increase("PubSub topic pending listens",
static_cast<int64_t>(numRequestedListens));
for (const auto &topic : msg.topics)
{
this->listeners_.emplace_back(Listener{topic, false, false, false});
this->listeners_.emplace_back(Listener{
TopicData{
topic,
false,
false,
},
false,
});
}
qCDebug(chatterinoPubSub)
@ -127,7 +135,7 @@ PubSubClient::UnlistenPrefixResponse PubSubClient::unlistenPrefix(
this->numListens_ -= numRequestedUnlistens;
DebugCount::increase("PubSub topic pending unlistens",
numRequestedUnlistens);
static_cast<int64_t>(numRequestedUnlistens));
PubSubUnlistenMessage message(topics);
@ -192,6 +200,7 @@ void PubSubClient::ping()
runAfter(this->heartbeatTimer_, this->clientOptions_.pingInterval_,
[self](auto timer) {
(void)timer;
if (!self->started_)
{
return;

View file

@ -45,7 +45,7 @@ public:
websocketpp::close::status::value code =
websocketpp::close::status::normal);
bool listen(PubSubListenMessage msg);
bool listen(const PubSubListenMessage &msg);
UnlistenPrefixResponse unlistenPrefix(const QString &prefix);
void handleListenResponse(const PubSubMessage &message);

View file

@ -83,7 +83,6 @@ TwitchChannel::TwitchChannel(const QString &name)
, bttvEmotes_(std::make_shared<EmoteMap>())
, ffzEmotes_(std::make_shared<EmoteMap>())
, seventvEmotes_(std::make_shared<EmoteMap>())
, mod_(false)
{
qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened";
@ -322,13 +321,15 @@ void TwitchChannel::refreshFFZChannelEmotes(bool manualRefresh)
[this, weak = weakOf<Channel>(this)](auto &&modBadge) {
if (auto shared = weak.lock())
{
this->ffzCustomModBadge_.set(std::move(modBadge));
this->ffzCustomModBadge_.set(
std::forward<decltype(modBadge)>(modBadge));
}
},
[this, weak = weakOf<Channel>(this)](auto &&vipBadge) {
if (auto shared = weak.lock())
{
this->ffzCustomVipBadge_.set(std::move(vipBadge));
this->ffzCustomVipBadge_.set(
std::forward<decltype(vipBadge)>(vipBadge));
}
},
manualRefresh);
@ -778,12 +779,12 @@ void TwitchChannel::setRoomId(const QString &id)
SharedAccessGuard<const TwitchChannel::RoomModes>
TwitchChannel::accessRoomModes() const
{
return this->roomModes_.accessConst();
return this->roomModes.accessConst();
}
void TwitchChannel::setRoomModes(const RoomModes &_roomModes)
void TwitchChannel::setRoomModes(const RoomModes &newRoomModes)
{
this->roomModes_ = _roomModes;
this->roomModes = newRoomModes;
this->roomModesChanged.invoke();
}
@ -1133,7 +1134,7 @@ const QString &TwitchChannel::popoutPlayerUrl()
return this->popoutPlayerUrl_;
}
int TwitchChannel::chatterCount()
int TwitchChannel::chatterCount() const
{
return this->chatterCount_;
}
@ -1201,7 +1202,7 @@ void TwitchChannel::loadRecentMessages()
tc->loadingRecentMessages_.clear();
std::vector<MessagePtr> msgs;
for (MessagePtr msg : messages)
for (const auto &msg : messages)
{
const auto highlighted =
msg->flags.has(MessageFlag::Highlighted);
@ -1351,7 +1352,10 @@ void TwitchChannel::refreshChatters()
}
},
// Refresh chatters should only be used when failing silently is an option
[](auto error, auto message) {});
[](auto error, auto message) {
(void)error;
(void)message;
});
}
void TwitchChannel::addReplyThread(const std::shared_ptr<MessageThread> &thread)
@ -1429,14 +1433,15 @@ void TwitchChannel::refreshBadges()
for (const auto &version : badgeSet.versions)
{
auto emote = Emote{
EmoteName{},
ImageSet{
Image::fromUrl(version.imageURL1x, 1),
Image::fromUrl(version.imageURL2x, .5),
Image::fromUrl(version.imageURL4x, .25),
},
Tooltip{version.title},
version.clickURL,
.name = EmoteName{},
.images =
ImageSet{
Image::fromUrl(version.imageURL1x, 1),
Image::fromUrl(version.imageURL2x, .5),
Image::fromUrl(version.imageURL4x, .25),
},
.tooltip = Tooltip{version.title},
.homePage = version.clickURL,
};
(*badgeSets)[setID][version.id] =
std::make_shared<Emote>(emote);
@ -1508,22 +1513,28 @@ void TwitchChannel::refreshCheerEmotes()
// Combine the prefix (e.g. BibleThump) with the tier (1, 100 etc.)
auto emoteTooltip =
set.prefix + tier.id + "<br>Twitch Cheer Emote";
cheerEmote.animatedEmote = std::make_shared<Emote>(
Emote{EmoteName{"cheer emote"},
ImageSet{
tier.darkAnimated.imageURL1x,
tier.darkAnimated.imageURL2x,
tier.darkAnimated.imageURL4x,
},
Tooltip{emoteTooltip}, Url{}});
cheerEmote.staticEmote = std::make_shared<Emote>(
Emote{EmoteName{"cheer emote"},
ImageSet{
tier.darkStatic.imageURL1x,
tier.darkStatic.imageURL2x,
tier.darkStatic.imageURL4x,
},
Tooltip{emoteTooltip}, Url{}});
cheerEmote.animatedEmote = std::make_shared<Emote>(Emote{
.name = EmoteName{"cheer emote"},
.images =
ImageSet{
tier.darkAnimated.imageURL1x,
tier.darkAnimated.imageURL2x,
tier.darkAnimated.imageURL4x,
},
.tooltip = Tooltip{emoteTooltip},
.homePage = Url{},
});
cheerEmote.staticEmote = std::make_shared<Emote>(Emote{
.name = EmoteName{"cheer emote"},
.images =
ImageSet{
tier.darkStatic.imageURL1x,
tier.darkStatic.imageURL2x,
tier.darkStatic.imageURL4x,
},
.tooltip = Tooltip{emoteTooltip},
.homePage = Url{},
});
cheerEmoteSet.cheerEmotes.emplace_back(
std::move(cheerEmote));
@ -1760,7 +1771,7 @@ void TwitchChannel::updateSevenTVActivity()
});
}
void TwitchChannel::listenSevenTVCosmetics()
void TwitchChannel::listenSevenTVCosmetics() const
{
if (getApp()->twitch->seventvEventAPI)
{

View file

@ -110,6 +110,11 @@ public:
explicit TwitchChannel(const QString &channelName);
~TwitchChannel() override;
TwitchChannel(const TwitchChannel &) = delete;
TwitchChannel(TwitchChannel &&) = delete;
TwitchChannel &operator=(const TwitchChannel &) = delete;
TwitchChannel &operator=(TwitchChannel &&) = delete;
void initialize();
// Channel methods
@ -130,7 +135,7 @@ public:
const QString &subscriptionUrl();
const QString &channelUrl();
const QString &popoutPlayerUrl();
int chatterCount();
int chatterCount() const;
bool isLive() const override;
QString roomId() const;
SharedAccessGuard<const RoomModes> accessRoomModes() const;
@ -300,7 +305,7 @@ private:
* This is done at most once every 60s.
*/
void updateSevenTVActivity();
void listenSevenTVCosmetics();
void listenSevenTVCosmetics() const;
/**
* @brief Sets the live status of this Twitch channel
@ -312,7 +317,7 @@ private:
void setVIP(bool value);
void setStaff(bool value);
void setRoomId(const QString &id);
void setRoomModes(const RoomModes &roomModes_);
void setRoomModes(const RoomModes &newRoomModes);
void setDisplayName(const QString &name);
void setLocalizedName(const QString &name);
@ -371,7 +376,7 @@ private:
const QString popoutPlayerUrl_;
int chatterCount_{};
UniqueAccess<StreamStatus> streamStatus_;
UniqueAccess<RoomModes> roomModes_;
UniqueAccess<RoomModes> roomModes;
bool disconnected_{};
std::optional<std::chrono::time_point<std::chrono::system_clock>>
lastConnectedAt_{};

View file

@ -78,6 +78,7 @@ class ComboBox : public QComboBox
void wheelEvent(QWheelEvent *event) override
{
(void)event;
}
};
@ -311,8 +312,9 @@ public:
bool filterElements(const QString &query);
protected:
void resizeEvent(QResizeEvent *ev) override
void resizeEvent(QResizeEvent *event) override
{
(void)event;
}
private:

View file

@ -959,17 +959,23 @@ void Split::paintEvent(QPaintEvent *)
void Split::mouseMoveEvent(QMouseEvent *event)
{
(void)event;
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
}
void Split::keyPressEvent(QKeyEvent *event)
{
(void)event;
this->view_->unsetCursor();
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
}
void Split::keyReleaseEvent(QKeyEvent *event)
{
(void)event;
this->view_->unsetCursor();
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
}
@ -1005,6 +1011,8 @@ void Split::enterEvent(QEvent * /*event*/)
void Split::leaveEvent(QEvent *event)
{
(void)event;
this->isMouseOver_ = false;
this->overlay_->hide();

View file

@ -213,16 +213,17 @@ void SplitInput::scaleChangedEvent(float scale)
this->setMaximumHeight(this->scaledMaxHeight());
}
this->ui_.textEdit->setFont(
app->fonts->getFont(FontStyle::ChatMedium, this->scale()));
app->fonts->getFont(FontStyle::ChatMedium, scale));
this->ui_.textEditLength->setFont(
app->fonts->getFont(FontStyle::ChatMedium, this->scale()));
app->fonts->getFont(FontStyle::ChatMedium, scale));
this->ui_.replyLabel->setFont(
app->fonts->getFont(FontStyle::ChatMediumBold, this->scale()));
app->fonts->getFont(FontStyle::ChatMediumBold, scale));
}
void SplitInput::themeChangedEvent()
{
QPalette palette, placeholderPalette;
QPalette palette;
QPalette placeholderPalette;
palette.setColor(QPalette::WindowText, this->theme->splits.input.text);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
@ -256,15 +257,12 @@ void SplitInput::themeChangedEvent()
void SplitInput::updateEmoteButton()
{
float scale = this->scale();
auto scale = this->scale();
QString text = "<img src=':/buttons/emote.svg' width='xD' height='xD' />";
text.replace("xD", QString::number(int(12 * scale)));
if (this->theme->isLightTheme())
{
text.replace("emote", "emoteDark");
}
auto text =
QStringLiteral("<img src=':/buttons/%1.svg' width='%2' height='%2' />")
.arg(this->theme->isLightTheme() ? "emoteDark" : "emote")
.arg(int(12 * scale));
this->ui_.emoteButton->getLabel().setText(text);
this->ui_.emoteButton->setFixedHeight(int(18 * scale));
@ -274,15 +272,10 @@ void SplitInput::updateCancelReplyButton()
{
float scale = this->scale();
QString text =
QStringLiteral(
"<img src=':/buttons/cancel.svg' width='%1' height='%1' />")
.arg(QString::number(int(12 * scale)));
if (this->theme->isLightTheme())
{
text.replace("cancel", "cancelDark");
}
auto text =
QStringLiteral("<img src=':/buttons/%1.svg' width='%2' height='%2' />")
.arg(this->theme->isLightTheme() ? "cancelDark" : "cancel")
.arg(int(12 * scale));
this->ui_.cancelReplyButton->getLabel().setText(text);
this->ui_.cancelReplyButton->setFixedHeight(int(12 * scale));
@ -324,7 +317,7 @@ void SplitInput::openEmotePopup()
this->emotePopup_->activateWindow();
}
QString SplitInput::handleSendMessage(std::vector<QString> &arguments)
QString SplitInput::handleSendMessage(const std::vector<QString> &arguments)
{
auto c = this->split_->getChannel();
if (c == nullptr)
@ -346,40 +339,37 @@ QString SplitInput::handleSendMessage(std::vector<QString> &arguments)
this->postMessageSend(message, arguments);
return "";
}
else
// Reply to message
auto *tc = dynamic_cast<TwitchChannel *>(c.get());
if (!tc)
{
// Reply to message
auto *tc = dynamic_cast<TwitchChannel *>(c.get());
if (!tc)
{
// this should not fail
return "";
}
QString message = this->ui_.textEdit->toPlainText();
if (this->enableInlineReplying_)
{
// Remove @username prefix that is inserted when doing inline replies
message.remove(0, this->replyThread_->displayName.length() +
1); // remove "@username"
if (!message.isEmpty() && message.at(0) == ' ')
{
message.remove(0, 1); // remove possible space
}
}
message = message.replace('\n', ' ');
QString sendMessage =
getApp()->commands->execCommand(message, c, false);
// Reply within TwitchChannel
tc->sendReply(sendMessage, this->replyThread_->id);
this->postMessageSend(message, arguments);
// this should not fail
return "";
}
QString message = this->ui_.textEdit->toPlainText();
if (this->enableInlineReplying_)
{
// Remove @username prefix that is inserted when doing inline replies
message.remove(0, this->replyThread_->displayName.length() +
1); // remove "@username"
if (!message.isEmpty() && message.at(0) == ' ')
{
message.remove(0, 1); // remove possible space
}
}
message = message.replace('\n', ' ');
QString sendMessage = getApp()->commands->execCommand(message, c, false);
// Reply within TwitchChannel
tc->sendReply(sendMessage, this->replyThread_->id);
this->postMessageSend(message, arguments);
return "";
}
void SplitInput::postMessageSend(const QString &message,
@ -408,7 +398,7 @@ void SplitInput::addShortcuts()
{
HotkeyController::HotkeyMap actions{
{"cursorToStart",
[this](std::vector<QString> arguments) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
if (arguments.size() != 1)
{
qCWarning(chatterinoHotkeys)
@ -419,8 +409,8 @@ void SplitInput::addShortcuts()
}
QTextCursor cursor = this->ui_.textEdit->textCursor();
auto place = QTextCursor::Start;
auto stringTakeSelection = arguments.at(0);
bool select;
const auto &stringTakeSelection = arguments.at(0);
bool select{};
if (stringTakeSelection == "withSelection")
{
select = true;
@ -443,7 +433,7 @@ void SplitInput::addShortcuts()
return "";
}},
{"cursorToEnd",
[this](std::vector<QString> arguments) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
if (arguments.size() != 1)
{
qCWarning(chatterinoHotkeys)
@ -454,8 +444,8 @@ void SplitInput::addShortcuts()
}
QTextCursor cursor = this->ui_.textEdit->textCursor();
auto place = QTextCursor::End;
auto stringTakeSelection = arguments.at(0);
bool select;
const auto &stringTakeSelection = arguments.at(0);
bool select{};
if (stringTakeSelection == "withSelection")
{
select = true;
@ -478,36 +468,45 @@ void SplitInput::addShortcuts()
return "";
}},
{"openEmotesPopup",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
this->openEmotePopup();
return "";
}},
{"sendMessage",
[this](std::vector<QString> arguments) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
return this->handleSendMessage(arguments);
}},
{"previousMessage",
[this](std::vector<QString>) -> QString {
if (this->prevMsg_.size() && this->prevIndex_)
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
if (this->prevMsg_.isEmpty() || this->prevIndex_ == 0)
{
if (this->prevIndex_ == (this->prevMsg_.size()))
{
this->currMsg_ = ui_.textEdit->toPlainText();
}
this->prevIndex_--;
this->ui_.textEdit->setPlainText(
this->prevMsg_.at(this->prevIndex_));
this->ui_.textEdit->resetCompletion();
QTextCursor cursor = this->ui_.textEdit->textCursor();
cursor.movePosition(QTextCursor::End);
this->ui_.textEdit->setTextCursor(cursor);
return "";
}
if (this->prevIndex_ == (this->prevMsg_.size()))
{
this->currMsg_ = ui_.textEdit->toPlainText();
}
this->prevIndex_--;
this->ui_.textEdit->setPlainText(
this->prevMsg_.at(this->prevIndex_));
this->ui_.textEdit->resetCompletion();
QTextCursor cursor = this->ui_.textEdit->textCursor();
cursor.movePosition(QTextCursor::End);
this->ui_.textEdit->setTextCursor(cursor);
return "";
}},
{"nextMessage",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
// If user did not write anything before then just do nothing.
if (this->prevMsg_.isEmpty())
{
@ -556,19 +555,23 @@ void SplitInput::addShortcuts()
return "";
}},
{"undo",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
this->ui_.textEdit->undo();
return "";
}},
{"redo",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
this->ui_.textEdit->redo();
return "";
}},
{"copy",
[this](std::vector<QString> arguments) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
// XXX: this action is unused at the moment, a qt standard shortcut is used instead
if (arguments.size() == 0)
if (arguments.empty())
{
return "copy action takes only one argument: the source "
"of the copy \"split\", \"input\" or "
@ -578,8 +581,9 @@ void SplitInput::addShortcuts()
"copied. Automatic will pick whichever has a "
"selection";
}
bool copyFromSplit = false;
auto mode = arguments.at(0);
const auto &mode = arguments.at(0);
if (mode == "split")
{
copyFromSplit = true;
@ -605,22 +609,30 @@ void SplitInput::addShortcuts()
return "";
}},
{"paste",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
this->ui_.textEdit->paste();
return "";
}},
{"clear",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
this->clearInput();
return "";
}},
{"selectAll",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
this->ui_.textEdit->selectAll();
return "";
}},
{"selectWord",
[this](std::vector<QString>) -> QString {
[this](const std::vector<QString> &arguments) -> QString {
(void)arguments;
auto cursor = this->ui_.textEdit->textCursor();
cursor.select(QTextCursor::WordUnderCursor);
this->ui_.textEdit->setTextCursor(cursor);
@ -1018,7 +1030,7 @@ void SplitInput::paintEvent(QPaintEvent * /*event*/)
{
QPainter painter(this);
int s;
int s{};
QColor borderColor;
if (this->theme->isLightTheme())
@ -1052,8 +1064,10 @@ void SplitInput::paintEvent(QPaintEvent * /*event*/)
}
}
void SplitInput::resizeEvent(QResizeEvent *)
void SplitInput::resizeEvent(QResizeEvent *event)
{
(void)event;
if (this->height() == this->maximumHeight())
{
this->ui_.textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);

View file

@ -80,14 +80,13 @@ protected:
virtual void giveFocus(Qt::FocusReason reason);
QString handleSendMessage(std::vector<QString> &arguments);
QString handleSendMessage(const std::vector<QString> &arguments);
void postMessageSend(const QString &message,
const std::vector<QString> &arguments);
/// Clears the input box, clears reply thread if inline replies are enabled
void clearInput();
protected:
void addShortcuts() override;
void initLayout();
bool eventFilter(QObject *obj, QEvent *event) override;