mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
added regex highlights
This commit is contained in:
parent
ba4173822e
commit
b95388107f
|
@ -191,7 +191,10 @@ SOURCES += \
|
||||||
src/controllers/commands/commandcontroller.cpp \
|
src/controllers/commands/commandcontroller.cpp \
|
||||||
src/controllers/highlights/highlightcontroller.cpp \
|
src/controllers/highlights/highlightcontroller.cpp \
|
||||||
src/controllers/highlights/highlightmodel.cpp \
|
src/controllers/highlights/highlightmodel.cpp \
|
||||||
src/widgets/helper/editablemodelview.cpp
|
src/widgets/helper/editablemodelview.cpp \
|
||||||
|
src/controllers/accounts/accountcontroller.cpp \
|
||||||
|
src/controllers/accounts/accountmodel.cpp \
|
||||||
|
src/controllers/accounts/account.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/precompiled_header.hpp \
|
src/precompiled_header.hpp \
|
||||||
|
@ -330,7 +333,11 @@ HEADERS += \
|
||||||
src/controllers/highlights/highlightcontroller.hpp \
|
src/controllers/highlights/highlightcontroller.hpp \
|
||||||
src/controllers/highlights/highlightphrase.hpp \
|
src/controllers/highlights/highlightphrase.hpp \
|
||||||
src/controllers/highlights/highlightmodel.hpp \
|
src/controllers/highlights/highlightmodel.hpp \
|
||||||
src/widgets/helper/editablemodelview.hpp
|
src/widgets/helper/editablemodelview.hpp \
|
||||||
|
src/controllers/accounts/accountcontroller.hpp \
|
||||||
|
src/controllers/accounts/accountmodel.hpp \
|
||||||
|
src/controllers/accounts/account.hpp \
|
||||||
|
src/util/sharedptrelementless.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources/resources.qrc
|
resources/resources.qrc
|
||||||
|
|
|
@ -203,7 +203,7 @@ void Application::initialize()
|
||||||
this->twitch.pubsub->listenToWhispers(this->accounts->Twitch.getCurrent()); //
|
this->twitch.pubsub->listenToWhispers(this->accounts->Twitch.getCurrent()); //
|
||||||
};
|
};
|
||||||
|
|
||||||
this->accounts->Twitch.userChanged.connect(RequestModerationActions);
|
this->accounts->Twitch.currentUserChanged.connect(RequestModerationActions);
|
||||||
|
|
||||||
RequestModerationActions();
|
RequestModerationActions();
|
||||||
}
|
}
|
||||||
|
|
30
src/controllers/accounts/account.cpp
Normal file
30
src/controllers/accounts/account.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include "account.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace accounts {
|
||||||
|
|
||||||
|
Account::Account(const QString &category)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &Account::getCategory() const
|
||||||
|
{
|
||||||
|
return this->category;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Account::operator<(const Account &other) const
|
||||||
|
{
|
||||||
|
if (this->category < other.category) {
|
||||||
|
return true;
|
||||||
|
} else if (this->category == other.category) {
|
||||||
|
if (this->toString() < other.toString()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace accounts
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
25
src/controllers/accounts/account.hpp
Normal file
25
src/controllers/accounts/account.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace accounts {
|
||||||
|
|
||||||
|
class Account
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Account(const QString &category);
|
||||||
|
|
||||||
|
virtual QString toString() const = 0;
|
||||||
|
const QString &getCategory() const;
|
||||||
|
|
||||||
|
bool operator<(const Account &other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString category;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace accounts
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
24
src/controllers/accounts/accountcontroller.cpp
Normal file
24
src/controllers/accounts/accountcontroller.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "accountcontroller.hpp"
|
||||||
|
|
||||||
|
#include "controllers/accounts/accountmodel.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace accounts {
|
||||||
|
|
||||||
|
AccountController::AccountController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountModel *AccountController::createModel(QObject *parent)
|
||||||
|
{
|
||||||
|
AccountModel *model = new AccountModel(parent);
|
||||||
|
|
||||||
|
//(util::BaseSignalVector<stdAccount> *)
|
||||||
|
model->init(&this->accounts);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace accounts
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
29
src/controllers/accounts/accountcontroller.hpp
Normal file
29
src/controllers/accounts/accountcontroller.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "controllers/accounts/account.hpp"
|
||||||
|
#include "util/sharedptrelementless.hpp"
|
||||||
|
#include "util/signalvector2.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace accounts {
|
||||||
|
|
||||||
|
class AccountModel;
|
||||||
|
|
||||||
|
class AccountController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccountController();
|
||||||
|
|
||||||
|
AccountModel *createModel(QObject *parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
util::SortedSignalVector<std::shared_ptr<Account>, util::SharedPtrElementLess<Account>>
|
||||||
|
accounts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace accounts
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
27
src/controllers/accounts/accountmodel.cpp
Normal file
27
src/controllers/accounts/accountmodel.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "accountmodel.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace accounts {
|
||||||
|
|
||||||
|
AccountModel::AccountModel(QObject *parent)
|
||||||
|
: util::SignalVectorModel<std::shared_ptr<Account>>(1, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn a vector item into a model row
|
||||||
|
std::shared_ptr<Account> AccountModel::getItemFromRow(std::vector<QStandardItem *> &row)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// turns a row in the model into a vector item
|
||||||
|
void AccountModel::getRowFromItem(const std::shared_ptr<Account> &item,
|
||||||
|
std::vector<QStandardItem *> &row)
|
||||||
|
{
|
||||||
|
row[0]->setData(item->toString(), Qt::DisplayRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace accounts
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
30
src/controllers/accounts/accountmodel.hpp
Normal file
30
src/controllers/accounts/accountmodel.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma
|
||||||
|
|
||||||
|
#include "controllers/accounts/account.hpp"
|
||||||
|
#include "util/signalvectormodel.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace accounts {
|
||||||
|
|
||||||
|
class AccountController;
|
||||||
|
|
||||||
|
class AccountModel : public util::SignalVectorModel<std::shared_ptr<Account>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AccountModel(QObject *parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// turn a vector item into a model row
|
||||||
|
virtual std::shared_ptr<Account> getItemFromRow(std::vector<QStandardItem *> &row) override;
|
||||||
|
|
||||||
|
// turns a row in the model into a vector item
|
||||||
|
virtual void getRowFromItem(const std::shared_ptr<Account> &item,
|
||||||
|
std::vector<QStandardItem *> &row) override;
|
||||||
|
|
||||||
|
friend class AccountController;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace accounts
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
|
@ -45,10 +45,10 @@ HighlightPhrase HighlightModel::getItemFromRow(std::vector<QStandardItem *> &row
|
||||||
// turns a row in the model into a vector item
|
// turns a row in the model into a vector item
|
||||||
void HighlightModel::getRowFromItem(const HighlightPhrase &item, std::vector<QStandardItem *> &row)
|
void HighlightModel::getRowFromItem(const HighlightPhrase &item, std::vector<QStandardItem *> &row)
|
||||||
{
|
{
|
||||||
util::setStringItem(row[0], item.key);
|
util::setStringItem(row[0], item.getPattern());
|
||||||
util::setBoolItem(row[1], item.alert);
|
util::setBoolItem(row[1], item.getAlert());
|
||||||
util::setBoolItem(row[2], item.sound);
|
util::setBoolItem(row[2], item.getSound());
|
||||||
util::setBoolItem(row[3], item.regex);
|
util::setBoolItem(row[3], item.isRegex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HighlightModel::afterInit()
|
void HighlightModel::afterInit()
|
||||||
|
|
|
@ -2,24 +2,71 @@
|
||||||
|
|
||||||
#include "util/serialize-custom.hpp"
|
#include "util/serialize-custom.hpp"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <memory>
|
||||||
#include <pajlada/settings/serialize.hpp>
|
#include <pajlada/settings/serialize.hpp>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace controllers {
|
namespace controllers {
|
||||||
namespace highlights {
|
namespace highlights {
|
||||||
|
|
||||||
struct HighlightPhrase {
|
class HighlightPhrase
|
||||||
QString key;
|
{
|
||||||
|
QString pattern;
|
||||||
bool alert;
|
bool alert;
|
||||||
bool sound;
|
bool sound;
|
||||||
bool regex;
|
bool _isRegex;
|
||||||
|
QRegularExpression regex;
|
||||||
|
|
||||||
|
public:
|
||||||
bool operator==(const HighlightPhrase &other) const
|
bool operator==(const HighlightPhrase &other) const
|
||||||
{
|
{
|
||||||
return std::tie(this->key, this->sound, this->alert, this->regex) ==
|
return std::tie(this->pattern, this->sound, this->alert, this->_isRegex) ==
|
||||||
std::tie(other.key, other.sound, other.alert, other.regex);
|
std::tie(other.pattern, other.sound, other.alert, other._isRegex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HighlightPhrase(const QString &_pattern, bool _alert, bool _sound, bool isRegex)
|
||||||
|
: pattern(_pattern)
|
||||||
|
, alert(_alert)
|
||||||
|
, sound(_sound)
|
||||||
|
, _isRegex(isRegex)
|
||||||
|
, regex(_isRegex ? _pattern : "\b" + QRegularExpression::escape(_pattern) + "\b",
|
||||||
|
QRegularExpression::CaseInsensitiveOption)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &getPattern() const
|
||||||
|
{
|
||||||
|
return this->pattern;
|
||||||
|
}
|
||||||
|
bool getAlert() const
|
||||||
|
{
|
||||||
|
return this->alert;
|
||||||
|
}
|
||||||
|
bool getSound() const
|
||||||
|
{
|
||||||
|
return this->sound;
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// const QRegularExpression &getRegex() const
|
||||||
|
// {
|
||||||
|
// return this->regex;
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
} // namespace highlights
|
} // namespace highlights
|
||||||
} // namespace controllers
|
} // namespace controllers
|
||||||
|
@ -35,10 +82,10 @@ struct Serialize<chatterino::controllers::highlights::HighlightPhrase> {
|
||||||
{
|
{
|
||||||
rapidjson::Value ret(rapidjson::kObjectType);
|
rapidjson::Value ret(rapidjson::kObjectType);
|
||||||
|
|
||||||
AddMember(ret, "key", value.key, a);
|
AddMember(ret, "pattern", value.getPattern(), a);
|
||||||
AddMember(ret, "alert", value.alert, a);
|
AddMember(ret, "alert", value.getAlert(), a);
|
||||||
AddMember(ret, "sound", value.sound, a);
|
AddMember(ret, "sound", value.getSound(), a);
|
||||||
AddMember(ret, "regex", value.regex, a);
|
AddMember(ret, "regex", value.isRegex(), a);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -48,40 +95,45 @@ template <>
|
||||||
struct Deserialize<chatterino::controllers::highlights::HighlightPhrase> {
|
struct Deserialize<chatterino::controllers::highlights::HighlightPhrase> {
|
||||||
static chatterino::controllers::highlights::HighlightPhrase get(const rapidjson::Value &value)
|
static chatterino::controllers::highlights::HighlightPhrase get(const rapidjson::Value &value)
|
||||||
{
|
{
|
||||||
chatterino::controllers::highlights::HighlightPhrase ret;
|
|
||||||
if (!value.IsObject()) {
|
if (!value.IsObject()) {
|
||||||
return ret;
|
return chatterino::controllers::highlights::HighlightPhrase(QString(), true, false,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.HasMember("key")) {
|
QString _pattern;
|
||||||
const rapidjson::Value &key = value["key"];
|
if (value.HasMember("pattern")) {
|
||||||
|
const rapidjson::Value &key = value["pattern"];
|
||||||
if (key.IsString()) {
|
if (key.IsString()) {
|
||||||
ret.key = key.GetString();
|
_pattern = key.GetString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _alert = true;
|
||||||
if (value.HasMember("alert")) {
|
if (value.HasMember("alert")) {
|
||||||
const rapidjson::Value &alert = value["alert"];
|
const rapidjson::Value &alert = value["alert"];
|
||||||
if (alert.IsBool()) {
|
if (alert.IsBool()) {
|
||||||
ret.alert = alert.GetBool();
|
_alert = alert.GetBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _sound = false;
|
||||||
if (value.HasMember("sound")) {
|
if (value.HasMember("sound")) {
|
||||||
const rapidjson::Value &sound = value["sound"];
|
const rapidjson::Value &sound = value["sound"];
|
||||||
if (sound.IsBool()) {
|
if (sound.IsBool()) {
|
||||||
ret.sound = sound.GetBool();
|
_sound = sound.GetBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _isRegex = false;
|
||||||
if (value.HasMember("regex")) {
|
if (value.HasMember("regex")) {
|
||||||
const rapidjson::Value ®ex = value["regex"];
|
const rapidjson::Value ®ex = value["regex"];
|
||||||
if (regex.IsBool()) {
|
if (regex.IsBool()) {
|
||||||
ret.regex = regex.GetBool();
|
_isRegex = regex.GetBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return chatterino::controllers::highlights::HighlightPhrase(_pattern, _alert, _sound,
|
||||||
|
_isRegex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,77 +61,79 @@ void IrcMessageHandler::handleRoomStateMessage(Communi::IrcMessage *message)
|
||||||
void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message)
|
void IrcMessageHandler::handleClearChatMessage(Communi::IrcMessage *message)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
// check parameter count
|
// // check parameter count
|
||||||
if (message->parameters().length() < 1) {
|
// if (message->parameters().length() < 1) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
QString chanName;
|
// QString chanName;
|
||||||
if (!TrimChannelName(message->parameter(0), chanName)) {
|
// if (!TrimChannelName(message->parameter(0), chanName)) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
auto app = getApp();
|
// auto app = getApp();
|
||||||
|
|
||||||
// get channel
|
// // get channel
|
||||||
auto chan = app->twitch.server->getChannelOrEmpty(chanName);
|
// auto chan = app->twitch.server->getChannelOrEmpty(chanName);
|
||||||
|
|
||||||
if (chan->isEmpty()) {
|
// if (chan->isEmpty()) {
|
||||||
debug::Log("[IrcMessageHandler:handleClearChatMessage] Twitch channel {} not found",
|
// debug::Log("[IrcMessageHandler:handleClearChatMessage] Twitch channel {} not found",
|
||||||
chanName);
|
// chanName);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// check if the chat has been cleared by a moderator
|
// // check if the chat has been cleared by a moderator
|
||||||
if (message->parameters().length() == 1) {
|
// if (message->parameters().length() == 1) {
|
||||||
chan->addMessage(Message::createSystemMessage("Chat has been cleared by a moderator."));
|
// chan->addMessage(Message::createSystemMessage("Chat has been cleared by a
|
||||||
|
// moderator."));
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// get username, duration and message of the timed out user
|
// // get username, duration and message of the timed out user
|
||||||
QString username = message->parameter(1);
|
// QString username = message->parameter(1);
|
||||||
QString durationInSeconds, reason;
|
// QString durationInSeconds, reason;
|
||||||
QVariant v = message->tag("ban-duration");
|
// QVariant v = message->tag("ban-duration");
|
||||||
if (v.isValid()) {
|
// if (v.isValid()) {
|
||||||
durationInSeconds = v.toString();
|
// durationInSeconds = v.toString();
|
||||||
}
|
// }
|
||||||
|
|
||||||
v = message->tag("ban-reason");
|
// v = message->tag("ban-reason");
|
||||||
if (v.isValid()) {
|
// if (v.isValid()) {
|
||||||
reason = v.toString();
|
// reason = v.toString();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// add the notice that the user has been timed out
|
// // add the notice that the user has been timed out
|
||||||
LimitedQueueSnapshot<MessagePtr> snapshot = chan->getMessageSnapshot();
|
// LimitedQueueSnapshot<MessagePtr> snapshot = chan->getMessageSnapshot();
|
||||||
bool addMessage = true;
|
// bool addMessage = true;
|
||||||
int snapshotLength = snapshot.getLength();
|
// int snapshotLength = snapshot.getLength();
|
||||||
|
|
||||||
for (int i = std::max(0, snapshotLength - 20); i < snapshotLength; i++) {
|
// for (int i = std::max(0, snapshotLength - 20); i < snapshotLength; i++) {
|
||||||
auto &s = snapshot[i];
|
// auto &s = snapshot[i];
|
||||||
if (s->flags.HasFlag(Message::Timeout) && s->timeoutUser == username) {
|
// if (s->flags.HasFlag(Message::Timeout) && s->timeoutUser == username) {
|
||||||
MessagePtr replacement(
|
// MessagePtr replacement(
|
||||||
Message::createTimeoutMessage(username, durationInSeconds, reason, true));
|
// Message::createTimeoutMessage(username, durationInSeconds, reason, true));
|
||||||
chan->replaceMessage(s, replacement);
|
// chan->replaceMessage(s, replacement);
|
||||||
addMessage = false;
|
// addMessage = false;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (addMessage) {
|
// if (addMessage) {
|
||||||
chan->addMessage(Message::createTimeoutMessage(username, durationInSeconds, reason, false));
|
// chan->addMessage(Message::createTimeoutMessage(username, durationInSeconds, reason,
|
||||||
}
|
// false));
|
||||||
|
// }
|
||||||
|
|
||||||
// disable the messages from the user
|
// // disable the messages from the user
|
||||||
for (int i = 0; i < snapshotLength; i++) {
|
// for (int i = 0; i < snapshotLength; i++) {
|
||||||
auto &s = snapshot[i];
|
// auto &s = snapshot[i];
|
||||||
if (!(s->flags & Message::Timeout) && s->loginName == username) {
|
// if (!(s->flags & Message::Timeout) && s->loginName == username) {
|
||||||
s->flags.EnableFlag(Message::Disabled);
|
// s->flags.EnableFlag(Message::Disabled);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// refresh all
|
// // refresh all
|
||||||
app->windows->repaintVisibleChatWidgets(chan.get());
|
// app->windows->repaintVisibleChatWidgets(chan.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
||||||
|
@ -213,28 +215,28 @@ void IrcMessageHandler::handleModeMessage(Communi::IrcMessage *message)
|
||||||
void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
|
void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
auto app = getApp();
|
// auto app = getApp();
|
||||||
MessagePtr msg = Message::createSystemMessage(message->content());
|
// MessagePtr msg = Message::createSystemMessage(message->content());
|
||||||
|
|
||||||
QString channelName;
|
// QString channelName;
|
||||||
if (!TrimChannelName(message->target(), channelName)) {
|
// if (!TrimChannelName(message->target(), channelName)) {
|
||||||
// Notice wasn't targeted at a single channel, send to all twitch channels
|
// // Notice wasn't targeted at a single channel, send to all twitch channels
|
||||||
app->twitch.server->forEachChannelAndSpecialChannels([msg](const auto &c) {
|
// app->twitch.server->forEachChannelAndSpecialChannels([msg](const auto &c) {
|
||||||
c->addMessage(msg); //
|
// c->addMessage(msg); //
|
||||||
});
|
// });
|
||||||
|
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
auto channel = app->twitch.server->getChannelOrEmpty(channelName);
|
// auto channel = app->twitch.server->getChannelOrEmpty(channelName);
|
||||||
|
|
||||||
if (channel->isEmpty()) {
|
// if (channel->isEmpty()) {
|
||||||
debug::Log("[IrcManager:handleNoticeMessage] Channel {} not found in channel manager",
|
// debug::Log("[IrcManager:handleNoticeMessage] Channel {} not found in channel manager",
|
||||||
channelName);
|
// channelName);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
channel->addMessage(msg);
|
// channel->addMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrcMessageHandler::handleWriteConnectionNoticeMessage(Communi::IrcNoticeMessage *message)
|
void IrcMessageHandler::handleWriteConnectionNoticeMessage(Communi::IrcNoticeMessage *message)
|
||||||
|
|
|
@ -7,7 +7,8 @@ namespace twitch {
|
||||||
|
|
||||||
TwitchAccount::TwitchAccount(const QString &_username, const QString &_oauthToken,
|
TwitchAccount::TwitchAccount(const QString &_username, const QString &_oauthToken,
|
||||||
const QString &_oauthClient, const QString &_userID)
|
const QString &_oauthClient, const QString &_userID)
|
||||||
: oauthClient(_oauthClient)
|
: controllers::accounts::Account("Twitch")
|
||||||
|
, oauthClient(_oauthClient)
|
||||||
, oauthToken(_oauthToken)
|
, oauthToken(_oauthToken)
|
||||||
, userName(_username)
|
, userName(_username)
|
||||||
, userId(_userID)
|
, userId(_userID)
|
||||||
|
@ -15,6 +16,11 @@ TwitchAccount::TwitchAccount(const QString &_username, const QString &_oauthToke
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString TwitchAccount::toString() const
|
||||||
|
{
|
||||||
|
return this->getUserName();
|
||||||
|
}
|
||||||
|
|
||||||
const QString &TwitchAccount::getUserName() const
|
const QString &TwitchAccount::getUserName() const
|
||||||
{
|
{
|
||||||
return this->userName;
|
return this->userName;
|
||||||
|
|
|
@ -3,16 +3,20 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include "controllers/accounts/account.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace providers {
|
namespace providers {
|
||||||
namespace twitch {
|
namespace twitch {
|
||||||
|
|
||||||
class TwitchAccount
|
class TwitchAccount : public controllers::accounts::Account
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TwitchAccount(const QString &username, const QString &oauthToken, const QString &oauthClient,
|
TwitchAccount(const QString &username, const QString &oauthToken, const QString &oauthClient,
|
||||||
const QString &_userID);
|
const QString &_userID);
|
||||||
|
|
||||||
|
virtual QString toString() const override;
|
||||||
|
|
||||||
const QString &getUserName() const;
|
const QString &getUserName() const;
|
||||||
const QString &getOAuthToken() const;
|
const QString &getOAuthToken() const;
|
||||||
const QString &getOAuthClient() const;
|
const QString &getOAuthClient() const;
|
||||||
|
|
|
@ -94,7 +94,7 @@ void TwitchAccountManager::reloadUsers()
|
||||||
debug::Log("User {} already exists, and values updated!", userData.username);
|
debug::Log("User {} already exists, and values updated!", userData.username);
|
||||||
if (userData.username == this->getCurrent()->getUserName()) {
|
if (userData.username == this->getCurrent()->getUserName()) {
|
||||||
debug::Log("It was the current user, so we need to reconnect stuff!");
|
debug::Log("It was the current user, so we need to reconnect stuff!");
|
||||||
this->userChanged.invoke();
|
this->currentUserChanged.invoke();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case AddUserResponse::UserAdded: {
|
case AddUserResponse::UserAdded: {
|
||||||
|
@ -126,7 +126,7 @@ void TwitchAccountManager::load()
|
||||||
this->currentUser = this->anonymousUser;
|
this->currentUser = this->anonymousUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->userChanged.invoke();
|
this->currentUserChanged.invoke();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "providers/twitch/twitchaccount.hpp"
|
#include "providers/twitch/twitchaccount.hpp"
|
||||||
|
#include "util/sharedptrelementless.hpp"
|
||||||
|
#include "util/signalvector2.hpp"
|
||||||
|
|
||||||
#include <pajlada/settings/setting.hpp>
|
#include <pajlada/settings/setting.hpp>
|
||||||
|
|
||||||
|
@ -47,9 +49,13 @@ public:
|
||||||
bool removeUser(const QString &username);
|
bool removeUser(const QString &username);
|
||||||
|
|
||||||
pajlada::Settings::Setting<std::string> currentUsername = {"/accounts/current", ""};
|
pajlada::Settings::Setting<std::string> currentUsername = {"/accounts/current", ""};
|
||||||
pajlada::Signals::NoArgSignal userChanged;
|
pajlada::Signals::NoArgSignal currentUserChanged;
|
||||||
pajlada::Signals::NoArgSignal userListUpdated;
|
pajlada::Signals::NoArgSignal userListUpdated;
|
||||||
|
|
||||||
|
util::SortedSignalVector<std::shared_ptr<TwitchAccount>,
|
||||||
|
util::SharedPtrElementLess<TwitchAccount>>
|
||||||
|
accounts;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class AddUserResponse {
|
enum class AddUserResponse {
|
||||||
UserAlreadyExists,
|
UserAlreadyExists,
|
||||||
|
|
|
@ -45,7 +45,7 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection
|
||||||
this->refreshLiveStatus(); //
|
this->refreshLiveStatus(); //
|
||||||
});
|
});
|
||||||
|
|
||||||
this->managedConnect(app->accounts->Twitch.userChanged, [this]() { this->setMod(false); });
|
this->managedConnect(app->accounts->Twitch.currentUserChanged, [this]() { this->setMod(false); });
|
||||||
|
|
||||||
auto refreshPubSubState = [=]() {
|
auto refreshPubSubState = [=]() {
|
||||||
if (!this->hasModRights()) {
|
if (!this->hasModRights()) {
|
||||||
|
@ -64,7 +64,7 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection
|
||||||
|
|
||||||
this->userStateChanged.connect(refreshPubSubState);
|
this->userStateChanged.connect(refreshPubSubState);
|
||||||
this->roomIDchanged.connect(refreshPubSubState);
|
this->roomIDchanged.connect(refreshPubSubState);
|
||||||
this->managedConnect(app->accounts->Twitch.userChanged, refreshPubSubState);
|
this->managedConnect(app->accounts->Twitch.currentUserChanged, refreshPubSubState);
|
||||||
refreshPubSubState();
|
refreshPubSubState();
|
||||||
|
|
||||||
this->fetchMessages.connect([this] {
|
this->fetchMessages.connect([this] {
|
||||||
|
|
|
@ -404,10 +404,9 @@ void TwitchMessageBuilder::parseHighlights()
|
||||||
app->highlights->phrases.getVector();
|
app->highlights->phrases.getVector();
|
||||||
|
|
||||||
if (app->settings->enableHighlightsSelf && currentUsername.size() > 0) {
|
if (app->settings->enableHighlightsSelf && currentUsername.size() > 0) {
|
||||||
controllers::highlights::HighlightPhrase selfHighlight;
|
controllers::highlights::HighlightPhrase selfHighlight(
|
||||||
selfHighlight.key = currentUsername;
|
currentUsername, app->settings->enableHighlightTaskbar,
|
||||||
selfHighlight.sound = app->settings->enableHighlightSound;
|
app->settings->enableHighlightSound, false);
|
||||||
selfHighlight.alert = app->settings->enableHighlightTaskbar;
|
|
||||||
activeHighlights.emplace_back(std::move(selfHighlight));
|
activeHighlights.emplace_back(std::move(selfHighlight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,26 +418,17 @@ void TwitchMessageBuilder::parseHighlights()
|
||||||
|
|
||||||
if (!blackList.contains(this->ircMessage->nick(), Qt::CaseInsensitive)) {
|
if (!blackList.contains(this->ircMessage->nick(), Qt::CaseInsensitive)) {
|
||||||
for (const controllers::highlights::HighlightPhrase &highlight : activeHighlights) {
|
for (const controllers::highlights::HighlightPhrase &highlight : activeHighlights) {
|
||||||
int index = -1;
|
if (highlight.isMatch(this->originalMessage)) {
|
||||||
|
debug::Log("Highlight because {} matches {}", this->originalMessage,
|
||||||
while ((index = this->originalMessage.indexOf(highlight.key, index + 1,
|
highlight.getPattern());
|
||||||
Qt::CaseInsensitive)) != -1) {
|
|
||||||
if ((index != 0 && this->originalMessage[index - 1] != ' ') ||
|
|
||||||
(index + highlight.key.length() != this->originalMessage.length() &&
|
|
||||||
this->originalMessage[index + highlight.key.length()] != ' ')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug::Log("Highlight because {} contains {}", this->originalMessage,
|
|
||||||
highlight.key);
|
|
||||||
doHighlight = true;
|
doHighlight = true;
|
||||||
|
|
||||||
if (highlight.sound) {
|
if (highlight.getAlert()) {
|
||||||
playSound = true;
|
doAlert = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (highlight.alert) {
|
if (highlight.getSound()) {
|
||||||
doAlert = true;
|
playSound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playSound && doAlert) {
|
if (playSound && doAlert) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ TwitchServer::TwitchServer()
|
||||||
|
|
||||||
void TwitchServer::initialize()
|
void TwitchServer::initialize()
|
||||||
{
|
{
|
||||||
getApp()->accounts->Twitch.userChanged.connect(
|
getApp()->accounts->Twitch.currentUserChanged.connect(
|
||||||
[this]() { util::postToThread([this] { this->connect(); }); });
|
[this]() { util::postToThread([this] { this->connect(); }); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ EmoteManager::EmoteManager()
|
||||||
|
|
||||||
void EmoteManager::initialize()
|
void EmoteManager::initialize()
|
||||||
{
|
{
|
||||||
getApp()->accounts->Twitch.userChanged.connect([this] {
|
getApp()->accounts->Twitch.currentUserChanged.connect([this] {
|
||||||
auto currentUser = getApp()->accounts->Twitch.getCurrent();
|
auto currentUser = getApp()->accounts->Twitch.getCurrent();
|
||||||
assert(currentUser);
|
assert(currentUser);
|
||||||
this->refreshTwitchEmotes(currentUser);
|
this->refreshTwitchEmotes(currentUser);
|
||||||
|
|
17
src/util/sharedptrelementless.hpp
Normal file
17
src/util/sharedptrelementless.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct SharedPtrElementLess {
|
||||||
|
bool operator()(const std::shared_ptr<T> &a, const std::shared_ptr<T> &b) const
|
||||||
|
{
|
||||||
|
return a->operator<(*b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
} // namespace chatterino
|
|
@ -103,16 +103,18 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TVectorItem>
|
template <typename TVectorItem, typename Compare>
|
||||||
class SortedSignalVector : public BaseSignalVector<TVectorItem>
|
class SortedSignalVector : public BaseSignalVector<TVectorItem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = 0) override
|
virtual int insertItem(const TVectorItem &item, int proposedIndex = -1,
|
||||||
|
void *caller = 0) override
|
||||||
{
|
{
|
||||||
util::assertInGuiThread();
|
util::assertInGuiThread();
|
||||||
|
|
||||||
int index = this->vector.insert(
|
int index =
|
||||||
std::lower_bound(this->vector.begin(), this->vector.end(), item), item) -
|
this->vector.insert(
|
||||||
|
std::lower_bound(this->vector.begin(), this->vector.end(), item, Compare{}), item) -
|
||||||
this->vector.begin();
|
this->vector.begin();
|
||||||
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
||||||
this->itemInserted.invoke(args);
|
this->itemInserted.invoke(args);
|
||||||
|
|
|
@ -40,7 +40,7 @@ AccountPopupWidget::AccountPopupWidget(ChannelPtr _channel)
|
||||||
connect(this, &AccountPopupWidget::refreshButtons, this,
|
connect(this, &AccountPopupWidget::refreshButtons, this,
|
||||||
&AccountPopupWidget::actuallyRefreshButtons, Qt::QueuedConnection);
|
&AccountPopupWidget::actuallyRefreshButtons, Qt::QueuedConnection);
|
||||||
|
|
||||||
app->accounts->Twitch.userChanged.connect([=] {
|
app->accounts->Twitch.currentUserChanged.connect([=] {
|
||||||
auto currentTwitchUser = app->accounts->Twitch.getCurrent();
|
auto currentTwitchUser = app->accounts->Twitch.getCurrent();
|
||||||
if (!currentTwitchUser) {
|
if (!currentTwitchUser) {
|
||||||
// No twitch user set (should never happen)
|
// No twitch user set (should never happen)
|
||||||
|
|
|
@ -47,15 +47,13 @@ HighlightingPage::HighlightingPage()
|
||||||
helper::EditableModelView *view = *highlights.emplace<helper::EditableModelView>(
|
helper::EditableModelView *view = *highlights.emplace<helper::EditableModelView>(
|
||||||
app->highlights->createModel(nullptr));
|
app->highlights->createModel(nullptr));
|
||||||
|
|
||||||
view->getTableView()->hideColumn(3);
|
|
||||||
|
|
||||||
view->setTitles({"Pattern", "Flash taskbar", "Play sound", "Regex"});
|
view->setTitles({"Pattern", "Flash taskbar", "Play sound", "Regex"});
|
||||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||||
|
|
||||||
// fourtf: make class extrend BaseWidget and add this to dpiChanged
|
// fourtf: make class extrend BaseWidget and add this to dpiChanged
|
||||||
QTimer::singleShot(1, [view] {
|
QTimer::singleShot(1, [view] {
|
||||||
view->getTableView()->resizeColumnsToContents();
|
view->getTableView()->resizeColumnsToContents();
|
||||||
view->getTableView()->setColumnWidth(0, 250);
|
view->getTableView()->setColumnWidth(0, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
view->addButtonPressed.connect([] {
|
view->addButtonPressed.connect([] {
|
||||||
|
|
|
@ -47,7 +47,7 @@ Window::Window(WindowType _type)
|
||||||
app->windows->showAccountSelectPopup(QCursor::pos()); //
|
app->windows->showAccountSelectPopup(QCursor::pos()); //
|
||||||
});
|
});
|
||||||
|
|
||||||
app->accounts->Twitch.userChanged.connect(
|
app->accounts->Twitch.currentUserChanged.connect(
|
||||||
[=] { user->getLabel().setText(app->accounts->Twitch.getCurrent()->getUserName()); });
|
[=] { user->getLabel().setText(app->accounts->Twitch.getCurrent()->getUserName()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue