From a9d3c00369290c290ed6a829545abe9287d4a1fe Mon Sep 17 00:00:00 2001 From: Adam Davies <8650006+acdvs@users.noreply.github.com> Date: Sun, 13 Nov 2022 05:47:46 -0600 Subject: [PATCH] Add setting to prevent or highlight message overflow (#3418) Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + src/singletons/Settings.hpp | 3 ++ src/widgets/settingspages/GeneralPage.cpp | 13 ++++++ src/widgets/splits/SplitInput.cpp | 53 ++++++++++++++++++++++- src/widgets/splits/SplitInput.hpp | 21 +++++++++ 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84ab22cbd..6964b49fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ - Minor: Migrated /mods to Helix API. (#4103) - Minor: Improved text selection to match Windows native behaviour. (#4127) - Minor: Add settings tooltips. (#3437) +- Minor: Add setting to limit message input length. (#3418) - Minor: Improved look of tabs when using a layout other than top. (#3925) - Bugfix: Fixed `Add new account` dialog causing main chatterino window to be non movable. (#4121) - Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716) diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index b426c4257..94773fca9 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -14,6 +14,7 @@ #include "singletons/Toasts.hpp" #include "util/StreamerMode.hpp" #include "widgets/Notebook.hpp" +#include "widgets/splits/SplitInput.hpp" using TimeoutButton = std::pair; @@ -98,6 +99,8 @@ public: BoolSetting showEmptyInput = {"/appearance/showEmptyInputBox", true}; BoolSetting showMessageLength = {"/appearance/messages/showMessageLength", false}; + EnumSetting messageOverflow = { + "/appearance/messages/messageOverflow", MessageOverflow::Highlight}; BoolSetting separateMessages = {"/appearance/messages/separateMessages", false}; BoolSetting hideModerated = {"/appearance/messages/hideModerated", false}; diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp index c10e9eece..1c5777dae 100644 --- a/src/widgets/settingspages/GeneralPage.cpp +++ b/src/widgets/settingspages/GeneralPage.cpp @@ -19,6 +19,7 @@ #include "widgets/BaseWindow.hpp" #include "widgets/helper/Line.hpp" #include "widgets/settingspages/GeneralPageView.hpp" +#include "widgets/splits/SplitInput.hpp" #include #include @@ -261,6 +262,18 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addCheckbox( "Allow sending duplicate messages", s.allowDuplicateMessages, false, "Allow a single message to be repeatedly sent without any changes."); + layout.addDropdown::type>( + "Message overflow", {"Highlight", "Prevent", "Allow"}, + s.messageOverflow, + [](auto index) { + return index; + }, + [](auto args) { + return static_cast(args.index); + }, + false, + "Specify how Chatterino will handle messages that exceed Twitch " + "message limits"); layout.addTitle("Messages"); layout.addCheckbox("Separate with lines", s.separateMessages); diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 3acec66de..cfc5a3fd9 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -29,7 +29,6 @@ #include namespace chatterino { -const int TWITCH_MESSAGE_LIMIT = 500; SplitInput::SplitInput(Split *_chatWidget, bool enableInlineReplying) : SplitInput(_chatWidget, _chatWidget, enableInlineReplying) @@ -848,6 +847,13 @@ void SplitInput::editTextChanged() // set textLengthLabel value QString text = this->ui_.textEdit->toPlainText(); + if (this->shouldPreventInput(text)) + { + this->ui_.textEdit->setPlainText(text.left(TWITCH_MESSAGE_LIMIT)); + this->ui_.textEdit->moveCursor(QTextCursor::EndOfBlock); + return; + } + if (text.startsWith("/r ", Qt::CaseInsensitive) && this->split_->getChannel()->isTwitchChannel()) { @@ -867,6 +873,28 @@ void SplitInput::editTextChanged() app->commands->execCommand(text, this->split_->getChannel(), true); } + if (getSettings()->messageOverflow.getValue() == MessageOverflow::Highlight) + { + if (text.length() > TWITCH_MESSAGE_LIMIT && + text.length() > this->lastOverflowLength) + { + QTextCharFormat format; + format.setForeground(Qt::red); + + QTextCursor cursor = this->ui_.textEdit->textCursor(); + cursor.setPosition(lastOverflowLength, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + + this->lastOverflowLength = text.length(); + + cursor.setCharFormat(format); + } + else if (this->lastOverflowLength != TWITCH_MESSAGE_LIMIT) + { + this->lastOverflowLength = TWITCH_MESSAGE_LIMIT; + } + } + QString labelText; if (text.length() > 0 && getSettings()->showMessageLength) @@ -1012,4 +1040,27 @@ void SplitInput::clearInput() } } +bool SplitInput::shouldPreventInput(const QString &text) const +{ + if (getSettings()->messageOverflow.getValue() != MessageOverflow::Prevent) + { + return false; + } + + auto channel = this->split_->getChannel(); + + if (channel == nullptr) + { + return false; + } + + if (!channel->isTwitchChannel()) + { + // Don't respect this setting for IRC channels as the limits might be server-specific + return false; + } + + return text.length() > TWITCH_MESSAGE_LIMIT; +} + } // namespace chatterino diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index bcb4d149e..164d8de1b 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -22,6 +22,19 @@ class EffectLabel; class MessageThread; class ResizingTextEdit; +// MessageOverflow is used for controlling how to guide the user into not +// sending a message that will be discarded by Twitch +enum MessageOverflow { + // Allow overflowing characters to be inserted into the input box, but highlight them in red + Highlight, + + // Prevent more characters from being inserted into the input box + Prevent, + + // Do nothing + Allow, +}; + class SplitInput : public BaseWidget { Q_OBJECT @@ -36,6 +49,8 @@ public: QString getInputText() const; void insertText(const QString &text); + static const int TWITCH_MESSAGE_LIMIT = 500; + void setReply(std::shared_ptr reply, bool showInlineReplying = true); void setPlaceholderText(const QString &text); @@ -101,6 +116,10 @@ protected: // This does not take hidden into account, so callers must take hidden into account themselves int scaledMaxHeight() const; + // Returns true if the channel this input is connected to is a Twitch channel, + // the user's setting is set to Prevent, and the given text goes beyond the Twitch message length limit + bool shouldPreventInput(const QString &text) const; + Split *const split_; QObjectRef emotePopup_; QObjectRef inputCompletionPopup_; @@ -127,6 +146,8 @@ protected: QString currMsg_; int prevIndex_ = 0; + int lastOverflowLength = TWITCH_MESSAGE_LIMIT; + // Hidden denotes whether this split input should be hidden or not // This is used instead of the regular QWidget::hide/show because // focus events don't work as expected, so instead we use this bool and