feat: add setting to pulse split input on self message received (#6380)
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
- Minor: Message character length label is now monospaced. (#6366)
|
- Minor: Message character length label is now monospaced. (#6366)
|
||||||
- Minor: Add a setting under Moderation -> Logs to customize the timestamp used for chat logs. (#6338)
|
- Minor: Add a setting under Moderation -> Logs to customize the timestamp used for chat logs. (#6338)
|
||||||
- Minor: Add a setting under Moderation -> Logs to use server timestamp from the message instead of the local clock time for logging. (#6346)
|
- Minor: Add a setting under Moderation -> Logs to use server timestamp from the message instead of the local clock time for logging. (#6346)
|
||||||
|
- Minor: Add a setting under Chat that, when enabled, pulses the text input whenever one of your messages is successfully sent to the chat. (#6380)
|
||||||
- Minor: Add feature to search for only zero-width emotes when prepended by `:~`. (#6362)
|
- Minor: Add feature to search for only zero-width emotes when prepended by `:~`. (#6362)
|
||||||
- Minor: The follow and sub dates now show the duration in a tooltip. (#6384)
|
- Minor: The follow and sub dates now show the duration in a tooltip. (#6384)
|
||||||
- Minor: Usercards now show a live indicator if the user is currently streaming. (#6383)
|
- Minor: Usercards now show a live indicator if the user is currently streaming. (#6383)
|
||||||
|
|||||||
@@ -351,6 +351,7 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"background": { "$ref": "#/definitions/qt-color" },
|
"background": { "$ref": "#/definitions/qt-color" },
|
||||||
|
"backgroundPulse": { "$ref": "#/definitions/qt-color" },
|
||||||
"text": { "$ref": "#/definitions/qt-color" }
|
"text": { "$ref": "#/definitions/qt-color" }
|
||||||
},
|
},
|
||||||
"required": ["background", "text"]
|
"required": ["background", "text"]
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"input": {
|
"input": {
|
||||||
"background": "#080808",
|
"background": "#080808",
|
||||||
|
"backgroundPulse": "#083808",
|
||||||
"text": "#ffffff"
|
"text": "#ffffff"
|
||||||
},
|
},
|
||||||
"messageSeperator": "#3c3c3c",
|
"messageSeperator": "#3c3c3c",
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"input": {
|
"input": {
|
||||||
"background": "#242424",
|
"background": "#242424",
|
||||||
|
"backgroundPulse": "#245424",
|
||||||
"text": "#ffffff"
|
"text": "#ffffff"
|
||||||
},
|
},
|
||||||
"messageSeperator": "#3c3c3c",
|
"messageSeperator": "#3c3c3c",
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"input": {
|
"input": {
|
||||||
"background": "#dbdbdb",
|
"background": "#dbdbdb",
|
||||||
|
"backgroundPulse": "#dbffdb",
|
||||||
"text": "#000000"
|
"text": "#000000"
|
||||||
},
|
},
|
||||||
"messageSeperator": "#7f7f7f",
|
"messageSeperator": "#7f7f7f",
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"input": {
|
"input": {
|
||||||
"background": "#f2f2f2",
|
"background": "#f2f2f2",
|
||||||
|
"backgroundPulse": "#d2ffd2",
|
||||||
"text": "#000000"
|
"text": "#000000"
|
||||||
},
|
},
|
||||||
"messageSeperator": "#7f7f7f",
|
"messageSeperator": "#7f7f7f",
|
||||||
|
|||||||
@@ -285,6 +285,11 @@ public:
|
|||||||
false,
|
false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BoolSetting pulseTextInputOnSelfMessage = {
|
||||||
|
"/appearance/pulseTextInputOnSelfMessage",
|
||||||
|
false,
|
||||||
|
};
|
||||||
|
|
||||||
/// Behaviour
|
/// Behaviour
|
||||||
BoolSetting allowDuplicateMessages = {"/behaviour/allowDuplicateMessages",
|
BoolSetting allowDuplicateMessages = {"/behaviour/allowDuplicateMessages",
|
||||||
true};
|
true};
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ void parseSplits(const QJsonObject &splits, const QJsonObject &splitsFallback,
|
|||||||
const auto input = splits["input"_L1].toObject();
|
const auto input = splits["input"_L1].toObject();
|
||||||
const auto inputFallback = splitsFallback["input"_L1].toObject();
|
const auto inputFallback = splitsFallback["input"_L1].toObject();
|
||||||
parseColor(theme.splits, input, background);
|
parseColor(theme.splits, input, background);
|
||||||
|
parseColor(theme.splits, input, backgroundPulse);
|
||||||
parseColor(theme.splits, input, text);
|
parseColor(theme.splits, input, text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,9 @@ public:
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
QColor background;
|
QColor background;
|
||||||
|
QColor backgroundPulse;
|
||||||
QColor text;
|
QColor text;
|
||||||
|
// Used by the ChatterListWidget & QuickSwitcherPopup
|
||||||
QString styleSheet;
|
QString styleSheet;
|
||||||
} input;
|
} input;
|
||||||
} splits;
|
} splits;
|
||||||
|
|||||||
@@ -975,6 +975,7 @@ void ChannelView::setChannel(const ChannelPtr &underlyingChannel)
|
|||||||
}
|
}
|
||||||
this->channel_->addMessage(message, MessageContext::Repost,
|
this->channel_->addMessage(message, MessageContext::Repost,
|
||||||
overridingFlags);
|
overridingFlags);
|
||||||
|
this->messageAddedToChannel(message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -228,6 +228,9 @@ public:
|
|||||||
pajlada::Signals::Signal<QString, FromTwitchLinkOpenChannelIn>
|
pajlada::Signals::Signal<QString, FromTwitchLinkOpenChannelIn>
|
||||||
openChannelIn;
|
openChannelIn;
|
||||||
|
|
||||||
|
/// This signal fires when a message passed filters and was added to the channel view
|
||||||
|
Q_SIGNAL void messageAddedToChannel(MessagePtr &message);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void themeChangedEvent() override;
|
void themeChangedEvent() override;
|
||||||
void scaleChangedEvent(float scale) override;
|
void scaleChangedEvent(float scale) override;
|
||||||
|
|||||||
@@ -496,6 +496,14 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||||||
->addKeywords({"scroll bar"})
|
->addKeywords({"scroll bar"})
|
||||||
->addTo(layout);
|
->addTo(layout);
|
||||||
|
|
||||||
|
SettingWidget::checkbox(
|
||||||
|
"Pulse text input when one of your messages is successfully sent",
|
||||||
|
s.pulseTextInputOnSelfMessage)
|
||||||
|
->setTooltip(
|
||||||
|
"Pulses the text input in a green color whenever a message of "
|
||||||
|
"yours is successfully sent in the matching channel.")
|
||||||
|
->addTo(layout);
|
||||||
|
|
||||||
layout.addTitle("Messages");
|
layout.addTitle("Messages");
|
||||||
|
|
||||||
SettingWidget::checkbox("Separate with lines", s.separateMessages)
|
SettingWidget::checkbox("Separate with lines", s.separateMessages)
|
||||||
|
|||||||
@@ -854,6 +854,21 @@ void Split::setChannel(IndirectChannel newChannel)
|
|||||||
this->actionRequested.invoke(Action::RefreshTab);
|
this->actionRequested.invoke(Action::RefreshTab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
this->view_, &ChannelView::messageAddedToChannel, this,
|
||||||
|
[this](MessagePtr &message) {
|
||||||
|
if (!getSettings()->pulseTextInputOnSelfMessage)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto user = getApp()->getAccounts()->twitch.getCurrent();
|
||||||
|
if (!user->isAnon() && message->userID == user->getUserId())
|
||||||
|
{
|
||||||
|
// A message from yourself was just received in this split
|
||||||
|
this->input_->triggerSelfMessageReceived();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this->channelChanged.invoke();
|
this->channelChanged.invoke();
|
||||||
this->actionRequested.invoke(Action::RefreshTab);
|
this->actionRequested.invoke(Action::RefreshTab);
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,24 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace Qt::Literals;
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Current function: https://www.desmos.com/calculator/vdyamchjwh
|
||||||
|
qreal highlightEasingFunction(qreal progress)
|
||||||
|
{
|
||||||
|
if (progress <= 0.1)
|
||||||
|
{
|
||||||
|
return 1.0 - pow(10.0 * progress, 3.0);
|
||||||
|
}
|
||||||
|
return 1.0 + pow((20.0 / 9.0) * (0.5 * progress - 0.5), 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
SplitInput::SplitInput(Split *_chatWidget, bool enableInlineReplying)
|
SplitInput::SplitInput(Split *_chatWidget, bool enableInlineReplying)
|
||||||
: SplitInput(_chatWidget, _chatWidget, _chatWidget->view_,
|
: SplitInput(_chatWidget, _chatWidget, _chatWidget->view_,
|
||||||
enableInlineReplying)
|
enableInlineReplying)
|
||||||
@@ -47,6 +63,7 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget,
|
|||||||
, split_(_chatWidget)
|
, split_(_chatWidget)
|
||||||
, channelView_(_channelView)
|
, channelView_(_channelView)
|
||||||
, enableInlineReplying_(enableInlineReplying)
|
, enableInlineReplying_(enableInlineReplying)
|
||||||
|
, backgroundColorAnimation(this, "backgroundColor"_ba)
|
||||||
{
|
{
|
||||||
this->installEventFilter(this);
|
this->installEventFilter(this);
|
||||||
this->initLayout();
|
this->initLayout();
|
||||||
@@ -75,6 +92,11 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget,
|
|||||||
this->clearShortcuts();
|
this->clearShortcuts();
|
||||||
this->addShortcuts();
|
this->addShortcuts();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QEasingCurve curve;
|
||||||
|
curve.setCustomType(highlightEasingFunction);
|
||||||
|
this->backgroundColorAnimation.setDuration(500);
|
||||||
|
this->backgroundColorAnimation.setEasingCurve(curve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitInput::initLayout()
|
void SplitInput::initLayout()
|
||||||
@@ -140,6 +162,7 @@ void SplitInput::initLayout()
|
|||||||
hboxLayout.emplace<ResizingTextEdit>().assign(&this->ui_.textEdit);
|
hboxLayout.emplace<ResizingTextEdit>().assign(&this->ui_.textEdit);
|
||||||
connect(textEdit.getElement(), &ResizingTextEdit::textChanged, this,
|
connect(textEdit.getElement(), &ResizingTextEdit::textChanged, this,
|
||||||
&SplitInput::editTextChanged);
|
&SplitInput::editTextChanged);
|
||||||
|
textEdit->setFrameStyle(QFrame::NoFrame);
|
||||||
|
|
||||||
hboxLayout.emplace<LabelButton>("SEND").assign(&this->ui_.sendButton);
|
hboxLayout.emplace<LabelButton>("SEND").assign(&this->ui_.sendButton);
|
||||||
this->ui_.sendButton->hide();
|
this->ui_.sendButton->hide();
|
||||||
@@ -226,6 +249,16 @@ void SplitInput::initLayout()
|
|||||||
this->managedConnections_);
|
this->managedConnections_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SplitInput::triggerSelfMessageReceived()
|
||||||
|
{
|
||||||
|
if (this->backgroundColorAnimation.state() != QPropertyAnimation::Stopped)
|
||||||
|
{
|
||||||
|
this->backgroundColorAnimation.stop();
|
||||||
|
}
|
||||||
|
this->backgroundColorAnimation.setDirection(QPropertyAnimation::Forward);
|
||||||
|
this->backgroundColorAnimation.start();
|
||||||
|
}
|
||||||
|
|
||||||
void SplitInput::scaleChangedEvent(float scale)
|
void SplitInput::scaleChangedEvent(float scale)
|
||||||
{
|
{
|
||||||
auto *app = getApp();
|
auto *app = getApp();
|
||||||
@@ -246,13 +279,6 @@ void SplitInput::scaleChangedEvent(float scale)
|
|||||||
this->ui_.textEdit->setFont(
|
this->ui_.textEdit->setFont(
|
||||||
app->getFonts()->getFont(FontStyle::ChatMedium, scale));
|
app->getFonts()->getFont(FontStyle::ChatMedium, scale));
|
||||||
|
|
||||||
QPalette placeholderPalette;
|
|
||||||
placeholderPalette.setColor(
|
|
||||||
QPalette::PlaceholderText,
|
|
||||||
this->theme->messages.textColors.chatPlaceholder);
|
|
||||||
|
|
||||||
this->ui_.textEdit->setStyleSheet(this->theme->splits.input.styleSheet);
|
|
||||||
this->ui_.textEdit->setPalette(placeholderPalette);
|
|
||||||
// TODO: This font does _not_ get updated when you change your chat font
|
// TODO: This font does _not_ get updated when you change your chat font
|
||||||
// NOTE: We're using TimestampMedium here to get a font that uses the tnum font feature,
|
// NOTE: We're using TimestampMedium here to get a font that uses the tnum font feature,
|
||||||
// meaning numbers get equal width & don't bounce around while the user is typing.
|
// meaning numbers get equal width & don't bounce around while the user is typing.
|
||||||
@@ -266,17 +292,19 @@ void SplitInput::scaleChangedEvent(float scale)
|
|||||||
void SplitInput::themeChangedEvent()
|
void SplitInput::themeChangedEvent()
|
||||||
{
|
{
|
||||||
QPalette palette;
|
QPalette palette;
|
||||||
QPalette placeholderPalette;
|
|
||||||
|
|
||||||
palette.setColor(QPalette::WindowText, this->theme->splits.input.text);
|
palette.setColor(QPalette::WindowText, this->theme->splits.input.text);
|
||||||
placeholderPalette.setColor(
|
|
||||||
QPalette::PlaceholderText,
|
|
||||||
this->theme->messages.textColors.chatPlaceholder);
|
|
||||||
|
|
||||||
this->ui_.textEditLength->setPalette(palette);
|
this->ui_.textEditLength->setPalette(palette);
|
||||||
|
|
||||||
this->ui_.textEdit->setStyleSheet(this->theme->splits.input.styleSheet);
|
// Theme changed, reset current background color
|
||||||
this->ui_.textEdit->setPalette(placeholderPalette);
|
this->setBackgroundColor(this->theme->splits.input.background);
|
||||||
|
this->backgroundColorAnimation.setStartValue(
|
||||||
|
this->theme->splits.input.backgroundPulse);
|
||||||
|
this->backgroundColorAnimation.setEndValue(
|
||||||
|
this->theme->splits.input.background);
|
||||||
|
this->backgroundColorAnimation.stop();
|
||||||
|
this->updateTextEditPalette();
|
||||||
|
|
||||||
if (this->theme->isLightTheme())
|
if (this->theme->isLightTheme())
|
||||||
{
|
{
|
||||||
@@ -1277,4 +1305,39 @@ int SplitInput::replyMessageWidth() const
|
|||||||
return this->ui_.inputWrapper->width() - 1 - 10;
|
return this->ui_.inputWrapper->width() - 1 - 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SplitInput::updateTextEditPalette()
|
||||||
|
{
|
||||||
|
QPalette p;
|
||||||
|
|
||||||
|
// Placeholder text color
|
||||||
|
p.setColor(QPalette::PlaceholderText,
|
||||||
|
this->theme->messages.textColors.chatPlaceholder);
|
||||||
|
|
||||||
|
// Text color
|
||||||
|
p.setColor(QPalette::Text, this->theme->messages.textColors.regular);
|
||||||
|
|
||||||
|
// Selection background color
|
||||||
|
p.setBrush(QPalette::Highlight,
|
||||||
|
this->theme->isLightTheme()
|
||||||
|
? QColor(u"#68B1FF"_s)
|
||||||
|
: this->theme->tabs.selected.backgrounds.regular);
|
||||||
|
|
||||||
|
// Background color
|
||||||
|
p.setBrush(QPalette::Base, this->backgroundColor());
|
||||||
|
|
||||||
|
this->ui_.textEdit->setPalette(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor SplitInput::backgroundColor() const
|
||||||
|
{
|
||||||
|
return this->backgroundColor_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitInput::setBackgroundColor(QColor newColor)
|
||||||
|
{
|
||||||
|
this->backgroundColor_ = newColor;
|
||||||
|
|
||||||
|
this->updateTextEditPalette();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QPaintEvent>
|
#include <QPaintEvent>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -75,6 +76,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setInputText(const QString &newInputText);
|
void setInputText(const QString &newInputText);
|
||||||
|
|
||||||
|
void triggerSelfMessageReceived();
|
||||||
|
|
||||||
pajlada::Signals::Signal<const QString &> textChanged;
|
pajlada::Signals::Signal<const QString &> textChanged;
|
||||||
pajlada::Signals::NoArgSignal selectionChanged;
|
pajlada::Signals::NoArgSignal selectionChanged;
|
||||||
|
|
||||||
@@ -169,6 +172,22 @@ protected:
|
|||||||
// set the height of the split input to 0 if we're supposed to be hidden instead
|
// set the height of the split input to 0 if we're supposed to be hidden instead
|
||||||
bool hidden{false};
|
bool hidden{false};
|
||||||
|
|
||||||
|
/// Updates the text edit palette using the current theme
|
||||||
|
/// and current "backgroundColor" property
|
||||||
|
void updateTextEditPalette();
|
||||||
|
|
||||||
|
// the background color defines the current background color of this split input
|
||||||
|
// instead of reading straight from the theme, we store a property here
|
||||||
|
// to be used by a property to be able to pulse a highlight color on demand
|
||||||
|
Q_PROPERTY(
|
||||||
|
QColor backgroundColor READ backgroundColor WRITE setBackgroundColor);
|
||||||
|
|
||||||
|
QColor backgroundColor_{"#000000"};
|
||||||
|
QColor backgroundColor() const;
|
||||||
|
void setBackgroundColor(QColor newColor);
|
||||||
|
|
||||||
|
QPropertyAnimation backgroundColorAnimation;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void editTextChanged();
|
void editTextChanged();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user