From 9a1e4055634e17985e5fd36b074708ff3b398537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Sun, 15 Aug 2021 11:52:32 +0200 Subject: [PATCH 1/4] Fix /me not going through upon sending an identical message (#3166) --- CHANGELOG.md | 1 + src/providers/twitch/TwitchChannel.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c8caeb71..096f1209f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Minor: Display a system message when reloading subscription emotes to match BTTV/FFZ behavior (#3135) - Minor: Added a setting to hide similar messages by any user. (#2716) - Minor: Duplicate spaces now count towards the display message length. (#3002) +- Bugfix: Restored ability to send duplicate `/me` messages. (#3166) - Bugfix: Notifications for moderators about other moderators deleting messages can now be disabled. (#3121) - Bugfix: Moderation mode and active filters are now preserved when opening a split as a popup. (#3113, #3130) - Bugfix: Fixed a bug that caused all badge highlights to use the same color. (#3132, #3134) diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 94c458a55..db35de7b2 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -377,6 +377,16 @@ void TwitchChannel::sendMessage(const QString &message) if (parsedMessage == this->lastSentMessage_) { auto spaceIndex = parsedMessage.indexOf(' '); + // If the message starts with either '/' or '.' Twitch will treat it as a command, omitting + // first space and only rest of the arguments treated as actual message content + // In cases when user sends a message like ". .a b" first character and first space are omitted as well + bool ignoreFirstSpace = + parsedMessage.at(0) == '/' || parsedMessage.at(0) == '.'; + if (ignoreFirstSpace) + { + spaceIndex = parsedMessage.indexOf(' ', spaceIndex + 1); + } + if (spaceIndex == -1) { // no spaces found, fall back to old magic character From 4b251c64b69ed2d05e78f754b09ccf3dbf551b29 Mon Sep 17 00:00:00 2001 From: James Upjohn Date: Sun, 15 Aug 2021 22:39:58 +1200 Subject: [PATCH 2/4] Allow resub messages to show in /mentions tab (#3148) Co-authored-by: pajlada --- CHANGELOG.md | 1 + src/messages/SharedMessageBuilder.cpp | 20 +++++++++++++------- src/providers/twitch/IrcMessageHandler.cpp | 7 ++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 096f1209f..2a2144b87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Minor: Remove TwitchEmotes.com attribution and the open/copy options when right-clicking a Twitch Emote. (#2214, #3136) - Minor: Strip leading @ and trailing , from username in /user and /usercard commands. (#3143) - Minor: Display a system message when reloading subscription emotes to match BTTV/FFZ behavior (#3135) +- Minor: Allow resub messages to show in `/mentions` tab (#3148) - Minor: Added a setting to hide similar messages by any user. (#2716) - Minor: Duplicate spaces now count towards the display message length. (#3002) - Bugfix: Restored ability to send duplicate `/me` messages. (#3166) diff --git a/src/messages/SharedMessageBuilder.cpp b/src/messages/SharedMessageBuilder.cpp index cdc8e59f0..3af860f9f 100644 --- a/src/messages/SharedMessageBuilder.cpp +++ b/src/messages/SharedMessageBuilder.cpp @@ -157,10 +157,6 @@ void SharedMessageBuilder::parseHighlights() this->message().flags.set(MessageFlag::Highlighted); this->message().highlightColor = ColorProvider::instance().color(ColorType::Subscription); - - // This message was a subscription. - // Don't check for any other highlight phrases. - return; } // XXX: Non-common term in SharedMessageBuilder @@ -220,7 +216,10 @@ void SharedMessageBuilder::parseHighlights() << "sent a message"; this->message().flags.set(MessageFlag::Highlighted); - this->message().highlightColor = userHighlight.getColor(); + if (!this->message().flags.has(MessageFlag::Subscription)) + { + this->message().highlightColor = userHighlight.getColor(); + } if (userHighlight.showInMentions()) { @@ -289,7 +288,10 @@ void SharedMessageBuilder::parseHighlights() } this->message().flags.set(MessageFlag::Highlighted); - this->message().highlightColor = highlight.getColor(); + if (!this->message().flags.has(MessageFlag::Subscription)) + { + this->message().highlightColor = highlight.getColor(); + } if (highlight.showInMentions()) { @@ -344,7 +346,11 @@ void SharedMessageBuilder::parseHighlights() if (!badgeHighlightSet) { this->message().flags.set(MessageFlag::Highlighted); - this->message().highlightColor = highlight.getColor(); + if (!this->message().flags.has(MessageFlag::Subscription)) + { + this->message().highlightColor = highlight.getColor(); + } + badgeHighlightSet = true; } diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index 0e720d0ee..a4ce3c513 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -313,12 +313,9 @@ void IrcMessageHandler::addMessage(Communi::IrcMessage *_message, const auto highlighted = msg->flags.has(MessageFlag::Highlighted); const auto showInMentions = msg->flags.has(MessageFlag::ShowInMentions); - if (!isSub) + if (highlighted && showInMentions) { - if (highlighted && showInMentions) - { - server.mentionsChannel->addMessage(msg); - } + server.mentionsChannel->addMessage(msg); } chan->addMessage(msg); From b2d9b678a288b31640a2d64ccf1861d0c7fb91a6 Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 15 Aug 2021 14:33:31 +0200 Subject: [PATCH 3/4] Enable backup for commands (#3168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł --- CHANGELOG.md | 1 + src/controllers/commands/CommandController.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a2144b87..b48ade145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Minor: Allow resub messages to show in `/mentions` tab (#3148) - Minor: Added a setting to hide similar messages by any user. (#2716) - Minor: Duplicate spaces now count towards the display message length. (#3002) +- Minor: Commands are now backed up. (#3168) - Bugfix: Restored ability to send duplicate `/me` messages. (#3166) - Bugfix: Notifications for moderators about other moderators deleting messages can now be disabled. (#3121) - Bugfix: Moderation mode and active filters are now preserved when opening a split as a popup. (#3113, #3130) diff --git a/src/controllers/commands/CommandController.cpp b/src/controllers/commands/CommandController.cpp index 8e977af9b..13368917e 100644 --- a/src/controllers/commands/CommandController.cpp +++ b/src/controllers/commands/CommandController.cpp @@ -267,6 +267,8 @@ void CommandController::initialize(Settings &, Paths &paths) auto path = combinePath(paths.settingsDirectory, "commands.json"); this->sm_ = std::make_shared(); this->sm_->setPath(path.toStdString()); + this->sm_->setBackupEnabled(true); + this->sm_->setBackupSlots(9); // Delayed initialization of the setting storing all commands this->commandsSetting_.reset( From 1d664f88e56179a0f5da0cd687df2e19bfb79c4b Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 15 Aug 2021 15:59:52 +0200 Subject: [PATCH 4/4] Keyboard integration for Streamlink quality confirmation (#3169) Co-authored-by: zneix --- src/util/StreamLink.cpp | 2 +- src/widgets/BasePopup.cpp | 64 ++++++++++++++++++++++++++++ src/widgets/BasePopup.hpp | 8 ++++ src/widgets/dialogs/QualityPopup.cpp | 50 +++++++++++++--------- src/widgets/dialogs/QualityPopup.hpp | 18 ++++---- 5 files changed, 111 insertions(+), 31 deletions(-) diff --git a/src/util/StreamLink.cpp b/src/util/StreamLink.cpp index 2ac42cfa6..b631cad51 100644 --- a/src/util/StreamLink.cpp +++ b/src/util/StreamLink.cpp @@ -200,7 +200,7 @@ void openStreamlinkForChannel(const QString &channel) if (preferredQuality == "choose") { getStreamQualities(channelURL, [=](QStringList qualityOptions) { - QualityPopup::showDialog(channel, qualityOptions); + QualityPopup::showDialog(channelURL, qualityOptions); }); return; diff --git a/src/widgets/BasePopup.cpp b/src/widgets/BasePopup.cpp index 0f3ed3c1d..afae740b6 100644 --- a/src/widgets/BasePopup.cpp +++ b/src/widgets/BasePopup.cpp @@ -1,5 +1,7 @@ #include "widgets/BasePopup.hpp" +#include +#include #include namespace chatterino { @@ -20,4 +22,66 @@ void BasePopup::keyPressEvent(QKeyEvent *e) BaseWindow::keyPressEvent(e); } +bool BasePopup::handleEscape(QKeyEvent *e, QDialogButtonBox *buttonBox) +{ + assert(buttonBox != nullptr); + + if (e->key() == Qt::Key_Escape) + { + auto buttons = buttonBox->buttons(); + for (auto *button : buttons) + { + if (auto role = buttonBox->buttonRole(button); + role == QDialogButtonBox::ButtonRole::RejectRole) + { + button->click(); + return true; + } + } + } + + return false; +} + +bool BasePopup::handleEnter(QKeyEvent *e, QDialogButtonBox *buttonBox) +{ + assert(buttonBox != nullptr); + + if (!e->modifiers() || + (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) + { + switch (e->key()) + { + case Qt::Key_Enter: + case Qt::Key_Return: { + auto buttons = buttonBox->buttons(); + QAbstractButton *acceptButton = nullptr; + for (auto *button : buttons) + { + if (button->hasFocus()) + { + button->click(); + return true; + } + + if (auto role = buttonBox->buttonRole(button); + role == QDialogButtonBox::ButtonRole::AcceptRole) + { + acceptButton = button; + } + } + + if (acceptButton != nullptr) + { + acceptButton->click(); + return true; + } + } + break; + } + } + + return false; +} + } // namespace chatterino diff --git a/src/widgets/BasePopup.hpp b/src/widgets/BasePopup.hpp index 5741b0006..d7942f2fc 100644 --- a/src/widgets/BasePopup.hpp +++ b/src/widgets/BasePopup.hpp @@ -3,6 +3,8 @@ #include "common/FlagsEnum.hpp" #include "widgets/BaseWindow.hpp" +class QDialogButtonBox; + namespace chatterino { class BasePopup : public BaseWindow @@ -13,6 +15,12 @@ public: protected: void keyPressEvent(QKeyEvent *e) override; + + // handleEscape is a helper function for clicking the "Reject" role button of a button box when the Escape button is pressed + bool handleEscape(QKeyEvent *e, QDialogButtonBox *buttonBox); + + // handleEnter is a helper function for clicking the "Accept" role button of a button box when Return or Enter is pressed + bool handleEnter(QKeyEvent *e, QDialogButtonBox *buttonBox); }; } // namespace chatterino diff --git a/src/widgets/dialogs/QualityPopup.cpp b/src/widgets/dialogs/QualityPopup.cpp index 414ab2548..52f7dba47 100644 --- a/src/widgets/dialogs/QualityPopup.cpp +++ b/src/widgets/dialogs/QualityPopup.cpp @@ -7,35 +7,32 @@ namespace chatterino { -QualityPopup::QualityPopup(const QString &_channelName, QStringList options) +QualityPopup::QualityPopup(const QString &channelURL, QStringList options) : BasePopup({}, static_cast(&(getApp()->windows->getMainWindow()))) - , channelName_(_channelName) + , channelURL_(channelURL) { - this->ui_.okButton.setText("OK"); - this->ui_.cancelButton.setText("Cancel"); + this->ui_.selector = new QComboBox(this); + this->ui_.vbox = new QVBoxLayout(this); + this->ui_.buttonBox = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - QObject::connect(&this->ui_.okButton, &QPushButton::clicked, this, + QObject::connect(this->ui_.buttonBox, &QDialogButtonBox::accepted, this, &QualityPopup::okButtonClicked); - QObject::connect(&this->ui_.cancelButton, &QPushButton::clicked, this, + QObject::connect(this->ui_.buttonBox, &QDialogButtonBox::rejected, this, &QualityPopup::cancelButtonClicked); - this->ui_.buttonBox.addButton(&this->ui_.okButton, - QDialogButtonBox::ButtonRole::AcceptRole); - this->ui_.buttonBox.addButton(&this->ui_.cancelButton, - QDialogButtonBox::ButtonRole::RejectRole); + this->ui_.selector->addItems(options); - this->ui_.selector.addItems(options); + this->ui_.vbox->addWidget(this->ui_.selector); + this->ui_.vbox->addWidget(this->ui_.buttonBox); - this->ui_.vbox.addWidget(&this->ui_.selector); - this->ui_.vbox.addWidget(&this->ui_.buttonBox); - - this->setLayout(&this->ui_.vbox); + this->setLayout(this->ui_.vbox); } -void QualityPopup::showDialog(const QString &channelName, QStringList options) +void QualityPopup::showDialog(const QString &channelURL, QStringList options) { - QualityPopup *instance = new QualityPopup(channelName, options); + QualityPopup *instance = new QualityPopup(channelURL, options); instance->window()->setWindowTitle("Chatterino - select stream quality"); instance->setAttribute(Qt::WA_DeleteOnClose, true); @@ -43,16 +40,27 @@ void QualityPopup::showDialog(const QString &channelName, QStringList options) instance->show(); instance->activateWindow(); instance->raise(); - instance->setFocus(); +} + +void QualityPopup::keyPressEvent(QKeyEvent *e) +{ + if (this->handleEscape(e, this->ui_.buttonBox)) + { + return; + } + if (this->handleEnter(e, this->ui_.buttonBox)) + { + return; + } + + BasePopup::keyPressEvent(e); } void QualityPopup::okButtonClicked() { - QString channelURL = "twitch.tv/" + this->channelName_; - try { - openStreamlink(channelURL, this->ui_.selector.currentText()); + openStreamlink(this->channelURL_, this->ui_.selector->currentText()); } catch (const Exception &ex) { diff --git a/src/widgets/dialogs/QualityPopup.hpp b/src/widgets/dialogs/QualityPopup.hpp index cb5f06205..f0820218d 100644 --- a/src/widgets/dialogs/QualityPopup.hpp +++ b/src/widgets/dialogs/QualityPopup.hpp @@ -4,7 +4,6 @@ #include #include -#include #include namespace chatterino { @@ -12,22 +11,23 @@ namespace chatterino { class QualityPopup : public BasePopup { public: - QualityPopup(const QString &_channelName, QStringList options); - static void showDialog(const QString &_channelName, QStringList options); + QualityPopup(const QString &channelURL, QStringList options); + static void showDialog(const QString &channelURL, QStringList options); + +protected: + void keyPressEvent(QKeyEvent *e) override; private: void okButtonClicked(); void cancelButtonClicked(); struct { - QVBoxLayout vbox; - QComboBox selector; - QDialogButtonBox buttonBox; - QPushButton okButton; - QPushButton cancelButton; + QVBoxLayout *vbox; + QComboBox *selector; + QDialogButtonBox *buttonBox; } ui_; - QString channelName_; + QString channelURL_; }; } // namespace chatterino