mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
added moderation buttons
This commit is contained in:
parent
252f648ff8
commit
6d6b99f3ef
15 changed files with 367 additions and 76 deletions
|
@ -127,7 +127,8 @@ SOURCES += \
|
||||||
src/widgets/settingspages/aboutpage.cpp \
|
src/widgets/settingspages/aboutpage.cpp \
|
||||||
src/widgets/settingspages/moderationpage.cpp \
|
src/widgets/settingspages/moderationpage.cpp \
|
||||||
src/widgets/settingspages/logspage.cpp \
|
src/widgets/settingspages/logspage.cpp \
|
||||||
src/widgets/basewindow.cpp
|
src/widgets/basewindow.cpp \
|
||||||
|
src/singletons/helper/moderationaction.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/precompiled_headers.hpp \
|
src/precompiled_headers.hpp \
|
||||||
|
@ -226,7 +227,8 @@ HEADERS += \
|
||||||
src/widgets/settingspages/aboutpage.hpp \
|
src/widgets/settingspages/aboutpage.hpp \
|
||||||
src/widgets/settingspages/moderationpage.hpp \
|
src/widgets/settingspages/moderationpage.hpp \
|
||||||
src/widgets/settingspages/logspage.hpp \
|
src/widgets/settingspages/logspage.hpp \
|
||||||
src/widgets/basewindow.hpp
|
src/widgets/basewindow.hpp \
|
||||||
|
src/singletons/helper/moderationaction.hpp
|
||||||
|
|
||||||
|
|
||||||
PRECOMPILED_HEADER =
|
PRECOMPILED_HEADER =
|
||||||
|
|
|
@ -41,11 +41,22 @@ MessageLayoutElement *MessageLayoutElement::setTrailingSpace(bool value)
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageLayoutElement *MessageLayoutElement::setLink(const Link &_link)
|
||||||
|
{
|
||||||
|
this->link = _link;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Link &MessageLayoutElement::getLink() const
|
||||||
|
{
|
||||||
|
return this->link;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// IMAGE
|
// IMAGE
|
||||||
//
|
//
|
||||||
|
|
||||||
ImageLayoutElement::ImageLayoutElement(MessageElement &_creator, Image &_image, QSize _size)
|
ImageLayoutElement::ImageLayoutElement(MessageElement &_creator, Image *_image, const QSize &_size)
|
||||||
: MessageLayoutElement(_creator, _size)
|
: MessageLayoutElement(_creator, _size)
|
||||||
, image(_image)
|
, image(_image)
|
||||||
{
|
{
|
||||||
|
@ -54,7 +65,7 @@ ImageLayoutElement::ImageLayoutElement(MessageElement &_creator, Image &_image,
|
||||||
|
|
||||||
void ImageLayoutElement::addCopyTextToString(QString &str, int from, int to) const
|
void ImageLayoutElement::addCopyTextToString(QString &str, int from, int to) const
|
||||||
{
|
{
|
||||||
str += this->image.getName();
|
str += this->image->getName();
|
||||||
|
|
||||||
if (this->hasTrailingSpace()) {
|
if (this->hasTrailingSpace()) {
|
||||||
str += " ";
|
str += " ";
|
||||||
|
@ -68,9 +79,9 @@ int ImageLayoutElement::getSelectionIndexCount()
|
||||||
|
|
||||||
void ImageLayoutElement::paint(QPainter &painter)
|
void ImageLayoutElement::paint(QPainter &painter)
|
||||||
{
|
{
|
||||||
const QPixmap *pixmap = this->image.getPixmap();
|
const QPixmap *pixmap = this->image->getPixmap();
|
||||||
|
|
||||||
if (pixmap != nullptr && !this->image.isAnimated()) {
|
if (pixmap != nullptr && !this->image->isAnimated()) {
|
||||||
// fourtf: make it use qreal values
|
// fourtf: make it use qreal values
|
||||||
painter.drawPixmap(QRectF(this->getRect()), *pixmap, QRectF());
|
painter.drawPixmap(QRectF(this->getRect()), *pixmap, QRectF());
|
||||||
}
|
}
|
||||||
|
@ -78,12 +89,12 @@ void ImageLayoutElement::paint(QPainter &painter)
|
||||||
|
|
||||||
void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset)
|
void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset)
|
||||||
{
|
{
|
||||||
if (this->image.isAnimated()) {
|
if (this->image->isAnimated()) {
|
||||||
if (this->image.getPixmap() != nullptr) {
|
if (this->image->getPixmap() != nullptr) {
|
||||||
// fourtf: make it use qreal values
|
// fourtf: make it use qreal values
|
||||||
QRect rect = this->getRect();
|
QRect rect = this->getRect();
|
||||||
rect.moveTop(rect.y() + yOffset);
|
rect.moveTop(rect.y() + yOffset);
|
||||||
painter.drawPixmap(QRectF(rect), *this->image.getPixmap(), QRectF());
|
painter.drawPixmap(QRectF(rect), *this->image->getPixmap(), QRectF());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +120,7 @@ int ImageLayoutElement::getXFromIndex(int index)
|
||||||
// TEXT
|
// TEXT
|
||||||
//
|
//
|
||||||
|
|
||||||
TextLayoutElement::TextLayoutElement(MessageElement &_creator, QString &_text, QSize _size,
|
TextLayoutElement::TextLayoutElement(MessageElement &_creator, QString &_text, const QSize &_size,
|
||||||
QColor _color, FontStyle _style, float _scale)
|
QColor _color, FontStyle _style, float _scale)
|
||||||
: MessageLayoutElement(_creator, _size)
|
: MessageLayoutElement(_creator, _size)
|
||||||
, text(_text)
|
, text(_text)
|
||||||
|
@ -188,6 +199,69 @@ int TextLayoutElement::getXFromIndex(int index)
|
||||||
return this->getRect().right();
|
return this->getRect().right();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TEXT ICON
|
||||||
|
TextIconLayoutElement::TextIconLayoutElement(MessageElement &creator, const QString &_line1,
|
||||||
|
const QString &_line2, float _scale, const QSize &size)
|
||||||
|
: MessageLayoutElement(creator, size)
|
||||||
|
, scale(_scale)
|
||||||
|
, line1(_line1)
|
||||||
|
, line2(_line2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextIconLayoutElement::addCopyTextToString(QString &str, int from, int to) const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextIconLayoutElement::getSelectionIndexCount()
|
||||||
|
{
|
||||||
|
return this->trailingSpace ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextIconLayoutElement::paint(QPainter &painter)
|
||||||
|
{
|
||||||
|
QFont font = singletons::FontManager::getInstance().getFont(FontStyle::Tiny, this->scale);
|
||||||
|
|
||||||
|
painter.setBrush(singletons::ThemeManager::getInstance().messages.textColors.regular);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
QTextOption option;
|
||||||
|
option.setAlignment(Qt::AlignHCenter);
|
||||||
|
|
||||||
|
if (this->line2.isEmpty()) {
|
||||||
|
QRect rect(this->getRect());
|
||||||
|
painter.drawText(rect, this->line1, option);
|
||||||
|
} else {
|
||||||
|
painter.drawText(
|
||||||
|
QPoint(this->getRect().x(), this->getRect().y() + this->getRect().height() / 2),
|
||||||
|
this->line1);
|
||||||
|
painter.drawText(
|
||||||
|
QPoint(this->getRect().x(), this->getRect().y() + this->getRect().height()),
|
||||||
|
this->line2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextIconLayoutElement::paintAnimated(QPainter &painter, int yOffset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextIconLayoutElement::getMouseOverIndex(const QPoint &abs)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextIconLayoutElement::getXFromIndex(int index)
|
||||||
|
{
|
||||||
|
if (index <= 0) {
|
||||||
|
return this->getRect().left();
|
||||||
|
} else if (index == 1) {
|
||||||
|
// fourtf: remove space width
|
||||||
|
return this->getRect().right();
|
||||||
|
} else {
|
||||||
|
return this->getRect().right();
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace layouts
|
} // namespace layouts
|
||||||
} // namespace messages
|
} // namespace messages
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
|
#include "messages/link.hpp"
|
||||||
#include "messages/messagecolor.hpp"
|
#include "messages/messagecolor.hpp"
|
||||||
#include "singletons/fontmanager.hpp"
|
#include "singletons/fontmanager.hpp"
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ public:
|
||||||
bool hasTrailingSpace() const;
|
bool hasTrailingSpace() const;
|
||||||
|
|
||||||
MessageLayoutElement *setTrailingSpace(bool value);
|
MessageLayoutElement *setTrailingSpace(bool value);
|
||||||
|
MessageLayoutElement *setLink(const Link &link);
|
||||||
|
|
||||||
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const = 0;
|
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const = 0;
|
||||||
virtual int getSelectionIndexCount() = 0;
|
virtual int getSelectionIndexCount() = 0;
|
||||||
|
@ -37,12 +39,14 @@ public:
|
||||||
virtual void paintAnimated(QPainter &painter, int yOffset) = 0;
|
virtual void paintAnimated(QPainter &painter, int yOffset) = 0;
|
||||||
virtual int getMouseOverIndex(const QPoint &abs) = 0;
|
virtual int getMouseOverIndex(const QPoint &abs) = 0;
|
||||||
virtual int getXFromIndex(int index) = 0;
|
virtual int getXFromIndex(int index) = 0;
|
||||||
|
const Link &getLink() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool trailingSpace = true;
|
bool trailingSpace = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRect rect;
|
QRect rect;
|
||||||
|
Link link;
|
||||||
// bool isInNewLine;
|
// bool isInNewLine;
|
||||||
MessageElement &creator;
|
MessageElement &creator;
|
||||||
};
|
};
|
||||||
|
@ -51,7 +55,7 @@ private:
|
||||||
class ImageLayoutElement : public MessageLayoutElement
|
class ImageLayoutElement : public MessageLayoutElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageLayoutElement(MessageElement &creator, Image &image, QSize size);
|
ImageLayoutElement(MessageElement &creator, Image *image, const QSize &size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const override;
|
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const override;
|
||||||
|
@ -62,14 +66,14 @@ protected:
|
||||||
virtual int getXFromIndex(int index) override;
|
virtual int getXFromIndex(int index) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Image ℑ
|
Image *image;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TEXT
|
// TEXT
|
||||||
class TextLayoutElement : public MessageLayoutElement
|
class TextLayoutElement : public MessageLayoutElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextLayoutElement(MessageElement &creator, QString &text, QSize size, QColor color,
|
TextLayoutElement(MessageElement &creator, QString &text, const QSize &size, QColor color,
|
||||||
FontStyle style, float scale);
|
FontStyle style, float scale);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -86,6 +90,28 @@ private:
|
||||||
FontStyle style;
|
FontStyle style;
|
||||||
float scale;
|
float scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TEXT ICON
|
||||||
|
// two lines of text (characters) in the size of a normal chat badge
|
||||||
|
class TextIconLayoutElement : public MessageLayoutElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextIconLayoutElement(MessageElement &creator, const QString &line1, const QString &line2,
|
||||||
|
float scale, const QSize &size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const override;
|
||||||
|
virtual int getSelectionIndexCount() override;
|
||||||
|
virtual void paint(QPainter &painter) override;
|
||||||
|
virtual void paintAnimated(QPainter &painter, int yOffset) override;
|
||||||
|
virtual int getMouseOverIndex(const QPoint &abs) override;
|
||||||
|
virtual int getXFromIndex(int index) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString line1;
|
||||||
|
QString line2;
|
||||||
|
float scale;
|
||||||
|
};
|
||||||
} // namespace layouts
|
} // namespace layouts
|
||||||
} // namespace messages
|
} // namespace messages
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
UserBan,
|
UserBan,
|
||||||
InsertText,
|
InsertText,
|
||||||
ShowMessage,
|
ShowMessage,
|
||||||
|
UserAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
Link();
|
Link();
|
||||||
|
|
|
@ -52,19 +52,20 @@ MessageElement::Flags MessageElement::getFlags() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMAGE
|
// IMAGE
|
||||||
ImageElement::ImageElement(Image &_image, MessageElement::Flags flags)
|
ImageElement::ImageElement(Image *_image, MessageElement::Flags flags)
|
||||||
: MessageElement(flags)
|
: MessageElement(flags)
|
||||||
, image(_image)
|
, image(_image)
|
||||||
{
|
{
|
||||||
this->setTooltip(_image.getTooltip());
|
this->setTooltip(_image->getTooltip());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags _flags)
|
void ImageElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags _flags)
|
||||||
{
|
{
|
||||||
QSize size(this->image.getWidth() * this->image.getScale() * container.scale,
|
QSize size(this->image->getWidth() * this->image->getScale() * container.scale,
|
||||||
this->image.getHeight() * this->image.getScale() * container.scale);
|
this->image->getHeight() * this->image->getScale() * container.scale);
|
||||||
|
|
||||||
container.addElement(new ImageLayoutElement(*this, this->image, size));
|
container.addElement(
|
||||||
|
(new ImageLayoutElement(*this, this->image, size))->setLink(this->getLink()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageElement::update(UpdateFlags _flags)
|
void ImageElement::update(UpdateFlags _flags)
|
||||||
|
@ -102,7 +103,7 @@ void EmoteElement::addToContainer(MessageLayoutContainer &container, MessageElem
|
||||||
QSize size((int)(container.scale * _image->getScaledWidth()),
|
QSize size((int)(container.scale * _image->getScaledWidth()),
|
||||||
(int)(container.scale * _image->getScaledHeight()));
|
(int)(container.scale * _image->getScaledHeight()));
|
||||||
|
|
||||||
container.addElement(new ImageLayoutElement(*this, *_image, size));
|
container.addElement((new ImageLayoutElement(*this, _image, size))->setLink(this->getLink()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmoteElement::update(UpdateFlags _flags)
|
void EmoteElement::update(UpdateFlags _flags)
|
||||||
|
@ -130,9 +131,10 @@ void TextElement::addToContainer(MessageLayoutContainer &container, MessageEleme
|
||||||
|
|
||||||
for (Word &word : this->words) {
|
for (Word &word : this->words) {
|
||||||
auto getTextLayoutElement = [&](QString text, int width, bool trailingSpace) {
|
auto getTextLayoutElement = [&](QString text, int width, bool trailingSpace) {
|
||||||
auto e = new TextLayoutElement(*this, text, QSize(width, metrics.height()),
|
auto e = (new TextLayoutElement(*this, text, QSize(width, metrics.height()),
|
||||||
this->color.getColor(themeManager), this->style,
|
this->color.getColor(themeManager), this->style,
|
||||||
container.scale);
|
container.scale))
|
||||||
|
->setLink(this->getLink());
|
||||||
e->setTrailingSpace(trailingSpace);
|
e->setTrailingSpace(trailingSpace);
|
||||||
return e;
|
return e;
|
||||||
};
|
};
|
||||||
|
@ -254,6 +256,19 @@ TwitchModerationElement::TwitchModerationElement()
|
||||||
void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
|
void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
|
||||||
MessageElement::Flags _flags)
|
MessageElement::Flags _flags)
|
||||||
{
|
{
|
||||||
|
QSize size((int)(container.scale * 16), (int)(container.scale * 16));
|
||||||
|
|
||||||
|
for (const singletons::ModerationAction &m :
|
||||||
|
singletons::SettingManager::getInstance().getModerationActions()) {
|
||||||
|
if (m.isImage()) {
|
||||||
|
container.addElement((new ImageLayoutElement(*this, m.getImage(), size))
|
||||||
|
->setLink(Link(Link::UserAction, m.getAction())));
|
||||||
|
} else {
|
||||||
|
container.addElement((new TextIconLayoutElement(*this, m.getLine1(), m.getLine2(),
|
||||||
|
container.scale, size))
|
||||||
|
->setLink(Link(Link::UserAction, m.getAction())));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TwitchModerationElement::update(UpdateFlags _flags)
|
void TwitchModerationElement::update(UpdateFlags _flags)
|
||||||
|
|
|
@ -137,10 +137,10 @@ private:
|
||||||
// contains a simple image
|
// contains a simple image
|
||||||
class ImageElement : public MessageElement
|
class ImageElement : public MessageElement
|
||||||
{
|
{
|
||||||
Image ℑ
|
Image *image;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ImageElement(Image &image, MessageElement::Flags flags);
|
ImageElement(Image *image, MessageElement::Flags flags);
|
||||||
|
|
||||||
virtual void addToContainer(MessageLayoutContainer &container,
|
virtual void addToContainer(MessageLayoutContainer &container,
|
||||||
MessageElement::Flags flags) override;
|
MessageElement::Flags flags) override;
|
||||||
|
|
|
@ -27,13 +27,13 @@ FontManager::FontManager()
|
||||||
this->currentFontFamily.connect([this](const std::string &newValue, auto) {
|
this->currentFontFamily.connect([this](const std::string &newValue, auto) {
|
||||||
this->incGeneration();
|
this->incGeneration();
|
||||||
// this->currentFont.setFamily(newValue.c_str());
|
// this->currentFont.setFamily(newValue.c_str());
|
||||||
this->currentFontByDpi.clear();
|
this->currentFontByScale.clear();
|
||||||
this->fontChanged.invoke();
|
this->fontChanged.invoke();
|
||||||
});
|
});
|
||||||
this->currentFontSize.connect([this](const int &newValue, auto) {
|
this->currentFontSize.connect([this](const int &newValue, auto) {
|
||||||
this->incGeneration();
|
this->incGeneration();
|
||||||
// this->currentFont.setSize(newValue);
|
// this->currentFont.setSize(newValue);
|
||||||
this->currentFontByDpi.clear();
|
this->currentFontByScale.clear();
|
||||||
this->fontChanged.invoke();
|
this->fontChanged.invoke();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -45,21 +45,23 @@ FontManager &FontManager::getInstance()
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFont &FontManager::getFont(Type type, float dpi)
|
QFont &FontManager::getFont(Type type, float scale)
|
||||||
{
|
{
|
||||||
// return this->currentFont.getFont(type);
|
// return this->currentFont.getFont(type);
|
||||||
return this->getCurrentFont(dpi).getFont(type);
|
return this->getCurrentFont(scale).getFont(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
QFontMetrics &FontManager::getFontMetrics(Type type, float dpi)
|
QFontMetrics &FontManager::getFontMetrics(Type type, float scale)
|
||||||
{
|
{
|
||||||
// return this->currentFont.getFontMetrics(type);
|
// return this->currentFont.getFontMetrics(type);
|
||||||
return this->getCurrentFont(dpi).getFontMetrics(type);
|
return this->getCurrentFont(scale).getFontMetrics(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontManager::FontData &FontManager::Font::getFontData(Type type)
|
FontManager::FontData &FontManager::Font::getFontData(Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case Tiny:
|
||||||
|
return this->tiny;
|
||||||
case Small:
|
case Small:
|
||||||
return this->small;
|
return this->small;
|
||||||
case MediumSmall:
|
case MediumSmall:
|
||||||
|
@ -90,18 +92,18 @@ QFontMetrics &FontManager::Font::getFontMetrics(Type type)
|
||||||
return this->getFontData(type).metrics;
|
return this->getFontData(type).metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
FontManager::Font &FontManager::getCurrentFont(float dpi)
|
FontManager::Font &FontManager::getCurrentFont(float scale)
|
||||||
{
|
{
|
||||||
for (auto it = this->currentFontByDpi.begin(); it != this->currentFontByDpi.end(); it++) {
|
for (auto it = this->currentFontByScale.begin(); it != this->currentFontByScale.end(); it++) {
|
||||||
if (it->first == dpi) {
|
if (it->first == scale) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->currentFontByDpi.push_back(std::make_pair(
|
this->currentFontByScale.push_back(
|
||||||
dpi,
|
std::make_pair(scale, Font(this->currentFontFamily.getValue().c_str(),
|
||||||
Font(this->currentFontFamily.getValue().c_str(), this->currentFontSize.getValue() * dpi)));
|
this->currentFontSize.getValue() * scale)));
|
||||||
|
|
||||||
return this->currentFontByDpi.back().second;
|
return this->currentFontByScale.back().second;
|
||||||
}
|
}
|
||||||
|
} // namespace singletons
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
|
#include <QFontDatabase>
|
||||||
#include <QFontMetrics>
|
#include <QFontMetrics>
|
||||||
#include <pajlada/settings/setting.hpp>
|
#include <pajlada/settings/setting.hpp>
|
||||||
#include <pajlada/signals/signal.hpp>
|
#include <pajlada/signals/signal.hpp>
|
||||||
|
@ -16,6 +17,7 @@ class FontManager
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Type : uint8_t {
|
enum Type : uint8_t {
|
||||||
|
Tiny,
|
||||||
Small,
|
Small,
|
||||||
MediumSmall,
|
MediumSmall,
|
||||||
Medium,
|
Medium,
|
||||||
|
@ -28,8 +30,8 @@ public:
|
||||||
// FontManager is initialized only once, on first use
|
// FontManager is initialized only once, on first use
|
||||||
static FontManager &getInstance();
|
static FontManager &getInstance();
|
||||||
|
|
||||||
QFont &getFont(Type type, float dpi);
|
QFont &getFont(Type type, float scale);
|
||||||
QFontMetrics &getFontMetrics(Type type, float dpi);
|
QFontMetrics &getFontMetrics(Type type, float scale);
|
||||||
|
|
||||||
int getGeneration() const
|
int getGeneration() const
|
||||||
{
|
{
|
||||||
|
@ -62,7 +64,8 @@ private:
|
||||||
Font() = delete;
|
Font() = delete;
|
||||||
|
|
||||||
explicit Font(const char *fontFamilyName, int mediumSize)
|
explicit Font(const char *fontFamilyName, int mediumSize)
|
||||||
: small(QFont(fontFamilyName, mediumSize - 4))
|
: tiny(QFont("Monospace", 8))
|
||||||
|
, small(QFont(fontFamilyName, mediumSize - 4))
|
||||||
, mediumSmall(QFont(fontFamilyName, mediumSize - 2))
|
, mediumSmall(QFont(fontFamilyName, mediumSize - 2))
|
||||||
, medium(QFont(fontFamilyName, mediumSize))
|
, medium(QFont(fontFamilyName, mediumSize))
|
||||||
, mediumBold(QFont(fontFamilyName, mediumSize, QFont::DemiBold))
|
, mediumBold(QFont(fontFamilyName, mediumSize, QFont::DemiBold))
|
||||||
|
@ -70,6 +73,7 @@ private:
|
||||||
, large(QFont(fontFamilyName, mediumSize))
|
, large(QFont(fontFamilyName, mediumSize))
|
||||||
, veryLarge(QFont(fontFamilyName, mediumSize))
|
, veryLarge(QFont(fontFamilyName, mediumSize))
|
||||||
{
|
{
|
||||||
|
tiny.font.setStyleHint(QFont::TypeWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFamily(const char *newFamily)
|
void setFamily(const char *newFamily)
|
||||||
|
@ -114,6 +118,7 @@ private:
|
||||||
QFont &getFont(Type type);
|
QFont &getFont(Type type);
|
||||||
QFontMetrics &getFontMetrics(Type type);
|
QFontMetrics &getFontMetrics(Type type);
|
||||||
|
|
||||||
|
FontData tiny;
|
||||||
FontData small;
|
FontData small;
|
||||||
FontData mediumSmall;
|
FontData mediumSmall;
|
||||||
FontData medium;
|
FontData medium;
|
||||||
|
@ -123,16 +128,16 @@ private:
|
||||||
FontData veryLarge;
|
FontData veryLarge;
|
||||||
};
|
};
|
||||||
|
|
||||||
Font &getCurrentFont(float dpi);
|
Font &getCurrentFont(float scale);
|
||||||
|
|
||||||
// Future plans:
|
// Future plans:
|
||||||
// Could have multiple fonts in here, such as "Menu font", "Application font", "Chat font"
|
// Could have multiple fonts in here, such as "Menu font", "Application font", "Chat font"
|
||||||
|
|
||||||
std::list<std::pair<float, Font>> currentFontByDpi;
|
std::list<std::pair<float, Font>> currentFontByScale;
|
||||||
|
|
||||||
int generation = 0;
|
int generation = 0;
|
||||||
};
|
};
|
||||||
}
|
} // namespace singletons
|
||||||
|
|
||||||
typedef singletons::FontManager::Type FontStyle;
|
typedef singletons::FontManager::Type FontStyle;
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
50
src/singletons/helper/moderationaction.cpp
Normal file
50
src/singletons/helper/moderationaction.cpp
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include "moderationaction.hpp"
|
||||||
|
|
||||||
|
#include "singletons/resourcemanager.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace singletons {
|
||||||
|
|
||||||
|
ModerationAction::ModerationAction(messages::Image *_image, const QString &_action)
|
||||||
|
: _isImage(true)
|
||||||
|
, image(_image)
|
||||||
|
, action(_action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ModerationAction::ModerationAction(const QString &_line1, const QString &_line2,
|
||||||
|
const QString &_action)
|
||||||
|
: _isImage(false)
|
||||||
|
, image(nullptr)
|
||||||
|
, line1(_line1)
|
||||||
|
, line2(_line2)
|
||||||
|
, action(_action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModerationAction::isImage() const
|
||||||
|
{
|
||||||
|
return this->_isImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages::Image *ModerationAction::getImage() const
|
||||||
|
{
|
||||||
|
return this->image;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &ModerationAction::getLine1() const
|
||||||
|
{
|
||||||
|
return this->line1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &ModerationAction::getLine2() const
|
||||||
|
{
|
||||||
|
return this->line2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &ModerationAction::getAction() const
|
||||||
|
{
|
||||||
|
return this->action;
|
||||||
|
}
|
||||||
|
} // namespace singletons
|
||||||
|
} // namespace chatterino
|
31
src/singletons/helper/moderationaction.hpp
Normal file
31
src/singletons/helper/moderationaction.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace messages {
|
||||||
|
class Image;
|
||||||
|
}
|
||||||
|
namespace singletons {
|
||||||
|
|
||||||
|
class ModerationAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModerationAction(messages::Image *image, const QString &action);
|
||||||
|
ModerationAction(const QString &line1, const QString &line2, const QString &action);
|
||||||
|
|
||||||
|
bool isImage() const;
|
||||||
|
messages::Image *getImage() const;
|
||||||
|
const QString &getLine1() const;
|
||||||
|
const QString &getLine2() const;
|
||||||
|
const QString &getAction() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _isImage;
|
||||||
|
messages::Image *image;
|
||||||
|
QString line1;
|
||||||
|
QString line2;
|
||||||
|
QString action;
|
||||||
|
};
|
||||||
|
} // namespace singletons
|
||||||
|
} // namespace chatterino
|
|
@ -1,6 +1,7 @@
|
||||||
#include "singletons/settingsmanager.hpp"
|
#include "singletons/settingsmanager.hpp"
|
||||||
#include "debug/log.hpp"
|
#include "debug/log.hpp"
|
||||||
#include "singletons/pathmanager.hpp"
|
#include "singletons/pathmanager.hpp"
|
||||||
|
#include "singletons/resourcemanager.hpp"
|
||||||
|
|
||||||
using namespace chatterino::messages;
|
using namespace chatterino::messages;
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ SettingManager::SettingManager()
|
||||||
this->wordMaskListener.cb = [this](auto) {
|
this->wordMaskListener.cb = [this](auto) {
|
||||||
this->updateWordTypeMask(); //
|
this->updateWordTypeMask(); //
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this->moderationActions.connect([this](auto, auto) { this->updateModerationActions(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageElement::Flags SettingManager::getWordTypeMask()
|
MessageElement::Flags SettingManager::getWordTypeMask()
|
||||||
|
@ -127,5 +130,77 @@ void SettingManager::recallSnapshot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ModerationAction> SettingManager::getModerationActions() const
|
||||||
|
{
|
||||||
|
return this->_moderationActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingManager::updateModerationActions()
|
||||||
|
{
|
||||||
|
auto &resources = singletons::ResourceManager::getInstance();
|
||||||
|
|
||||||
|
this->_moderationActions.clear();
|
||||||
|
|
||||||
|
static QRegularExpression newLineRegex("(\r\n?|\n)+");
|
||||||
|
static QRegularExpression replaceRegex("[!/.]");
|
||||||
|
static QRegularExpression timeoutRegex("^[./]timeout.* (\\d+)");
|
||||||
|
QStringList list = this->moderationActions.getValue().split(newLineRegex);
|
||||||
|
|
||||||
|
int multipleTimeouts = 0;
|
||||||
|
|
||||||
|
for (QString &str : list) {
|
||||||
|
if (timeoutRegex.match(str).hasMatch()) {
|
||||||
|
multipleTimeouts++;
|
||||||
|
if (multipleTimeouts > 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
QString &str = list[i];
|
||||||
|
|
||||||
|
if (str.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto timeoutMatch = timeoutRegex.match(str);
|
||||||
|
|
||||||
|
if (timeoutMatch.hasMatch()) {
|
||||||
|
if (multipleTimeouts > 1) {
|
||||||
|
QString line1;
|
||||||
|
QString line2;
|
||||||
|
|
||||||
|
int amount = timeoutMatch.captured(1).toInt();
|
||||||
|
|
||||||
|
if (amount < 60) {
|
||||||
|
line1 = QString::number(amount);
|
||||||
|
line2 = "s";
|
||||||
|
} else if (amount < 60 * 60) {
|
||||||
|
line1 = QString::number(amount / 60);
|
||||||
|
line2 = "m";
|
||||||
|
} else if (amount < 60 * 60 * 24) {
|
||||||
|
line1 = QString::number(amount / 60 / 60);
|
||||||
|
line2 = "h";
|
||||||
|
} else {
|
||||||
|
line1 = QString::number(amount / 60 / 60 / 24);
|
||||||
|
line2 = "d";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->_moderationActions.emplace_back(line1, line2, str);
|
||||||
|
} else {
|
||||||
|
this->_moderationActions.emplace_back(resources.buttonTimeout, str);
|
||||||
|
}
|
||||||
|
} else if (str.startsWith("/ban ")) {
|
||||||
|
this->_moderationActions.emplace_back(resources.buttonBan, str);
|
||||||
|
} else {
|
||||||
|
QString xD = str;
|
||||||
|
|
||||||
|
xD.replace(replaceRegex, "");
|
||||||
|
|
||||||
|
this->_moderationActions.emplace_back(xD.mid(0, 2), xD.mid(2, 2), str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace singletons
|
} // namespace singletons
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "messages/highlightphrase.hpp"
|
#include "messages/highlightphrase.hpp"
|
||||||
#include "messages/messageelement.hpp"
|
#include "messages/messageelement.hpp"
|
||||||
#include "singletons/helper/chatterinosetting.hpp"
|
#include "singletons/helper/chatterinosetting.hpp"
|
||||||
|
#include "singletons/helper/moderationaction.hpp"
|
||||||
|
|
||||||
#include <pajlada/settings/setting.hpp>
|
#include <pajlada/settings/setting.hpp>
|
||||||
#include <pajlada/settings/settinglistener.hpp>
|
#include <pajlada/settings/settinglistener.hpp>
|
||||||
|
@ -105,14 +106,19 @@ public:
|
||||||
void saveSnapshot();
|
void saveSnapshot();
|
||||||
void recallSnapshot();
|
void recallSnapshot();
|
||||||
|
|
||||||
|
std::vector<ModerationAction> getModerationActions() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void wordTypeMaskChanged();
|
void wordTypeMaskChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<ModerationAction> _moderationActions;
|
||||||
std::unique_ptr<rapidjson::Document> snapshot;
|
std::unique_ptr<rapidjson::Document> snapshot;
|
||||||
|
|
||||||
SettingManager();
|
SettingManager();
|
||||||
|
|
||||||
|
void updateModerationActions();
|
||||||
|
|
||||||
messages::MessageElement::Flags wordTypeMask = messages::MessageElement::Default;
|
messages::MessageElement::Flags wordTypeMask = messages::MessageElement::Default;
|
||||||
|
|
||||||
pajlada::Settings::SettingListener wordMaskListener;
|
pajlada::Settings::SettingListener wordMaskListener;
|
||||||
|
|
|
@ -511,7 +511,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
|
||||||
// Try to fetch channel-specific bit badge
|
// Try to fetch channel-specific bit badge
|
||||||
try {
|
try {
|
||||||
const auto &badge = channelResources.badgeSets.at("bits").versions.at(versionKey);
|
const auto &badge = channelResources.badgeSets.at("bits").versions.at(versionKey);
|
||||||
this->append<ImageElement>(*(badge.badgeImage1x), MessageElement::BadgeVanity);
|
this->append<ImageElement>(badge.badgeImage1x, MessageElement::BadgeVanity);
|
||||||
continue;
|
continue;
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
// Channel does not contain a special bit badge for this version
|
// Channel does not contain a special bit badge for this version
|
||||||
|
@ -520,44 +520,44 @@ void TwitchMessageBuilder::parseTwitchBadges()
|
||||||
// Use default bit badge
|
// Use default bit badge
|
||||||
try {
|
try {
|
||||||
const auto &badge = resourceManager.badgeSets.at("bits").versions.at(versionKey);
|
const auto &badge = resourceManager.badgeSets.at("bits").versions.at(versionKey);
|
||||||
this->append<ImageElement>(*(badge.badgeImage1x), MessageElement::BadgeVanity);
|
this->append<ImageElement>(badge.badgeImage1x, MessageElement::BadgeVanity);
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
debug::Log("No default bit badge for version {} found", versionKey);
|
debug::Log("No default bit badge for version {} found", versionKey);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (badge == "staff/1") {
|
} else if (badge == "staff/1") {
|
||||||
this->append<ImageElement>(*resourceManager.badgeStaff,
|
this->append<ImageElement>(resourceManager.badgeStaff,
|
||||||
MessageElement::BadgeGlobalAuthority)
|
MessageElement::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Staff");
|
->setTooltip("Twitch Staff");
|
||||||
} else if (badge == "admin/1") {
|
} else if (badge == "admin/1") {
|
||||||
this->append<ImageElement>(*resourceManager.badgeAdmin,
|
this->append<ImageElement>(resourceManager.badgeAdmin,
|
||||||
MessageElement::BadgeGlobalAuthority)
|
MessageElement::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Admin");
|
->setTooltip("Twitch Admin");
|
||||||
} else if (badge == "global_mod/1") {
|
} else if (badge == "global_mod/1") {
|
||||||
this->append<ImageElement>(*resourceManager.badgeGlobalModerator,
|
this->append<ImageElement>(resourceManager.badgeGlobalModerator,
|
||||||
MessageElement::BadgeGlobalAuthority)
|
MessageElement::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Global Moderator");
|
->setTooltip("Twitch Global Moderator");
|
||||||
} else if (badge == "moderator/1") {
|
} else if (badge == "moderator/1") {
|
||||||
// TODO: Implement custom FFZ moderator badge
|
// TODO: Implement custom FFZ moderator badge
|
||||||
this->append<ImageElement>(*resourceManager.badgeModerator,
|
this->append<ImageElement>(resourceManager.badgeModerator,
|
||||||
MessageElement::BadgeChannelAuthority)
|
MessageElement::BadgeChannelAuthority)
|
||||||
->setTooltip("Twitch Channel Moderator");
|
->setTooltip("Twitch Channel Moderator");
|
||||||
} else if (badge == "turbo/1") {
|
} else if (badge == "turbo/1") {
|
||||||
this->append<ImageElement>(*resourceManager.badgeTurbo,
|
this->append<ImageElement>(resourceManager.badgeTurbo,
|
||||||
MessageElement::BadgeGlobalAuthority)
|
MessageElement::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Turbo Subscriber");
|
->setTooltip("Twitch Turbo Subscriber");
|
||||||
} else if (badge == "broadcaster/1") {
|
} else if (badge == "broadcaster/1") {
|
||||||
this->append<ImageElement>(*resourceManager.badgeBroadcaster,
|
this->append<ImageElement>(resourceManager.badgeBroadcaster,
|
||||||
MessageElement::BadgeChannelAuthority)
|
MessageElement::BadgeChannelAuthority)
|
||||||
->setTooltip("Twitch Broadcaster");
|
->setTooltip("Twitch Broadcaster");
|
||||||
} else if (badge == "premium/1") {
|
} else if (badge == "premium/1") {
|
||||||
this->append<ImageElement>(*resourceManager.badgePremium, MessageElement::BadgeVanity)
|
this->append<ImageElement>(resourceManager.badgePremium, MessageElement::BadgeVanity)
|
||||||
->setTooltip("Twitch Prime Subscriber");
|
->setTooltip("Twitch Prime Subscriber");
|
||||||
} else if (badge.startsWith("partner/")) {
|
} else if (badge.startsWith("partner/")) {
|
||||||
int index = badge.midRef(8).toInt();
|
int index = badge.midRef(8).toInt();
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 1: {
|
case 1: {
|
||||||
this->append<ImageElement>(*resourceManager.badgeVerified,
|
this->append<ImageElement>(resourceManager.badgeVerified,
|
||||||
MessageElement::BadgeVanity)
|
MessageElement::BadgeVanity)
|
||||||
->setTooltip("Twitch Verified");
|
->setTooltip("Twitch Verified");
|
||||||
} break;
|
} break;
|
||||||
|
@ -574,7 +574,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
|
||||||
auto badgeSetIt = channelResources.badgeSets.find("subscriber");
|
auto badgeSetIt = channelResources.badgeSets.find("subscriber");
|
||||||
if (badgeSetIt == channelResources.badgeSets.end()) {
|
if (badgeSetIt == channelResources.badgeSets.end()) {
|
||||||
// Fall back to default badge
|
// Fall back to default badge
|
||||||
this->append<ImageElement>(*resourceManager.badgeSubscriber,
|
this->append<ImageElement>(resourceManager.badgeSubscriber,
|
||||||
MessageElement::BadgeSubscription)
|
MessageElement::BadgeSubscription)
|
||||||
->setTooltip("Twitch Subscriber");
|
->setTooltip("Twitch Subscriber");
|
||||||
continue;
|
continue;
|
||||||
|
@ -588,7 +588,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
|
||||||
|
|
||||||
if (badgeVersionIt == badgeSet.versions.end()) {
|
if (badgeVersionIt == badgeSet.versions.end()) {
|
||||||
// Fall back to default badge
|
// Fall back to default badge
|
||||||
this->append<ImageElement>(*resourceManager.badgeSubscriber,
|
this->append<ImageElement>(resourceManager.badgeSubscriber,
|
||||||
MessageElement::BadgeSubscription)
|
MessageElement::BadgeSubscription)
|
||||||
->setTooltip("Twitch Subscriber");
|
->setTooltip("Twitch Subscriber");
|
||||||
continue;
|
continue;
|
||||||
|
@ -596,8 +596,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
|
||||||
|
|
||||||
auto &badgeVersion = badgeVersionIt->second;
|
auto &badgeVersion = badgeVersionIt->second;
|
||||||
|
|
||||||
this->append<ImageElement>(*badgeVersion.badgeImage1x,
|
this->append<ImageElement>(badgeVersion.badgeImage1x, MessageElement::BadgeSubscription)
|
||||||
MessageElement::BadgeSubscription)
|
|
||||||
->setTooltip("Twitch " + QString::fromStdString(badgeVersion.title));
|
->setTooltip("Twitch " + QString::fromStdString(badgeVersion.title));
|
||||||
} else {
|
} else {
|
||||||
if (!resourceManager.dynamicBadgesLoaded) {
|
if (!resourceManager.dynamicBadgesLoaded) {
|
||||||
|
@ -623,7 +622,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
|
||||||
try {
|
try {
|
||||||
auto &badgeVersion = badgeSet.versions.at(versionKey);
|
auto &badgeVersion = badgeSet.versions.at(versionKey);
|
||||||
|
|
||||||
this->append<ImageElement>(*badgeVersion.badgeImage1x, badgeType)
|
this->append<ImageElement>(badgeVersion.badgeImage1x, badgeType)
|
||||||
->setTooltip("Twitch " + QString::fromStdString(badgeVersion.title));
|
->setTooltip("Twitch " + QString::fromStdString(badgeVersion.title));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
qDebug() << "Exception caught:" << e.what()
|
qDebug() << "Exception caught:" << e.what()
|
||||||
|
@ -648,7 +647,7 @@ void TwitchMessageBuilder::addChatterinoBadges()
|
||||||
|
|
||||||
const auto badge = it->second;
|
const auto badge = it->second;
|
||||||
|
|
||||||
this->append<ImageElement>(*badge->image, MessageElement::BadgeChatterino)
|
this->append<ImageElement>(badge->image, MessageElement::BadgeChatterino)
|
||||||
->setTooltip(QString::fromStdString(badge->tooltip));
|
->setTooltip(QString::fromStdString(badge->tooltip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -641,7 +641,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if word has a link
|
// check if word has a link
|
||||||
if (hoverLayoutElement->getCreator().getLink().isValid()) {
|
if (hoverLayoutElement->getLink().isValid()) {
|
||||||
this->setCursor(Qt::PointingHandCursor);
|
this->setCursor(Qt::PointingHandCursor);
|
||||||
} else {
|
} else {
|
||||||
this->setCursor(Qt::ArrowCursor);
|
this->setCursor(Qt::ArrowCursor);
|
||||||
|
@ -764,7 +764,7 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &link = hoverLayoutElement->getCreator().getLink();
|
auto &link = hoverLayoutElement->getLink();
|
||||||
|
|
||||||
switch (link.getType()) {
|
switch (link.getType()) {
|
||||||
case messages::Link::UserInfo: {
|
case messages::Link::UserInfo: {
|
||||||
|
@ -782,6 +782,11 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
QDesktopServices::openUrl(QUrl(link.getValue()));
|
QDesktopServices::openUrl(QUrl(link.getValue()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case messages::Link::UserAction: {
|
||||||
|
QString value = link.getValue();
|
||||||
|
value.replace("{user}", layout->getMessage()->loginName);
|
||||||
|
this->channel->sendMessage(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,21 +21,21 @@ ModerationPage::ModerationPage()
|
||||||
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
auto label = layout.emplace<QLabel>("In channels that you moderate there is a button <insert image of button here> to enable moderation mode.");
|
auto label = layout.emplace<QLabel>("In channels that you moderate there is a button <insert image of button here> to enable moderation mode.\n\nOne action per line. {user} will be replaced with the username.\nExample `/timeout {user} 120`");
|
||||||
label->setWordWrap(true);
|
label->setWordWrap(true);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
auto text = layout.emplace<QTextEdit>().getElement();
|
auto text = layout.emplace<QTextEdit>().getElement();
|
||||||
|
|
||||||
|
settings.moderationActions.connect([=](const QString &str, auto) {
|
||||||
|
text->setPlainText(str); //
|
||||||
|
});
|
||||||
|
|
||||||
QObject::connect(text, &QTextEdit::textChanged, this,
|
QObject::connect(text, &QTextEdit::textChanged, this,
|
||||||
[this] { this->itemsChangedTimer.start(200); });
|
[this] { this->itemsChangedTimer.start(200); });
|
||||||
|
|
||||||
QObject::connect(&this->itemsChangedTimer, &QTimer::timeout, this,
|
QObject::connect(&this->itemsChangedTimer, &QTimer::timeout, this,
|
||||||
[text, &settings]() { settings.moderationActions = text->toPlainText(); });
|
[text, &settings]() { settings.moderationActions = text->toPlainText(); });
|
||||||
|
|
||||||
settings.highlightUserBlacklist.connect([=](const QString &str, auto) {
|
|
||||||
text->setPlainText(str); //
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- misc
|
// ---- misc
|
||||||
|
|
Loading…
Reference in a new issue