mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Merge pull request #1316 from Chatterino/moderation
Pausing while key is pressed + no more moving highlights
This commit is contained in:
commit
ffd63d9407
7 changed files with 171 additions and 28 deletions
|
@ -51,4 +51,38 @@ using IntSetting = ChatterinoSetting<int>;
|
||||||
using StringSetting = ChatterinoSetting<std::string>;
|
using StringSetting = ChatterinoSetting<std::string>;
|
||||||
using QStringSetting = ChatterinoSetting<QString>;
|
using QStringSetting = ChatterinoSetting<QString>;
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
class EnumSetting
|
||||||
|
: public ChatterinoSetting<typename std::underlying_type<Enum>::type>
|
||||||
|
{
|
||||||
|
using Underlying = typename std::underlying_type<Enum>::type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using ChatterinoSetting<Underlying>::ChatterinoSetting;
|
||||||
|
|
||||||
|
EnumSetting(const std::string &path, const Enum &defaultValue)
|
||||||
|
: ChatterinoSetting<Underlying>(path, Underlying(defaultValue))
|
||||||
|
{
|
||||||
|
_registerSetting(this->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
EnumSetting<Enum> &operator=(Enum newValue)
|
||||||
|
{
|
||||||
|
this->setValue(Underlying(newValue));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator Enum()
|
||||||
|
{
|
||||||
|
return Enum(this->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
Enum getEnum()
|
||||||
|
{
|
||||||
|
return Enum(this->getValue());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace AB_NAMESPACE
|
} // namespace AB_NAMESPACE
|
||||||
|
|
|
@ -102,7 +102,9 @@ public:
|
||||||
BoolSetting prefixOnlyEmoteCompletion = {
|
BoolSetting prefixOnlyEmoteCompletion = {
|
||||||
"/behaviour/autocompletion/prefixOnlyCompletion", true};
|
"/behaviour/autocompletion/prefixOnlyCompletion", true};
|
||||||
|
|
||||||
BoolSetting pauseChatOnHover = {"/behaviour/pauseChatHover", false};
|
FloatSetting pauseOnHoverDuration = {"/behaviour/pauseOnHoverDuration", 0};
|
||||||
|
EnumSetting<Qt::KeyboardModifier> pauseChatModifier = {
|
||||||
|
"/behaviour/pauseChatModifier", Qt::KeyboardModifier::NoModifier};
|
||||||
BoolSetting autorun = {"/behaviour/autorun", false};
|
BoolSetting autorun = {"/behaviour/autorun", false};
|
||||||
BoolSetting mentionUsersWithComma = {"/behaviour/mentionUsersWithComma",
|
BoolSetting mentionUsersWithComma = {"/behaviour/mentionUsersWithComma",
|
||||||
true};
|
true};
|
||||||
|
|
|
@ -241,6 +241,14 @@ void ChannelView::unpause(PauseReason reason)
|
||||||
this->pauses_.erase(reason);
|
this->pauses_.erase(reason);
|
||||||
|
|
||||||
this->updatePauseTimer();
|
this->updatePauseTimer();
|
||||||
|
|
||||||
|
/// Move selection
|
||||||
|
this->selection_.selectionMin.messageIndex -= this->pauseSelectionOffset_;
|
||||||
|
this->selection_.selectionMax.messageIndex -= this->pauseSelectionOffset_;
|
||||||
|
this->selection_.start.messageIndex -= this->pauseSelectionOffset_;
|
||||||
|
this->selection_.end.messageIndex -= this->pauseSelectionOffset_;
|
||||||
|
|
||||||
|
this->pauseSelectionOffset_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelView::updatePauseTimer()
|
void ChannelView::updatePauseTimer()
|
||||||
|
@ -527,64 +535,64 @@ ChannelPtr ChannelView::channel()
|
||||||
return this->channel_;
|
return this->channel_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelView::setChannel(ChannelPtr newChannel)
|
void ChannelView::setChannel(ChannelPtr channel)
|
||||||
{
|
{
|
||||||
/// Clear connections from the last channel
|
/// Clear connections from the last channel
|
||||||
this->channelConnections_.clear();
|
this->channelConnections_.clear();
|
||||||
|
|
||||||
this->clearMessages();
|
this->clearMessages();
|
||||||
|
this->scrollBar_->clearHighlights();
|
||||||
|
|
||||||
// on new message
|
// on new message
|
||||||
this->channelConnections_.push_back(newChannel->messageAppended.connect(
|
this->channelConnections_.push_back(channel->messageAppended.connect(
|
||||||
[this](MessagePtr &message,
|
[this](MessagePtr &message,
|
||||||
boost::optional<MessageFlags> overridingFlags) {
|
boost::optional<MessageFlags> overridingFlags) {
|
||||||
this->messageAppended(message, overridingFlags);
|
this->messageAppended(message, overridingFlags);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this->channelConnections_.push_back(
|
this->channelConnections_.push_back(channel->messagesAddedAtStart.connect(
|
||||||
newChannel->messagesAddedAtStart.connect(
|
[this](std::vector<MessagePtr> &messages) {
|
||||||
[this](std::vector<MessagePtr> &messages) {
|
this->messageAddedAtStart(messages);
|
||||||
this->messageAddedAtStart(messages);
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
// on message removed
|
// on message removed
|
||||||
this->channelConnections_.push_back(
|
this->channelConnections_.push_back(
|
||||||
newChannel->messageRemovedFromStart.connect(
|
channel->messageRemovedFromStart.connect([this](MessagePtr &message) {
|
||||||
[this](MessagePtr &message) {
|
this->messageRemoveFromStart(message);
|
||||||
this->messageRemoveFromStart(message);
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
// on message replaced
|
// on message replaced
|
||||||
this->channelConnections_.push_back(newChannel->messageReplaced.connect(
|
this->channelConnections_.push_back(channel->messageReplaced.connect(
|
||||||
[this](size_t index, MessagePtr replacement) {
|
[this](size_t index, MessagePtr replacement) {
|
||||||
this->messageReplaced(index, replacement);
|
this->messageReplaced(index, replacement);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
auto snapshot = newChannel->getMessageSnapshot();
|
auto snapshot = channel->getMessageSnapshot();
|
||||||
|
|
||||||
for (size_t i = 0; i < snapshot.size(); i++)
|
for (size_t i = 0; i < snapshot.size(); i++)
|
||||||
{
|
{
|
||||||
MessageLayoutPtr deleted;
|
MessageLayoutPtr deleted;
|
||||||
|
|
||||||
auto messageRef = new MessageLayout(snapshot[i]);
|
auto messageLayout = new MessageLayout(snapshot[i]);
|
||||||
|
|
||||||
if (this->lastMessageHasAlternateBackground_)
|
if (this->lastMessageHasAlternateBackground_)
|
||||||
{
|
{
|
||||||
messageRef->flags.set(MessageLayoutFlag::AlternateBackground);
|
messageLayout->flags.set(MessageLayoutFlag::AlternateBackground);
|
||||||
}
|
}
|
||||||
this->lastMessageHasAlternateBackground_ =
|
this->lastMessageHasAlternateBackground_ =
|
||||||
!this->lastMessageHasAlternateBackground_;
|
!this->lastMessageHasAlternateBackground_;
|
||||||
|
|
||||||
this->messages_.pushBack(MessageLayoutPtr(messageRef), deleted);
|
this->messages_.pushBack(MessageLayoutPtr(messageLayout), deleted);
|
||||||
|
this->scrollBar_->addHighlight(snapshot[i]->getScrollBarHighlight());
|
||||||
}
|
}
|
||||||
|
|
||||||
this->channel_ = newChannel;
|
this->channel_ = channel;
|
||||||
|
|
||||||
this->queueLayout();
|
this->queueLayout();
|
||||||
this->queueUpdate();
|
this->queueUpdate();
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
if (auto tc = dynamic_cast<TwitchChannel *>(newChannel.get()))
|
if (auto tc = dynamic_cast<TwitchChannel *>(channel.get()))
|
||||||
{
|
{
|
||||||
this->connections_.push_back(tc->liveStatusChanged.connect([this]() {
|
this->connections_.push_back(tc->liveStatusChanged.connect([this]() {
|
||||||
this->liveStatusChanged.invoke(); //
|
this->liveStatusChanged.invoke(); //
|
||||||
|
@ -697,10 +705,17 @@ void ChannelView::messageAddedAtStart(std::vector<MessagePtr> &messages)
|
||||||
|
|
||||||
void ChannelView::messageRemoveFromStart(MessagePtr &message)
|
void ChannelView::messageRemoveFromStart(MessagePtr &message)
|
||||||
{
|
{
|
||||||
this->selection_.selectionMin.messageIndex--;
|
if (this->paused())
|
||||||
this->selection_.selectionMax.messageIndex--;
|
{
|
||||||
this->selection_.start.messageIndex--;
|
this->pauseSelectionOffset_ += 1;
|
||||||
this->selection_.end.messageIndex--;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->selection_.selectionMin.messageIndex--;
|
||||||
|
this->selection_.selectionMax.messageIndex--;
|
||||||
|
this->selection_.start.messageIndex--;
|
||||||
|
this->selection_.end.messageIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
this->queueLayout();
|
this->queueLayout();
|
||||||
}
|
}
|
||||||
|
@ -1023,9 +1038,14 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pause on hover
|
/// Pause on hover
|
||||||
if (getSettings()->pauseChatOnHover.getValue())
|
if (float pauseTime = getSettings()->pauseOnHoverDuration;
|
||||||
|
pauseTime > 0.001f)
|
||||||
{
|
{
|
||||||
this->pause(PauseReason::Mouse, 500);
|
this->pause(PauseReason::Mouse, uint(pauseTime * 1000.f));
|
||||||
|
}
|
||||||
|
else if (pauseTime < -0.5f)
|
||||||
|
{
|
||||||
|
this->pause(PauseReason::Mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tooltipWidget = TooltipWidget::getInstance();
|
auto tooltipWidget = TooltipWidget::getInstance();
|
||||||
|
|
|
@ -44,6 +44,7 @@ enum class PauseReason {
|
||||||
Mouse,
|
Mouse,
|
||||||
Selection,
|
Selection,
|
||||||
DoubleClick,
|
DoubleClick,
|
||||||
|
KeyboardModifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
using SteadyClock = std::chrono::steady_clock;
|
using SteadyClock = std::chrono::steady_clock;
|
||||||
|
@ -162,6 +163,7 @@ private:
|
||||||
pauses_;
|
pauses_;
|
||||||
boost::optional<SteadyClock::time_point> pauseEnd_;
|
boost::optional<SteadyClock::time_point> pauseEnd_;
|
||||||
int pauseScrollOffset_ = 0;
|
int pauseScrollOffset_ = 0;
|
||||||
|
int pauseSelectionOffset_ = 0;
|
||||||
|
|
||||||
boost::optional<MessageElementFlags> overrideFlags_;
|
boost::optional<MessageElementFlags> overrideFlags_;
|
||||||
MessageLayoutPtr lastReadMessage_;
|
MessageLayoutPtr lastReadMessage_;
|
||||||
|
|
|
@ -21,9 +21,56 @@
|
||||||
#define FIREFOX_EXTENSION_LINK \
|
#define FIREFOX_EXTENSION_LINK \
|
||||||
"https://addons.mozilla.org/en-US/firefox/addon/chatterino-native-host/"
|
"https://addons.mozilla.org/en-US/firefox/addon/chatterino-native-host/"
|
||||||
|
|
||||||
|
// define to highlight sections in editor
|
||||||
#define addTitle addTitle
|
#define addTitle addTitle
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# define META_KEY "Windows"
|
||||||
|
#else
|
||||||
|
# define META_KEY "Meta"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
namespace {
|
||||||
|
void addKeyboardModifierSetting(SettingsLayout &layout,
|
||||||
|
const QString &title,
|
||||||
|
EnumSetting<Qt::KeyboardModifier> &setting)
|
||||||
|
{
|
||||||
|
layout.addDropdown<std::underlying_type<Qt::KeyboardModifier>::type>(
|
||||||
|
title, {"None", "Shift", "Control", "Alt", META_KEY}, setting,
|
||||||
|
[](int index) {
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case Qt::ShiftModifier:
|
||||||
|
return 1;
|
||||||
|
case Qt::ControlModifier:
|
||||||
|
return 2;
|
||||||
|
case Qt::AltModifier:
|
||||||
|
return 3;
|
||||||
|
case Qt::MetaModifier:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[](DropdownArgs args) {
|
||||||
|
switch (args.index)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return Qt::ShiftModifier;
|
||||||
|
case 2:
|
||||||
|
return Qt::ControlModifier;
|
||||||
|
case 3:
|
||||||
|
return Qt::AltModifier;
|
||||||
|
case 4:
|
||||||
|
return Qt::MetaModifier;
|
||||||
|
default:
|
||||||
|
return Qt::NoModifier;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
TitleLabel *SettingsLayout::addTitle(const QString &title)
|
TitleLabel *SettingsLayout::addTitle(const QString &title)
|
||||||
{
|
{
|
||||||
|
@ -272,7 +319,28 @@ void GeneralPage::initLayout(SettingsLayout &layout)
|
||||||
layout.addCheckbox("Smooth scrolling", s.enableSmoothScrolling);
|
layout.addCheckbox("Smooth scrolling", s.enableSmoothScrolling);
|
||||||
layout.addCheckbox("Smooth scrolling on new messages",
|
layout.addCheckbox("Smooth scrolling on new messages",
|
||||||
s.enableSmoothScrollingNewMessages);
|
s.enableSmoothScrollingNewMessages);
|
||||||
layout.addCheckbox("Pause on hover", s.pauseChatOnHover);
|
layout.addDropdown<float>(
|
||||||
|
"Pause on hover", {"Disabled", "0.5s", "1s", "2s", "5s", "Indefinite"},
|
||||||
|
s.pauseOnHoverDuration,
|
||||||
|
[](auto val) {
|
||||||
|
if (val < -0.5f)
|
||||||
|
return QString("Indefinite");
|
||||||
|
else if (val < 0.001f)
|
||||||
|
return QString("Disabled");
|
||||||
|
else
|
||||||
|
return QString::number(val) + "s";
|
||||||
|
},
|
||||||
|
[](auto args) {
|
||||||
|
if (args.index == 0)
|
||||||
|
return 0.0f;
|
||||||
|
else if (args.value == "Indefinite")
|
||||||
|
return -1.0f;
|
||||||
|
else
|
||||||
|
return fuzzyToFloat(args.value,
|
||||||
|
std::numeric_limits<float>::infinity());
|
||||||
|
});
|
||||||
|
addKeyboardModifierSetting(layout, "Pause while holding a key",
|
||||||
|
s.pauseChatModifier);
|
||||||
layout.addCheckbox("Show input when it's empty", s.showEmptyInput);
|
layout.addCheckbox("Show input when it's empty", s.showEmptyInput);
|
||||||
layout.addCheckbox("Show message length while typing", s.showMessageLength);
|
layout.addCheckbox("Show message length while typing", s.showMessageLength);
|
||||||
if (!BaseWindow::supportsCustomWindowFrame())
|
if (!BaseWindow::supportsCustomWindowFrame())
|
||||||
|
@ -401,8 +469,7 @@ void GeneralPage::initLayout(SettingsLayout &layout)
|
||||||
s.mentionUsersWithComma);
|
s.mentionUsersWithComma);
|
||||||
layout.addCheckbox("Show joined users (< 1000 chatters)", s.showJoins);
|
layout.addCheckbox("Show joined users (< 1000 chatters)", s.showJoins);
|
||||||
layout.addCheckbox("Show parted users (< 1000 chatters)", s.showParts);
|
layout.addCheckbox("Show parted users (< 1000 chatters)", s.showParts);
|
||||||
layout.addCheckbox("Lowercase domains (anti-phisching)",
|
layout.addCheckbox("Lowercase domains (anti-phishing)", s.lowercaseDomains);
|
||||||
s.lowercaseDomains);
|
|
||||||
layout.addCheckbox("Bold @usernames", s.boldUsernames);
|
layout.addCheckbox("Bold @usernames", s.boldUsernames);
|
||||||
layout.addDropdown<float>(
|
layout.addDropdown<float>(
|
||||||
"Username font weight", {"50", "Default", "75", "100"}, s.boldScale,
|
"Username font weight", {"50", "Default", "75", "100"}, s.boldScale,
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "util/Shortcut.hpp"
|
#include "util/Shortcut.hpp"
|
||||||
#include "util/StreamLink.hpp"
|
#include "util/StreamLink.hpp"
|
||||||
#include "widgets/Notebook.hpp"
|
#include "widgets/Notebook.hpp"
|
||||||
|
#include "widgets/TooltipWidget.hpp"
|
||||||
#include "widgets/Window.hpp"
|
#include "widgets/Window.hpp"
|
||||||
#include "widgets/dialogs/QualityPopup.hpp"
|
#include "widgets/dialogs/QualityPopup.hpp"
|
||||||
#include "widgets/dialogs/SelectChannelDialog.hpp"
|
#include "widgets/dialogs/SelectChannelDialog.hpp"
|
||||||
|
@ -188,6 +189,16 @@ Split::Split(QWidget *parent)
|
||||||
{
|
{
|
||||||
this->overlay_->hide();
|
this->overlay_->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getSettings()->pauseChatModifier.getEnum() != Qt::NoModifier &&
|
||||||
|
status == getSettings()->pauseChatModifier.getEnum())
|
||||||
|
{
|
||||||
|
this->view_->pause(PauseReason::KeyboardModifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->view_->unpause(PauseReason::KeyboardModifier);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->input_->ui_.textEdit->focused.connect(
|
this->input_->ui_.textEdit->focused.connect(
|
||||||
|
@ -401,6 +412,8 @@ void Split::leaveEvent(QEvent *event)
|
||||||
|
|
||||||
this->overlay_->hide();
|
this->overlay_->hide();
|
||||||
|
|
||||||
|
TooltipWidget::getInstance()->hide();
|
||||||
|
|
||||||
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,6 +301,11 @@ std::unique_ptr<QMenu> SplitHeader::createMainMenu()
|
||||||
// sub menu
|
// sub menu
|
||||||
auto moreMenu = new QMenu("More", this);
|
auto moreMenu = new QMenu("More", this);
|
||||||
|
|
||||||
|
|
||||||
|
moreMenu->addAction("Toggle moderation mode", this->split_, [this]() {
|
||||||
|
this->split_->setModerationMode(!this->split_->getModerationMode());
|
||||||
|
});
|
||||||
|
|
||||||
if (dynamic_cast<TwitchChannel *>(this->split_->getChannel().get()))
|
if (dynamic_cast<TwitchChannel *>(this->split_->getChannel().get()))
|
||||||
{
|
{
|
||||||
moreMenu->addAction("Show viewer list", this->split_,
|
moreMenu->addAction("Show viewer list", this->split_,
|
||||||
|
|
Loading…
Reference in a new issue