Merge branch 'Ch2Usercard'

This commit is contained in:
fourtf 2020-09-26 14:54:44 +02:00
commit db3402a18e
7 changed files with 334 additions and 81 deletions

View file

@ -2,6 +2,7 @@
## Unversioned
- Minor: Added customizable timeout buttons to the user info popup
- Minor: Deprecate loading of "v1" window layouts. If you haven't updated Chatterino in more than 2 years, there's a chance you will lose your window layout.
- Minor: Disable checking for updates on unsupported platforms (#1874)
- Bugfix: Fix bug preventing users from setting the highlight color of the second entry in the "User" highlights tab (#1898)

View file

@ -11,6 +11,8 @@
#include "singletons/Toasts.hpp"
#include "widgets/Notebook.hpp"
using TimeoutButton = std::pair<QString, int>;
namespace chatterino {
class HighlightPhrase;
@ -339,6 +341,13 @@ public:
IntSetting hideSimilarMaxMessagesToCheck = {
"/similarity/hideSimilarMaxMessagesToCheck", 3};
/// Timeout buttons
ChatterinoSetting<std::vector<TimeoutButton>> timeoutButtons = {
"/timeouts/timeoutButtons",
{ { "s", 1 }, { "s", 30 }, { "m", 1 }, { "m", 5 },
{ "m", 30 }, { "h", 1 }, { "d", 1 }, { "w", 1 } } };
private:
void updateModerationActions();
};

View file

@ -85,6 +85,17 @@ namespace {
return channelPtr;
};
const auto borderColor = QColor(255, 255, 255, 80);
int calculateTimeoutDuration(TimeoutButton timeout)
{
static const QMap<QString, int> durations{
{"s", 1}, {"m", 60}, {"h", 3600}, {"d", 86400}, {"w", 604800},
};
return timeout.second * durations[timeout.first];
}
} // namespace
UserInfoPopup::UserInfoPopup(bool closeAutomatically)
@ -628,99 +639,126 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
QColor color1(255, 255, 255, 80);
QColor color2(255, 255, 255, 0);
int buttonWidth = 24;
int buttonWidth = 40;
// int buttonWidth = 24;
int buttonWidth2 = 32;
int buttonHeight = 32;
layout->setSpacing(16);
auto addButton = [&](Action action, const QString &text,
const QPixmap &pixmap) {
//auto addButton = [&](Action action, const QString &text,
// const QPixmap &pixmap) {
// auto vbox = layout.emplace<QVBoxLayout>().withoutMargin();
// {
// auto title = vbox.emplace<QHBoxLayout>().withoutMargin();
// title->addStretch(1);
// auto label = title.emplace<Label>(text);
// label->setHasOffset(false);
// label->setStyleSheet("color: #BBB");
// title->addStretch(1);
// auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
// hbox->setSpacing(0);
// {
// auto button = hbox.emplace<Button>(nullptr);
// button->setPixmap(pixmap);
// button->setScaleIndependantSize(buttonHeight, buttonHeight);
// button->setBorderColor(QColor(255, 255, 255, 127));
// QObject::connect(
// button.getElement(), &Button::leftClicked, [this, action] {
// this->buttonClicked.invoke(std::make_pair(action, -1));
// });
// }
// }
//};
const auto addLayout = [&](const QString &text) {
auto vbox = layout.emplace<QVBoxLayout>().withoutMargin();
auto title = vbox.emplace<QHBoxLayout>().withoutMargin();
title->addStretch(1);
auto label = title.emplace<Label>(text);
label->setStyleSheet("color: #BBB");
label->setHasOffset(false);
title->addStretch(1);
auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
hbox->setSpacing(0);
return hbox;
};
const auto addButton = [&](Action action, const QString &title,
const QPixmap &pixmap) {
auto button = addLayout(title).emplace<Button>(nullptr);
button->setPixmap(pixmap);
button->setScaleIndependantSize(buttonHeight, buttonHeight);
button->setBorderColor(QColor(255, 255, 255, 127));
QObject::connect(
button.getElement(), &Button::leftClicked, [this, action] {
this->buttonClicked.invoke(std::make_pair(action, -1));
});
};
auto addTimeouts = [&](const QString &title) {
auto hbox = addLayout(title);
for (const auto &item : getSettings()->timeoutButtons.getValue())
{
auto title = vbox.emplace<QHBoxLayout>().withoutMargin();
title->addStretch(1);
auto label = title.emplace<Label>(text);
label->setHasOffset(false);
label->setStyleSheet("color: #BBB");
title->addStretch(1);
auto a = hbox.emplace<EffectLabel2>();
a->getLabel().setText(QString::number(item.second) + item.first);
auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
hbox->setSpacing(0);
{
auto button = hbox.emplace<Button>(nullptr);
button->setPixmap(pixmap);
button->setScaleIndependantSize(buttonHeight, buttonHeight);
button->setBorderColor(QColor(255, 255, 255, 127));
a->setScaleIndependantSize(buttonWidth, buttonHeight);
a->setBorderColor(borderColor);
QObject::connect(
button.getElement(), &Button::leftClicked, [this, action] {
this->buttonClicked.invoke(std::make_pair(action, -1));
});
}
const auto pair =
std::make_pair(Action::Timeout, calculateTimeoutDuration(item));
QObject::connect(
a.getElement(), &EffectLabel2::leftClicked,
[this, pair] { this->buttonClicked.invoke(pair); });
//auto addTimeouts = [&](const QString &title_,
// const std::vector<std::pair<QString, int>> &items) {
// auto vbox = layout.emplace<QVBoxLayout>().withoutMargin();
// {
// auto title = vbox.emplace<QHBoxLayout>().withoutMargin();
// title->addStretch(1);
// auto label = title.emplace<Label>(title_);
// label->setStyleSheet("color: #BBB");
// label->setHasOffset(false);
// title->addStretch(1);
// auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
// hbox->setSpacing(0);
// for (const auto &item : items)
// {
// auto a = hbox.emplace<EffectLabel2>();
// a->getLabel().setText(std::get<0>(item));
// if (std::get<0>(item).length() > 1)
// {
// a->setScaleIndependantSize(buttonWidth2, buttonHeight);
// }
// else
// {
// a->setScaleIndependantSize(buttonWidth, buttonHeight);
// }
// a->setBorderColor(color1);
// QObject::connect(a.getElement(), &EffectLabel2::leftClicked,
// [this, timeout = std::get<1>(item)] {
// this->buttonClicked.invoke(std::make_pair(
// Action::Timeout, timeout));
// });
// }
}
};
auto addTimeouts = [&](const QString &title_,
const std::vector<std::pair<QString, int>> &items) {
auto vbox = layout.emplace<QVBoxLayout>().withoutMargin();
{
auto title = vbox.emplace<QHBoxLayout>().withoutMargin();
title->addStretch(1);
auto label = title.emplace<Label>(title_);
label->setStyleSheet("color: #BBB");
label->setHasOffset(false);
title->addStretch(1);
auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
hbox->setSpacing(0);
for (const auto &item : items)
{
auto a = hbox.emplace<EffectLabel2>();
a->getLabel().setText(std::get<0>(item));
if (std::get<0>(item).length() > 1)
{
a->setScaleIndependantSize(buttonWidth2, buttonHeight);
}
else
{
a->setScaleIndependantSize(buttonWidth, buttonHeight);
}
a->setBorderColor(color1);
QObject::connect(a.getElement(), &EffectLabel2::leftClicked,
[this, timeout = std::get<1>(item)] {
this->buttonClicked.invoke(std::make_pair(
Action::Timeout, timeout));
});
}
}
};
addButton(Unban, "unban", getResources().buttons.unban);
addTimeouts("sec", {{"1", 1}});
addTimeouts("min", {
{"1", 1 * 60},
{"5", 5 * 60},
{"10", 10 * 60},
});
addTimeouts("hour", {
{"1", 1 * 60 * 60},
{"4", 4 * 60 * 60},
});
addTimeouts("days", {
{"1", 1 * 60 * 60 * 24},
{"3", 3 * 60 * 60 * 24},
});
addTimeouts("weeks", {
{"1", 1 * 60 * 60 * 24 * 7},
{"2", 2 * 60 * 60 * 24 * 7},
});
addButton(Ban, "ban", getResources().buttons.ban);
addButton(Unban, "Unban", getResources().buttons.unban);
addTimeouts("Timeouts");
addButton(Ban, "Ban", getResources().buttons.ban);
}
void UserInfoPopup::TimeoutWidget::paintEvent(QPaintEvent *)

View file

@ -0,0 +1,89 @@
// Timeoutbuttons
{
auto timeoutLayout = tabs.appendTab(new QVBoxLayout, "Timeouts");
auto texts = timeoutLayout.emplace<QVBoxLayout>().withoutMargin();
{
auto infoLabel = texts.emplace<QLabel>();
infoLabel->setText(
"Customize your timeout buttons in seconds (s), "
"minutes (m), hours (h), days (d) or weeks (w).");
infoLabel->setAlignment(Qt::AlignCenter);
auto maxLabel = texts.emplace<QLabel>();
maxLabel->setText("(maximum timeout duration = 2 w)");
maxLabel->setAlignment(Qt::AlignCenter);
}
texts->setContentsMargins(0, 0, 0, 15);
texts->setSizeConstraint(QLayout::SetMaximumSize);
const auto valueChanged = [=] {
const auto index = QObject::sender()->objectName().toInt();
const auto line = this->durationInputs_[index];
const auto duration = line->text().toInt();
const auto unit = this->unitInputs_[index]->currentText();
// safety mechanism for setting days and weeks
if (unit == "d" && duration > 14)
{
line->setText("14");
return;
}
else if (unit == "w" && duration > 2)
{
line->setText("2");
return;
}
auto timeouts = getSettings()->timeoutButtons.getValue();
timeouts[index] = TimeoutButton{ unit, duration };
getSettings()->timeoutButtons.setValue(timeouts);
};
// build one line for each customizable button
auto i = 0;
for (const auto tButton : getSettings()->timeoutButtons.getValue())
{
const auto buttonNumber = QString::number(i);
auto timeout = timeoutLayout.emplace<QHBoxLayout>().withoutMargin();
auto buttonLabel = timeout.emplace<QLabel>();
buttonLabel->setText(QString("Button %1: ").arg(++i));
auto *lineEditDurationInput = new QLineEdit();
lineEditDurationInput->setObjectName(buttonNumber);
lineEditDurationInput->setValidator(
new QIntValidator(1, 99, this));
lineEditDurationInput->setText(
QString::number(tButton.second));
lineEditDurationInput->setAlignment(Qt::AlignRight);
lineEditDurationInput->setMaximumWidth(30);
timeout.append(lineEditDurationInput);
auto *timeoutDurationUnit = new QComboBox();
timeoutDurationUnit->setObjectName(buttonNumber);
timeoutDurationUnit->addItems({ "s", "m", "h", "d", "w" });
timeoutDurationUnit->setCurrentText(tButton.first);
timeout.append(timeoutDurationUnit);
QObject::connect(lineEditDurationInput,
&QLineEdit::textChanged, this,
valueChanged);
QObject::connect(timeoutDurationUnit,
&QComboBox::currentTextChanged, this,
valueChanged);
timeout->addStretch();
this->durationInputs_.push_back(lineEditDurationInput);
this->unitInputs_.push_back(timeoutDurationUnit);
timeout->setContentsMargins(40, 0, 0, 0);
timeout->setSizeConstraint(QLayout::SetMaximumSize);
}
timeoutLayout->addStretch();
}
// Timeoutbuttons end
}

View file

@ -0,0 +1,19 @@
#pragma once
#include "widgets/settingspages/SettingsPage.hpp"
namespace chatterino {
class AdvancedPage : public SettingsPage
{
public:
AdvancedPage();
private:
// list needed for dynamic timeout settings
std::vector<QLineEdit *> durationInputs_;
std::vector<QComboBox *> unitInputs_;
};
} // namespace chatterino

View file

@ -202,10 +202,99 @@ ModerationPage::ModerationPage()
}*/
}
this->addModerationButtonSettings(tabs);
// ---- misc
this->itemsChangedTimer_.setSingleShot(true);
}
void ModerationPage::addModerationButtonSettings(
LayoutCreator<QTabWidget> &tabs)
{
auto timeoutLayout =
tabs.appendTab(new QVBoxLayout, "User Timeout Buttons");
auto texts = timeoutLayout.emplace<QVBoxLayout>().withoutMargin();
{
auto infoLabel = texts.emplace<QLabel>();
infoLabel->setText(
"Customize the timeout buttons in the user popup (accessible "
"through clicking a username).\nUse seconds (s), "
"minutes (m), hours (h), days (d) or weeks (w).");
infoLabel->setAlignment(Qt::AlignCenter);
auto maxLabel = texts.emplace<QLabel>();
maxLabel->setText("(maximum timeout duration = 2 w)");
maxLabel->setAlignment(Qt::AlignCenter);
}
texts->setContentsMargins(0, 0, 0, 15);
texts->setSizeConstraint(QLayout::SetMaximumSize);
const auto valueChanged = [=] {
const auto index = QObject::sender()->objectName().toInt();
const auto line = this->durationInputs_[index];
const auto duration = line->text().toInt();
const auto unit = this->unitInputs_[index]->currentText();
// safety mechanism for setting days and weeks
if (unit == "d" && duration > 14)
{
line->setText("14");
return;
}
else if (unit == "w" && duration > 2)
{
line->setText("2");
return;
}
auto timeouts = getSettings()->timeoutButtons.getValue();
timeouts[index] = TimeoutButton{unit, duration};
getSettings()->timeoutButtons.setValue(timeouts);
};
// build one line for each customizable button
auto i = 0;
for (const auto tButton : getSettings()->timeoutButtons.getValue())
{
const auto buttonNumber = QString::number(i);
auto timeout = timeoutLayout.emplace<QHBoxLayout>().withoutMargin();
auto buttonLabel = timeout.emplace<QLabel>();
buttonLabel->setText(QString("Button %1: ").arg(++i));
auto *lineEditDurationInput = new QLineEdit();
lineEditDurationInput->setObjectName(buttonNumber);
lineEditDurationInput->setValidator(new QIntValidator(1, 99, this));
lineEditDurationInput->setText(QString::number(tButton.second));
lineEditDurationInput->setAlignment(Qt::AlignRight);
lineEditDurationInput->setMaximumWidth(30);
timeout.append(lineEditDurationInput);
auto *timeoutDurationUnit = new QComboBox();
timeoutDurationUnit->setObjectName(buttonNumber);
timeoutDurationUnit->addItems({"s", "m", "h", "d", "w"});
timeoutDurationUnit->setCurrentText(tButton.first);
timeout.append(timeoutDurationUnit);
QObject::connect(lineEditDurationInput, &QLineEdit::textChanged, this,
valueChanged);
QObject::connect(timeoutDurationUnit, &QComboBox::currentTextChanged,
this, valueChanged);
timeout->addStretch();
this->durationInputs_.push_back(lineEditDurationInput);
this->unitInputs_.push_back(timeoutDurationUnit);
timeout->setContentsMargins(40, 0, 0, 0);
timeout->setSizeConstraint(QLayout::SetMaximumSize);
}
timeoutLayout->addStretch();
}
void ModerationPage::selectModerationActions()
{
this->tabWidget_->setCurrentIndex(1);

View file

@ -9,6 +9,9 @@ class QPushButton;
namespace chatterino {
template <typename X>
class LayoutCreator;
class ModerationPage : public SettingsPage
{
public:
@ -17,8 +20,13 @@ public:
void selectModerationActions();
private:
void addModerationButtonSettings(LayoutCreator<QTabWidget> &);
QTimer itemsChangedTimer_;
QTabWidget *tabWidget_{};
std::vector<QLineEdit *> durationInputs_;
std::vector<QComboBox *> unitInputs_;
};
} // namespace chatterino