Merge remote-tracking branch 'refs/remotes/fourtf/master'

This commit is contained in:
apa420 2018-05-14 00:58:54 +02:00
commit 69237bc46a
17 changed files with 278 additions and 123 deletions

View file

@ -154,7 +154,6 @@ SOURCES += \
src/widgets/settingspages/commandpage.cpp \
src/widgets/settingspages/emotespage.cpp \
src/widgets/settingspages/highlightingpage.cpp \
src/widgets/settingspages/ignoremessagespage.cpp \
src/widgets/settingspages/ignoreuserspage.cpp \
src/widgets/settingspages/keyboardsettingspage.cpp \
src/widgets/settingspages/logspage.cpp \
@ -192,6 +191,8 @@ SOURCES += \
src/controllers/commands/commandcontroller.cpp \
src/controllers/highlights/highlightcontroller.cpp \
src/controllers/highlights/highlightmodel.cpp \
src/controllers/ignores/ignorecontroller.cpp \
src/controllers/ignores/ignoremodel.cpp \
src/widgets/helper/editablemodelview.cpp \
src/controllers/accounts/accountcontroller.cpp \
src/controllers/accounts/accountmodel.cpp \
@ -289,7 +290,6 @@ HEADERS += \
src/widgets/settingspages/commandpage.hpp \
src/widgets/settingspages/emotespage.hpp \
src/widgets/settingspages/highlightingpage.hpp \
src/widgets/settingspages/ignoremessagespage.hpp \
src/widgets/settingspages/ignoreuserspage.hpp \
src/widgets/settingspages/keyboardsettingspage.hpp \
src/widgets/settingspages/logspage.hpp \
@ -335,6 +335,9 @@ HEADERS += \
src/controllers/highlights/highlightcontroller.hpp \
src/controllers/highlights/highlightphrase.hpp \
src/controllers/highlights/highlightmodel.hpp \
src/controllers/ignores/ignorecontroller.hpp \
src/controllers/ignores/ignorephrase.hpp \
src/controllers/ignores/ignoremodel.hpp \
src/widgets/helper/editablemodelview.hpp \
src/controllers/accounts/accountcontroller.hpp \
src/controllers/accounts/accountmodel.hpp \

View file

@ -2,6 +2,7 @@
#include "controllers/commands/commandcontroller.hpp"
#include "controllers/highlights/highlightcontroller.hpp"
#include "controllers/ignores/ignorecontroller.hpp"
#include "providers/twitch/pubsub.hpp"
#include "providers/twitch/twitchserver.hpp"
#include "singletons/accountmanager.hpp"
@ -66,6 +67,7 @@ void Application::construct()
this->logging = new singletons::LoggingManager;
this->commands = new controllers::commands::CommandController;
this->highlights = new controllers::highlights::HighlightController;
this->ignores = new controllers::ignores::IgnoreController;
this->accounts = new singletons::AccountManager;
this->emotes = new singletons::EmoteManager;
this->settings = new singletons::SettingManager;
@ -100,6 +102,7 @@ void Application::initialize()
this->resources->initialize();
this->highlights->initialize();
this->ignores->initialize();
this->emotes->initialize();

View file

@ -23,7 +23,10 @@ class CommandController;
namespace highlights {
class HighlightController;
}
namespace ignores {
class IgnoreController;
}
} // namespace controllers
namespace singletons {
@ -63,6 +66,7 @@ public:
singletons::LoggingManager *logging = nullptr;
controllers::commands::CommandController *commands = nullptr;
controllers::highlights::HighlightController *highlights = nullptr;
controllers::ignores::IgnoreController *ignores = nullptr;
singletons::AccountManager *accounts = nullptr;
singletons::EmoteManager *emotes = nullptr;
singletons::NativeMessagingManager *nativeMessaging = nullptr;

View file

@ -1,5 +1,6 @@
#pragma once
#include "util/rapidjson-helpers.hpp"
#include "util/serialize-custom.hpp"
#include <QRegularExpression>
@ -101,36 +102,14 @@ struct Deserialize<chatterino::controllers::highlights::HighlightPhrase> {
}
QString _pattern;
if (value.HasMember("pattern")) {
const rapidjson::Value &key = value["pattern"];
if (key.IsString()) {
_pattern = key.GetString();
}
}
bool _alert = true;
if (value.HasMember("alert")) {
const rapidjson::Value &alert = value["alert"];
if (alert.IsBool()) {
_alert = alert.GetBool();
}
}
bool _sound = false;
if (value.HasMember("sound")) {
const rapidjson::Value &sound = value["sound"];
if (sound.IsBool()) {
_sound = sound.GetBool();
}
}
bool _isRegex = false;
if (value.HasMember("regex")) {
const rapidjson::Value &regex = value["regex"];
if (regex.IsBool()) {
_isRegex = regex.GetBool();
}
}
chatterino::rj::getSafe(value, "pattern", _pattern);
chatterino::rj::getSafe(value, "alert", _alert);
chatterino::rj::getSafe(value, "sound", _sound);
chatterino::rj::getSafe(value, "regex", _isRegex);
return chatterino::controllers::highlights::HighlightPhrase(_pattern, _alert, _sound,
_isRegex);

View file

@ -0,0 +1,36 @@
#include "controllers/ignores/ignorecontroller.hpp"
#include "application.hpp"
#include "controllers/ignores/ignoremodel.hpp"
#include <cassert>
namespace chatterino {
namespace controllers {
namespace ignores {
void IgnoreController::initialize()
{
assert(!this->initialized);
this->initialized = true;
for (const IgnorePhrase &phrase : this->ignoresSetting.getValue()) {
this->phrases.appendItem(phrase);
}
this->phrases.delayedItemsChanged.connect([this] { //
this->ignoresSetting.setValue(this->phrases.getVector());
});
}
IgnoreModel *IgnoreController::createModel(QObject *parent)
{
IgnoreModel *model = new IgnoreModel(parent);
model->init(&this->phrases);
return model;
}
} // namespace ignores
} // namespace controllers
} // namespace chatterino

View file

@ -0,0 +1,31 @@
#pragma once
#include "controllers/ignores/ignorephrase.hpp"
#include "singletons/settingsmanager.hpp"
#include "util/signalvector2.hpp"
namespace chatterino {
namespace controllers {
namespace ignores {
class IgnoreModel;
class IgnoreController
{
public:
void initialize();
util::UnsortedSignalVector<IgnorePhrase> phrases;
IgnoreModel *createModel(QObject *parent);
private:
bool initialized = false;
singletons::ChatterinoSetting<std::vector<ignores::IgnorePhrase>> ignoresSetting = {
"/ignore/phrases"};
};
} // namespace ignores
} // namespace controllers
} // namespace chatterino

View file

@ -0,0 +1,35 @@
#include "ignoremodel.hpp"
#include "application.hpp"
#include "singletons/settingsmanager.hpp"
#include "util/standarditemhelper.hpp"
namespace chatterino {
namespace controllers {
namespace ignores {
// commandmodel
IgnoreModel::IgnoreModel(QObject *parent)
: util::SignalVectorModel<IgnorePhrase>(2, parent)
{
}
// turn a vector item into a model row
IgnorePhrase IgnoreModel::getItemFromRow(std::vector<QStandardItem *> &row)
{
// key, regex
return IgnorePhrase{row[0]->data(Qt::DisplayRole).toString(),
row[1]->data(Qt::CheckStateRole).toBool()};
}
// turns a row in the model into a vector item
void IgnoreModel::getRowFromItem(const IgnorePhrase &item, std::vector<QStandardItem *> &row)
{
util::setStringItem(row[0], item.getPattern());
util::setBoolItem(row[1], item.isRegex());
}
} // namespace ignores
} // namespace controllers
} // namespace chatterino

View file

@ -0,0 +1,31 @@
#pragma once
#include <QObject>
#include "controllers/ignores/ignorephrase.hpp"
#include "util/signalvectormodel.hpp"
namespace chatterino {
namespace controllers {
namespace ignores {
class IgnoreController;
class IgnoreModel : public util::SignalVectorModel<IgnorePhrase>
{
explicit IgnoreModel(QObject *parent);
protected:
// turn a vector item into a model row
virtual IgnorePhrase getItemFromRow(std::vector<QStandardItem *> &row) override;
// turns a row in the model into a vector item
virtual void getRowFromItem(const IgnorePhrase &item,
std::vector<QStandardItem *> &row) override;
friend class IgnoreController;
};
} // namespace ignores
} // namespace controllers
} // namespace chatterino

View file

@ -0,0 +1,95 @@
#pragma once
#include "util/rapidjson-helpers.hpp"
#include "util/serialize-custom.hpp"
#include <QRegularExpression>
#include <QString>
#include <pajlada/settings/serialize.hpp>
#include <memory>
namespace chatterino {
namespace controllers {
namespace ignores {
class IgnorePhrase
{
QString pattern;
bool _isRegex;
QRegularExpression regex;
public:
bool operator==(const IgnorePhrase &other) const
{
return std::tie(this->pattern, this->_isRegex) == std::tie(other.pattern, other._isRegex);
}
IgnorePhrase(const QString &_pattern, bool isRegex)
: pattern(_pattern)
, _isRegex(isRegex)
, regex(_isRegex ? _pattern : "\\b" + QRegularExpression::escape(_pattern) + "\\b",
QRegularExpression::CaseInsensitiveOption)
{
}
const QString &getPattern() const
{
return this->pattern;
}
bool isRegex() const
{
return this->_isRegex;
}
bool isValid() const
{
return !this->pattern.isEmpty() && this->regex.isValid();
}
bool isMatch(const QString &subject) const
{
return this->isValid() && this->regex.match(subject).hasMatch();
}
};
} // namespace ignores
} // namespace controllers
} // namespace chatterino
namespace pajlada {
namespace Settings {
template <>
struct Serialize<chatterino::controllers::ignores::IgnorePhrase> {
static rapidjson::Value get(const chatterino::controllers::ignores::IgnorePhrase &value,
rapidjson::Document::AllocatorType &a)
{
rapidjson::Value ret(rapidjson::kObjectType);
AddMember(ret, "pattern", value.getPattern(), a);
AddMember(ret, "regex", value.isRegex(), a);
return ret;
}
};
template <>
struct Deserialize<chatterino::controllers::ignores::IgnorePhrase> {
static chatterino::controllers::ignores::IgnorePhrase get(const rapidjson::Value &value)
{
if (!value.IsObject()) {
return chatterino::controllers::ignores::IgnorePhrase(QString(), false);
}
QString _pattern;
bool _isRegex = false;
chatterino::rj::getSafe(value, "pattern", _pattern);
chatterino::rj::getSafe(value, "regex", _isRegex);
return chatterino::controllers::ignores::IgnorePhrase(_pattern, _isRegex);
}
};
} // namespace Settings
} // namespace pajlada

View file

@ -2,6 +2,7 @@
#include "application.hpp"
#include "controllers/highlights/highlightcontroller.hpp"
#include "controllers/ignores/ignorecontroller.hpp"
#include "debug/log.hpp"
#include "providers/twitch/twitchchannel.hpp"
#include "singletons/accountmanager.hpp"
@ -54,10 +55,12 @@ TwitchMessageBuilder::TwitchMessageBuilder(Channel *_channel,
bool TwitchMessageBuilder::isIgnored() const
{
auto app = getApp();
std::shared_ptr<std::vector<QString>> ignoredKeywords = app->settings->getIgnoredKeywords();
for (const QString &keyword : *ignoredKeywords) {
if (this->originalMessage.contains(keyword, Qt::CaseInsensitive)) {
// TODO(pajlada): Do we need to check if the phrase is valid first?
for (const auto &phrase : app->ignores->phrases.getVector()) {
if (phrase.isMatch(this->originalMessage)) {
debug::Log("Blocking message because it contains ignored phrase {}",
phrase.getPattern());
return true;
}
}

View file

@ -19,7 +19,6 @@ void _actuallyRegisterSetting(std::weak_ptr<pajlada::Settings::ISettingData> set
}
SettingManager::SettingManager()
: _ignoredKeywords(new std::vector<QString>)
{
qDebug() << "init SettingManager";
@ -37,7 +36,6 @@ SettingManager::SettingManager()
void SettingManager::initialize()
{
this->moderationActions.connect([this](auto, auto) { this->updateModerationActions(); });
this->ignoredKeywords.connect([this](auto, auto) { this->updateIgnoredKeywords(); });
this->timestampFormat.connect([](auto, auto) {
auto app = getApp();
@ -151,11 +149,6 @@ std::vector<ModerationAction> SettingManager::getModerationActions() const
return this->_moderationActions;
}
const std::shared_ptr<std::vector<QString>> SettingManager::getIgnoredKeywords() const
{
return this->_ignoredKeywords;
}
void SettingManager::updateModerationActions()
{
auto app = getApp();
@ -224,21 +217,5 @@ void SettingManager::updateModerationActions()
}
}
void SettingManager::updateIgnoredKeywords()
{
static QRegularExpression newLineRegex("(\r\n?|\n)+");
auto items = new std::vector<QString>();
for (const QString &line : this->ignoredKeywords.getValue().split(newLineRegex)) {
QString line2 = line.trimmed();
if (!line2.isEmpty()) {
items->push_back(line2);
}
}
this->_ignoredKeywords = std::shared_ptr<std::vector<QString>>(items);
}
} // namespace singletons
} // namespace chatterino

View file

@ -86,7 +86,6 @@ public:
/// Ingored Users
BoolSetting enableTwitchIgnoredUsers = {"/ignore/enableTwitchIgnoredUsers", true};
QStringSetting ignoredKeywords = {"/ignore/ignoredKeywords", ""};
/// Moderation
QStringSetting moderationActions = {"/moderation/actions", "/ban {user}\n/timeout {user} 300"};
@ -123,16 +122,13 @@ public:
void recallSnapshot();
std::vector<ModerationAction> getModerationActions() const;
const std::shared_ptr<std::vector<QString>> getIgnoredKeywords() const;
pajlada::Signals::NoArgSignal wordFlagsChanged;
private:
std::vector<ModerationAction> _moderationActions;
std::unique_ptr<rapidjson::Document> snapshot;
std::shared_ptr<std::vector<QString>> _ignoredKeywords;
void updateModerationActions();
void updateIgnoredKeywords();
messages::MessageElement::Flags wordFlags = messages::MessageElement::Default;

View file

@ -159,6 +159,9 @@ void SplitInput::installKeyPressedEvent()
}
this->prevIndex = this->prevMsg.size();
} else if (event->key() == Qt::Key_Up) {
if ((event->modifiers() & Qt::ShiftModifier) != 0) {
return;
}
if (event->modifiers() == Qt::AltModifier) {
SplitContainer *page =
static_cast<SplitContainer *>(this->chatWidget->parentWidget());
@ -184,6 +187,9 @@ void SplitInput::installKeyPressedEvent()
}
}
} else if (event->key() == Qt::Key_Down) {
if ((event->modifiers() & Qt::ShiftModifier) != 0) {
return;
}
if (event->modifiers() == Qt::AltModifier) {
SplitContainer *page =
static_cast<SplitContainer *>(this->chatWidget->parentWidget());

View file

@ -11,7 +11,6 @@
#include "widgets/settingspages/emotespage.hpp"
#include "widgets/settingspages/externaltoolspage.hpp"
#include "widgets/settingspages/highlightingpage.hpp"
#include "widgets/settingspages/ignoremessagespage.hpp"
#include "widgets/settingspages/ignoreuserspage.hpp"
#include "widgets/settingspages/keyboardsettingspage.hpp"
#include "widgets/settingspages/logspage.hpp"
@ -89,7 +88,6 @@ void SettingsDialog::addTabs()
this->addTab(new settingspages::CommandPage);
// this->addTab(new settingspages::EmotesPage);
this->addTab(new settingspages::HighlightingPage);
// this->addTab(new settingspages::IgnoreMessagesPage);
this->addTab(new settingspages::IgnoreUsersPage);
this->ui.tabContainer->addSpacing(16);

View file

@ -1,40 +0,0 @@
#include "ignoremessagespage.hpp"
#include "application.hpp"
#include "util/layoutcreator.hpp"
#include <QLabel>
#include <QTextEdit>
namespace chatterino {
namespace widgets {
namespace settingspages {
IgnoreMessagesPage::IgnoreMessagesPage()
: SettingsPage("Ignore Messages", "")
{
auto app = getApp();
util::LayoutCreator<IgnoreMessagesPage> layoutCreator(this);
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
layout.emplace<QLabel>("Ignored keywords:");
QTextEdit *textEdit = layout.emplace<QTextEdit>().getElement();
textEdit->setPlainText(app->settings->ignoredKeywords);
QObject::connect(textEdit, &QTextEdit::textChanged,
[this] { this->keywordsUpdated.start(200); });
QObject::connect(&this->keywordsUpdated, &QTimer::timeout, [textEdit, app] {
QString text = textEdit->toPlainText();
app->settings->ignoredKeywords = text;
});
// ---- misc
this->keywordsUpdated.setSingleShot(true);
}
} // namespace settingspages
} // namespace widgets
} // namespace chatterino

View file

@ -1,21 +0,0 @@
#pragma once
#include "widgets/settingspages/settingspage.hpp"
#include <QTimer>
namespace chatterino {
namespace widgets {
namespace settingspages {
class IgnoreMessagesPage : public SettingsPage
{
public:
IgnoreMessagesPage();
QTimer keywordsUpdated;
};
} // namespace settingspages
} // namespace widgets
} // namespace chatterino

View file

@ -1,15 +1,19 @@
#include "ignoreuserspage.hpp"
#include "application.hpp"
#include "controllers/ignores/ignorecontroller.hpp"
#include "controllers/ignores/ignoremodel.hpp"
#include "singletons/accountmanager.hpp"
#include "singletons/settingsmanager.hpp"
#include "util/layoutcreator.hpp"
#include "widgets/helper/editablemodelview.hpp"
#include <QCheckBox>
#include <QGroupBox>
#include <QLabel>
#include <QListView>
#include <QPushButton>
#include <QTableView>
#include <QVBoxLayout>
// clang-format off
@ -60,7 +64,22 @@ IgnoreUsersPage::IgnoreUsersPage()
// messages
auto messages = tabs.appendTab(new QVBoxLayout, "Messages");
{
messages.emplace<QLabel>("wip");
helper::EditableModelView *view =
*messages.emplace<helper::EditableModelView>(app->ignores->createModel(nullptr));
view->setTitles({"Pattern", "Regex"});
view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
view->getTableView()->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
// fourtf: make class extrend BaseWidget and add this to dpiChanged
QTimer::singleShot(1, [view] {
view->getTableView()->resizeColumnsToContents();
view->getTableView()->setColumnWidth(0, 200);
});
view->addButtonPressed.connect([] {
getApp()->ignores->phrases.appendItem(
controllers::ignores::IgnorePhrase{"my phrase", false});
});
}
auto label = layout.emplace<QLabel>(INFO);