created directory for dialogs
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#include "EmotePopup.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "messages/MessageBuilder.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QShortcut>
|
||||
#include <QTabWidget>
|
||||
|
||||
using namespace chatterino::providers::twitch;
|
||||
using namespace chatterino::messages;
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
EmotePopup::EmotePopup()
|
||||
: BaseWindow(nullptr, BaseWindow::EnableCustomFrame)
|
||||
{
|
||||
this->viewEmotes = new ChannelView();
|
||||
this->viewEmojis = new ChannelView();
|
||||
|
||||
this->viewEmotes->setOverrideFlags(MessageElement::Flags(
|
||||
MessageElement::Default | MessageElement::AlwaysShow | MessageElement::EmoteImages));
|
||||
this->viewEmojis->setOverrideFlags(MessageElement::Flags(
|
||||
MessageElement::Default | MessageElement::AlwaysShow | MessageElement::EmoteImages));
|
||||
|
||||
this->viewEmotes->setEnableScrollingToBottom(false);
|
||||
this->viewEmojis->setEnableScrollingToBottom(false);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
|
||||
Notebook *notebook = new Notebook(this);
|
||||
layout->addWidget(notebook);
|
||||
layout->setMargin(0);
|
||||
|
||||
notebook->addPage(this->viewEmotes, "Emotes");
|
||||
notebook->addPage(this->viewEmojis, "Emojis");
|
||||
|
||||
this->loadEmojis();
|
||||
|
||||
this->viewEmotes->linkClicked.connect(
|
||||
[this](const Link &link) { this->linkClicked.invoke(link); });
|
||||
this->viewEmojis->linkClicked.connect(
|
||||
[this](const Link &link) { this->linkClicked.invoke(link); });
|
||||
}
|
||||
|
||||
void EmotePopup::loadChannel(ChannelPtr _channel)
|
||||
{
|
||||
this->setWindowTitle("Emotes from " + _channel->name);
|
||||
|
||||
TwitchChannel *channel = dynamic_cast<TwitchChannel *>(_channel.get());
|
||||
|
||||
if (channel == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelPtr emoteChannel(new Channel("", Channel::None));
|
||||
|
||||
auto addEmotes = [&](util::EmoteMap &map, const QString &title, const QString &emoteDesc) {
|
||||
// TITLE
|
||||
messages::MessageBuilder builder1;
|
||||
|
||||
builder1.append(new TextElement(title, MessageElement::Text));
|
||||
|
||||
builder1.getMessage()->flags |= Message::Centered;
|
||||
emoteChannel->addMessage(builder1.getMessage());
|
||||
|
||||
// EMOTES
|
||||
messages::MessageBuilder builder2;
|
||||
builder2.getMessage()->flags |= Message::Centered;
|
||||
builder2.getMessage()->flags |= Message::DisableCompactEmotes;
|
||||
|
||||
map.each([&](const QString &key, const util::EmoteData &value) {
|
||||
builder2.append((new EmoteElement(value, MessageElement::Flags::AlwaysShow))
|
||||
->setLink(Link(Link::InsertText, key)));
|
||||
});
|
||||
|
||||
emoteChannel->addMessage(builder2.getMessage());
|
||||
};
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
QString userID = app->accounts->twitch.getCurrent()->getUserId();
|
||||
|
||||
// fourtf: the entire emote manager needs to be refactored so there's no point in trying to
|
||||
// fix this pile of garbage
|
||||
for (const auto &set : app->emotes->twitch.emotes[userID].emoteSets) {
|
||||
// TITLE
|
||||
messages::MessageBuilder builder1;
|
||||
|
||||
QString setText;
|
||||
if (set->text.isEmpty()) {
|
||||
if (set->channelName.isEmpty()) {
|
||||
setText = "Twitch Account Emotes";
|
||||
} else {
|
||||
setText = "Twitch Account Emotes (" + set->channelName + ")";
|
||||
}
|
||||
} else {
|
||||
setText = set->text;
|
||||
}
|
||||
|
||||
builder1.append(new TextElement(setText, MessageElement::Text));
|
||||
|
||||
builder1.getMessage()->flags |= Message::Centered;
|
||||
emoteChannel->addMessage(builder1.getMessage());
|
||||
|
||||
// EMOTES
|
||||
messages::MessageBuilder builder2;
|
||||
builder2.getMessage()->flags |= Message::Centered;
|
||||
builder2.getMessage()->flags |= Message::DisableCompactEmotes;
|
||||
|
||||
for (const auto &emote : set->emotes) {
|
||||
[&](const QString &key, const util::EmoteData &value) {
|
||||
builder2.append((new EmoteElement(value, MessageElement::Flags::AlwaysShow))
|
||||
->setLink(Link(Link::InsertText, key)));
|
||||
}(emote.code, app->emotes->twitch.getEmoteById(emote.id, emote.code));
|
||||
}
|
||||
|
||||
emoteChannel->addMessage(builder2.getMessage());
|
||||
}
|
||||
|
||||
addEmotes(app->emotes->bttv.globalEmotes, "BetterTTV Global Emotes", "BetterTTV Global Emote");
|
||||
addEmotes(*channel->bttvChannelEmotes.get(), "BetterTTV Channel Emotes",
|
||||
"BetterTTV Channel Emote");
|
||||
addEmotes(app->emotes->ffz.globalEmotes, "FrankerFaceZ Global Emotes",
|
||||
"FrankerFaceZ Global Emote");
|
||||
addEmotes(*channel->ffzChannelEmotes.get(), "FrankerFaceZ Channel Emotes",
|
||||
"FrankerFaceZ Channel Emote");
|
||||
|
||||
this->viewEmotes->setChannel(emoteChannel);
|
||||
}
|
||||
|
||||
void EmotePopup::loadEmojis()
|
||||
{
|
||||
auto &emojis = getApp()->emotes->emojis.emojis;
|
||||
|
||||
ChannelPtr emojiChannel(new Channel("", Channel::None));
|
||||
|
||||
// title
|
||||
messages::MessageBuilder builder1;
|
||||
|
||||
builder1.append(new TextElement("emojis", MessageElement::Text));
|
||||
builder1.getMessage()->flags |= Message::Centered;
|
||||
emojiChannel->addMessage(builder1.getMessage());
|
||||
|
||||
// emojis
|
||||
messages::MessageBuilder builder;
|
||||
builder.getMessage()->flags |= Message::Centered;
|
||||
builder.getMessage()->flags |= Message::DisableCompactEmotes;
|
||||
|
||||
emojis.each([&builder](const QString &key, const auto &value) {
|
||||
builder.append(
|
||||
(new EmoteElement(value->emoteData, MessageElement::Flags::AlwaysShow))
|
||||
->setLink(Link(Link::Type::InsertText, ":" + value->shortCodes[0] + ":")));
|
||||
});
|
||||
emojiChannel->addMessage(builder.getMessage());
|
||||
|
||||
this->viewEmojis->setChannel(emojiChannel);
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class EmotePopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
EmotePopup();
|
||||
|
||||
void loadChannel(ChannelPtr channel);
|
||||
void loadEmojis();
|
||||
|
||||
pajlada::Signals::Signal<messages::Link> linkClicked;
|
||||
|
||||
private:
|
||||
ChannelView *viewEmotes;
|
||||
ChannelView *viewEmojis;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "LastRunCrashDialog.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "singletons/UpdateManager.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/PostToThread.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
LastRunCrashDialog::LastRunCrashDialog()
|
||||
{
|
||||
this->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
this->setWindowTitle("Chatterino");
|
||||
|
||||
auto &updateManager = singletons::UpdateManager::getInstance();
|
||||
|
||||
auto layout = util::LayoutCreator<LastRunCrashDialog>(this).setLayoutType<QVBoxLayout>();
|
||||
|
||||
layout.emplace<QLabel>(
|
||||
"The application wasn't terminated properly the last time it was executed.");
|
||||
|
||||
layout->addSpacing(16);
|
||||
|
||||
// auto update = layout.emplace<QLabel>();
|
||||
auto buttons = layout.emplace<QDialogButtonBox>();
|
||||
|
||||
// auto *installUpdateButton = buttons->addButton("Install Update",
|
||||
// QDialogButtonBox::NoRole); installUpdateButton->setEnabled(false);
|
||||
// QObject::connect(installUpdateButton, &QPushButton::clicked, [this, update]() mutable {
|
||||
// auto &updateManager = singletons::UpdateManager::getInstance();
|
||||
|
||||
// updateManager.installUpdates();
|
||||
// this->setEnabled(false);
|
||||
// update->setText("Downloading updates...");
|
||||
// });
|
||||
|
||||
auto *okButton = buttons->addButton("Ignore", QDialogButtonBox::ButtonRole::NoRole);
|
||||
QObject::connect(okButton, &QPushButton::clicked, [this] { this->accept(); });
|
||||
|
||||
// Updates
|
||||
// auto updateUpdateLabel = [update]() mutable {
|
||||
// auto &updateManager = singletons::UpdateManager::getInstance();
|
||||
|
||||
// switch (updateManager.getStatus()) {
|
||||
// case singletons::UpdateManager::None: {
|
||||
// update->setText("Not checking for updates.");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::Searching: {
|
||||
// update->setText("Checking for updates...");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::UpdateAvailable: {
|
||||
// update->setText("Update available.");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::NoUpdateAvailable: {
|
||||
// update->setText("No update abailable.");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::SearchFailed: {
|
||||
// update->setText("Error while searching for update.\nEither the update service
|
||||
// is "
|
||||
// "temporarily down or there is an issue with your
|
||||
// installation.");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::Downloading: {
|
||||
// update->setText(
|
||||
// "Downloading the update. Chatterino will close once the download is
|
||||
// done.");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::DownloadFailed: {
|
||||
// update->setText("Download failed.");
|
||||
// } break;
|
||||
// case singletons::UpdateManager::WriteFileFailed: {
|
||||
// update->setText("Writing the update file to the hard drive failed.");
|
||||
// } break;
|
||||
// }
|
||||
// };
|
||||
|
||||
// updateUpdateLabel();
|
||||
// this->managedConnect(updateManager.statusUpdated, [updateUpdateLabel](auto) mutable {
|
||||
// util::postToThread([updateUpdateLabel]() mutable { updateUpdateLabel(); });
|
||||
// });
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class LastRunCrashDialog : public QDialog, pajlada::Signals::SignalHolder
|
||||
{
|
||||
public:
|
||||
LastRunCrashDialog();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,219 @@
|
||||
#include "widgets/dialogs/LoginDialog.hpp"
|
||||
#include "Common.hpp"
|
||||
#include "util/UrlFetch.hpp"
|
||||
#ifdef USEWINSDK
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
#include <pajlada/settings/setting.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
namespace {
|
||||
|
||||
void LogInWithCredentials(const std::string &userID, const std::string &username,
|
||||
const std::string &clientID, const std::string &oauthToken)
|
||||
{
|
||||
QStringList errors;
|
||||
|
||||
if (userID.empty()) {
|
||||
errors.append("Missing user ID");
|
||||
}
|
||||
if (username.empty()) {
|
||||
errors.append("Missing username");
|
||||
}
|
||||
if (clientID.empty()) {
|
||||
errors.append("Missing Client ID");
|
||||
}
|
||||
if (oauthToken.empty()) {
|
||||
errors.append("Missing OAuth Token");
|
||||
}
|
||||
|
||||
if (errors.length() > 0) {
|
||||
QMessageBox messageBox;
|
||||
messageBox.setIcon(QMessageBox::Critical);
|
||||
messageBox.setText(errors.join("<br />"));
|
||||
messageBox.setStandardButtons(QMessageBox::Ok);
|
||||
messageBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
// QMessageBox messageBox;
|
||||
// messageBox.setIcon(QMessageBox::Information);
|
||||
// messageBox.setText("Successfully logged in with user <b>" + qS(username) + "</b>!");
|
||||
pajlada::Settings::Setting<std::string>::set("/accounts/uid" + userID + "/username", username);
|
||||
pajlada::Settings::Setting<std::string>::set("/accounts/uid" + userID + "/userID", userID);
|
||||
pajlada::Settings::Setting<std::string>::set("/accounts/uid" + userID + "/clientID", clientID);
|
||||
pajlada::Settings::Setting<std::string>::set("/accounts/uid" + userID + "/oauthToken",
|
||||
oauthToken);
|
||||
|
||||
getApp()->accounts->twitch.reloadUsers();
|
||||
|
||||
// messageBox.exec();
|
||||
|
||||
getApp()->accounts->twitch.currentUsername = username;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BasicLoginWidget::BasicLoginWidget()
|
||||
{
|
||||
this->setLayout(&this->ui.layout);
|
||||
|
||||
this->ui.loginButton.setText("Log in (Opens in browser)");
|
||||
this->ui.pasteCodeButton.setText("Paste code");
|
||||
|
||||
this->ui.horizontalLayout.addWidget(&this->ui.loginButton);
|
||||
this->ui.horizontalLayout.addWidget(&this->ui.pasteCodeButton);
|
||||
|
||||
this->ui.layout.addLayout(&this->ui.horizontalLayout);
|
||||
|
||||
connect(&this->ui.loginButton, &QPushButton::clicked, []() {
|
||||
printf("open login in browser\n");
|
||||
QDesktopServices::openUrl(QUrl("https://chatterino.com/client_login"));
|
||||
});
|
||||
|
||||
connect(&this->ui.pasteCodeButton, &QPushButton::clicked, [this]() {
|
||||
QClipboard *clipboard = QGuiApplication::clipboard();
|
||||
QString clipboardString = clipboard->text();
|
||||
QStringList parameters = clipboardString.split(';');
|
||||
|
||||
std::string oauthToken, clientID, username, userID;
|
||||
|
||||
for (const auto ¶m : parameters) {
|
||||
QStringList kvParameters = param.split('=');
|
||||
if (kvParameters.size() != 2) {
|
||||
continue;
|
||||
}
|
||||
QString key = kvParameters[0];
|
||||
QString value = kvParameters[1];
|
||||
|
||||
if (key == "oauth_token") {
|
||||
oauthToken = value.toStdString();
|
||||
} else if (key == "client_id") {
|
||||
clientID = value.toStdString();
|
||||
} else if (key == "username") {
|
||||
username = value.toStdString();
|
||||
} else if (key == "user_id") {
|
||||
userID = value.toStdString();
|
||||
} else {
|
||||
qDebug() << "Unknown key in code: " << key;
|
||||
}
|
||||
}
|
||||
|
||||
LogInWithCredentials(userID, username, clientID, oauthToken);
|
||||
|
||||
clipboard->clear();
|
||||
this->window()->close();
|
||||
});
|
||||
}
|
||||
|
||||
AdvancedLoginWidget::AdvancedLoginWidget()
|
||||
{
|
||||
this->setLayout(&this->ui.layout);
|
||||
|
||||
this->ui.instructionsLabel.setText("1. Fill in your username\n2. Fill in your user ID or press "
|
||||
"the 'Get user ID from username' button\n3. Fill in your "
|
||||
"Client ID\n4. Fill in your OAuth Token\n5. Press Add User");
|
||||
this->ui.instructionsLabel.setWordWrap(true);
|
||||
|
||||
this->ui.layout.addWidget(&this->ui.instructionsLabel);
|
||||
this->ui.layout.addLayout(&this->ui.formLayout);
|
||||
this->ui.layout.addLayout(&this->ui.buttonUpperRow.layout);
|
||||
this->ui.layout.addLayout(&this->ui.buttonLowerRow.layout);
|
||||
|
||||
this->refreshButtons();
|
||||
|
||||
/// Form
|
||||
this->ui.formLayout.addRow("Username", &this->ui.usernameInput);
|
||||
this->ui.formLayout.addRow("User ID", &this->ui.userIDInput);
|
||||
this->ui.formLayout.addRow("Client ID", &this->ui.clientIDInput);
|
||||
this->ui.formLayout.addRow("Oauth token", &this->ui.oauthTokenInput);
|
||||
|
||||
this->ui.oauthTokenInput.setEchoMode(QLineEdit::Password);
|
||||
|
||||
connect(&this->ui.userIDInput, &QLineEdit::textChanged, [=]() { this->refreshButtons(); });
|
||||
connect(&this->ui.usernameInput, &QLineEdit::textChanged, [=]() { this->refreshButtons(); });
|
||||
connect(&this->ui.clientIDInput, &QLineEdit::textChanged, [=]() { this->refreshButtons(); });
|
||||
connect(&this->ui.oauthTokenInput, &QLineEdit::textChanged, [=]() { this->refreshButtons(); });
|
||||
|
||||
/// Upper button row
|
||||
|
||||
this->ui.buttonUpperRow.addUserButton.setText("Add user");
|
||||
this->ui.buttonUpperRow.clearFieldsButton.setText("Clear fields");
|
||||
|
||||
this->ui.buttonUpperRow.layout.addWidget(&this->ui.buttonUpperRow.addUserButton);
|
||||
this->ui.buttonUpperRow.layout.addWidget(&this->ui.buttonUpperRow.clearFieldsButton);
|
||||
|
||||
connect(&this->ui.buttonUpperRow.clearFieldsButton, &QPushButton::clicked, [=]() {
|
||||
this->ui.userIDInput.clear();
|
||||
this->ui.usernameInput.clear();
|
||||
this->ui.clientIDInput.clear();
|
||||
this->ui.oauthTokenInput.clear();
|
||||
});
|
||||
|
||||
connect(&this->ui.buttonUpperRow.addUserButton, &QPushButton::clicked, [=]() {
|
||||
std::string userID = this->ui.userIDInput.text().toStdString();
|
||||
std::string username = this->ui.usernameInput.text().toStdString();
|
||||
std::string clientID = this->ui.clientIDInput.text().toStdString();
|
||||
std::string oauthToken = this->ui.oauthTokenInput.text().toStdString();
|
||||
|
||||
LogInWithCredentials(userID, username, clientID, oauthToken);
|
||||
});
|
||||
|
||||
/// Lower button row
|
||||
this->ui.buttonLowerRow.fillInUserIDButton.setText("Get user ID from username");
|
||||
|
||||
this->ui.buttonLowerRow.layout.addWidget(&this->ui.buttonLowerRow.fillInUserIDButton);
|
||||
|
||||
connect(&this->ui.buttonLowerRow.fillInUserIDButton, &QPushButton::clicked, [=]() {
|
||||
util::twitch::getUserID(this->ui.usernameInput.text(), this, [=](const QString &userID) {
|
||||
this->ui.userIDInput.setText(userID); //
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void AdvancedLoginWidget::refreshButtons()
|
||||
{
|
||||
this->ui.buttonLowerRow.fillInUserIDButton.setEnabled(!this->ui.usernameInput.text().isEmpty());
|
||||
|
||||
if (this->ui.userIDInput.text().isEmpty() || this->ui.usernameInput.text().isEmpty() ||
|
||||
this->ui.clientIDInput.text().isEmpty() || this->ui.oauthTokenInput.text().isEmpty()) {
|
||||
this->ui.buttonUpperRow.addUserButton.setEnabled(false);
|
||||
} else {
|
||||
this->ui.buttonUpperRow.addUserButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
LoginWidget::LoginWidget()
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||
#endif
|
||||
|
||||
this->setLayout(&this->ui.mainLayout);
|
||||
|
||||
this->ui.mainLayout.addWidget(&this->ui.tabWidget);
|
||||
|
||||
this->ui.tabWidget.addTab(&this->ui.basic, "Basic");
|
||||
|
||||
this->ui.tabWidget.addTab(&this->ui.advanced, "Advanced");
|
||||
|
||||
this->ui.buttonBox.setStandardButtons(QDialogButtonBox::Close);
|
||||
|
||||
QObject::connect(&this->ui.buttonBox, &QDialogButtonBox::rejected, [this]() {
|
||||
this->close(); //
|
||||
});
|
||||
|
||||
this->ui.mainLayout.addWidget(&this->ui.buttonBox);
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtWidgets/QAction>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QButtonGroup>
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QDialogButtonBox>
|
||||
#include <QtWidgets/QFormLayout>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QTabWidget>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class BasicLoginWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
BasicLoginWidget();
|
||||
|
||||
struct {
|
||||
QVBoxLayout layout;
|
||||
QHBoxLayout horizontalLayout;
|
||||
QPushButton loginButton;
|
||||
QPushButton pasteCodeButton;
|
||||
} ui;
|
||||
};
|
||||
|
||||
class AdvancedLoginWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
AdvancedLoginWidget();
|
||||
|
||||
void refreshButtons();
|
||||
|
||||
struct {
|
||||
QVBoxLayout layout;
|
||||
|
||||
QLabel instructionsLabel;
|
||||
|
||||
QFormLayout formLayout;
|
||||
|
||||
QLineEdit userIDInput;
|
||||
QLineEdit usernameInput;
|
||||
QLineEdit clientIDInput;
|
||||
QLineEdit oauthTokenInput;
|
||||
|
||||
struct {
|
||||
QHBoxLayout layout;
|
||||
|
||||
QPushButton addUserButton;
|
||||
QPushButton clearFieldsButton;
|
||||
} buttonUpperRow;
|
||||
|
||||
struct {
|
||||
QHBoxLayout layout;
|
||||
|
||||
QPushButton fillInUserIDButton;
|
||||
} buttonLowerRow;
|
||||
} ui;
|
||||
};
|
||||
|
||||
class LoginWidget : public QDialog
|
||||
{
|
||||
public:
|
||||
LoginWidget();
|
||||
|
||||
private:
|
||||
struct {
|
||||
QVBoxLayout mainLayout;
|
||||
|
||||
QTabWidget tabWidget;
|
||||
|
||||
QDialogButtonBox buttonBox;
|
||||
|
||||
BasicLoginWidget basic;
|
||||
|
||||
AdvancedLoginWidget advanced;
|
||||
} ui;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "NotificationPopup.hpp"
|
||||
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QScreen>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
NotificationPopup::NotificationPopup()
|
||||
: BaseWindow((QWidget *)nullptr, BaseWindow::Frameless)
|
||||
, channel(std::make_shared<Channel>("notifications", Channel::None))
|
||||
|
||||
{
|
||||
this->channelView = new ChannelView(this);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
this->setLayout(layout);
|
||||
|
||||
layout->addWidget(this->channelView);
|
||||
|
||||
this->channelView->setChannel(this->channel);
|
||||
this->setScaleIndependantSize(300, 150);
|
||||
}
|
||||
|
||||
void NotificationPopup::updatePosition()
|
||||
{
|
||||
Location location = BottomRight;
|
||||
|
||||
QDesktopWidget *desktop = QApplication::desktop();
|
||||
const QRect rect = desktop->availableGeometry();
|
||||
|
||||
switch (location) {
|
||||
case BottomRight: {
|
||||
this->move(rect.right() - this->width(), rect.bottom() - this->height());
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationPopup::addMessage(messages::MessagePtr msg)
|
||||
{
|
||||
this->channel->addMessage(msg);
|
||||
|
||||
// QTimer::singleShot(5000, this, [this, msg] { this->channel->remove });
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "Channel.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class ChannelView;
|
||||
|
||||
class NotificationPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
enum Location { TopLeft, TopRight, BottomLeft, BottomRight };
|
||||
NotificationPopup();
|
||||
|
||||
void addMessage(messages::MessagePtr msg);
|
||||
void updatePosition();
|
||||
|
||||
private:
|
||||
ChannelView *channelView;
|
||||
ChannelPtr channel;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "QualityPopup.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "util/StreamLink.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
QualityPopup::QualityPopup(const QString &_channelName, QStringList options)
|
||||
: channelName(_channelName)
|
||||
{
|
||||
this->ui_.okButton.setText("OK");
|
||||
this->ui_.cancelButton.setText("Cancel");
|
||||
|
||||
QObject::connect(&this->ui_.okButton, &QPushButton::clicked, this,
|
||||
&QualityPopup::okButtonClicked);
|
||||
QObject::connect(&this->ui_.cancelButton, &QPushButton::clicked, this,
|
||||
&QualityPopup::cancelButtonClicked);
|
||||
|
||||
this->ui_.buttonBox.addButton(&this->ui_.okButton, QDialogButtonBox::ButtonRole::AcceptRole);
|
||||
this->ui_.buttonBox.addButton(&this->ui_.cancelButton, QDialogButtonBox::ButtonRole::RejectRole);
|
||||
|
||||
this->ui_.selector.addItems(options);
|
||||
|
||||
this->ui_.vbox.addWidget(&this->ui_.selector);
|
||||
this->ui_.vbox.addWidget(&this->ui_.buttonBox);
|
||||
|
||||
this->setLayout(&this->ui_.vbox);
|
||||
}
|
||||
|
||||
void QualityPopup::showDialog(const QString &channelName, QStringList options)
|
||||
{
|
||||
QualityPopup *instance = new QualityPopup(channelName, options);
|
||||
|
||||
instance->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
instance->show();
|
||||
instance->activateWindow();
|
||||
instance->raise();
|
||||
instance->setFocus();
|
||||
}
|
||||
|
||||
void QualityPopup::okButtonClicked()
|
||||
{
|
||||
QString channelURL = "twitch.tv/" + this->channelName;
|
||||
|
||||
try {
|
||||
streamlink::OpenStreamlink(channelURL, this->ui_.selector.currentText());
|
||||
} catch (const streamlink::Exception &ex) {
|
||||
debug::Log("Exception caught trying to open streamlink: {}", ex.what());
|
||||
}
|
||||
|
||||
this->close();
|
||||
}
|
||||
|
||||
void QualityPopup::cancelButtonClicked()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class QualityPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
QualityPopup(const QString &_channelName, QStringList options);
|
||||
static void showDialog(const QString &_channelName, QStringList options);
|
||||
|
||||
private:
|
||||
struct {
|
||||
QVBoxLayout vbox;
|
||||
QComboBox selector;
|
||||
QDialogButtonBox buttonBox;
|
||||
QPushButton okButton;
|
||||
QPushButton cancelButton;
|
||||
} ui_;
|
||||
|
||||
QString channelName;
|
||||
|
||||
void okButtonClicked();
|
||||
void cancelButtonClicked();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,283 @@
|
||||
#include "SelectChannelDialog.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "providers/twitch/TwitchServer.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#define TAB_TWITCH 0
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
SelectChannelDialog::SelectChannelDialog(QWidget *parent)
|
||||
: BaseWindow(parent, BaseWindow::EnableCustomFrame)
|
||||
, selectedChannel(Channel::getEmpty())
|
||||
{
|
||||
this->setWindowTitle("Select a channel to join");
|
||||
|
||||
this->tabFilter.dialog = this;
|
||||
|
||||
util::LayoutCreator<QWidget> layoutWidget(this->getLayoutContainer());
|
||||
auto layout = layoutWidget.setLayoutType<QVBoxLayout>().withoutMargin();
|
||||
auto notebook = layout.emplace<Notebook>(this).assign(&this->ui_.notebook);
|
||||
|
||||
// twitch
|
||||
{
|
||||
util::LayoutCreator<QWidget> obj(new QWidget());
|
||||
auto vbox = obj.setLayoutType<QVBoxLayout>();
|
||||
|
||||
// channel_btn
|
||||
auto channel_btn = vbox.emplace<QRadioButton>("Channel").assign(&this->ui_.twitch.channel);
|
||||
auto channel_lbl = vbox.emplace<QLabel>("Join a twitch channel by its name.").hidden();
|
||||
channel_lbl->setWordWrap(true);
|
||||
auto channel_edit =
|
||||
vbox.emplace<QLineEdit>().hidden().assign(&this->ui_.twitch.channelName);
|
||||
|
||||
QObject::connect(channel_btn.getElement(), &QRadioButton::toggled,
|
||||
[=](bool enabled) mutable {
|
||||
if (enabled) {
|
||||
channel_edit->setFocus();
|
||||
channel_edit->setSelection(0, channel_edit->text().length());
|
||||
}
|
||||
|
||||
channel_edit->setVisible(enabled);
|
||||
channel_lbl->setVisible(enabled);
|
||||
});
|
||||
|
||||
channel_btn->installEventFilter(&this->tabFilter);
|
||||
channel_edit->installEventFilter(&this->tabFilter);
|
||||
|
||||
// whispers_btn
|
||||
auto whispers_btn =
|
||||
vbox.emplace<QRadioButton>("Whispers").assign(&this->ui_.twitch.whispers);
|
||||
auto whispers_lbl =
|
||||
vbox.emplace<QLabel>("Shows the whispers that you receive while chatterino is running.")
|
||||
.hidden();
|
||||
|
||||
whispers_lbl->setWordWrap(true);
|
||||
whispers_btn->installEventFilter(&this->tabFilter);
|
||||
|
||||
QObject::connect(whispers_btn.getElement(), &QRadioButton::toggled,
|
||||
[=](bool enabled) mutable { whispers_lbl->setVisible(enabled); });
|
||||
|
||||
// mentions_btn
|
||||
auto mentions_btn =
|
||||
vbox.emplace<QRadioButton>("Mentions").assign(&this->ui_.twitch.mentions);
|
||||
auto mentions_lbl =
|
||||
vbox.emplace<QLabel>("Shows all the messages that highlight you from any channel.")
|
||||
.hidden();
|
||||
|
||||
mentions_lbl->setWordWrap(true);
|
||||
mentions_btn->installEventFilter(&this->tabFilter);
|
||||
|
||||
QObject::connect(mentions_btn.getElement(), &QRadioButton::toggled,
|
||||
[=](bool enabled) mutable { mentions_lbl->setVisible(enabled); });
|
||||
|
||||
// watching_btn
|
||||
auto watching_btn =
|
||||
vbox.emplace<QRadioButton>("Watching").assign(&this->ui_.twitch.watching);
|
||||
auto watching_lbl =
|
||||
vbox.emplace<QLabel>("Requires the chatterino browser extension.").hidden();
|
||||
|
||||
watching_lbl->setWordWrap(true);
|
||||
watching_btn->installEventFilter(&this->tabFilter);
|
||||
|
||||
QObject::connect(watching_btn.getElement(), &QRadioButton::toggled,
|
||||
[=](bool enabled) mutable { watching_lbl->setVisible(enabled); });
|
||||
|
||||
vbox->addStretch(1);
|
||||
|
||||
// tabbing order
|
||||
QWidget::setTabOrder(watching_btn.getElement(), channel_btn.getElement());
|
||||
QWidget::setTabOrder(channel_btn.getElement(), whispers_btn.getElement());
|
||||
QWidget::setTabOrder(whispers_btn.getElement(), mentions_btn.getElement());
|
||||
QWidget::setTabOrder(mentions_btn.getElement(), watching_btn.getElement());
|
||||
|
||||
// tab
|
||||
NotebookTab *tab = notebook->addPage(obj.getElement());
|
||||
tab->setCustomTitle("Twitch");
|
||||
}
|
||||
|
||||
// irc
|
||||
/*{
|
||||
util::LayoutCreator<QWidget> obj(new QWidget());
|
||||
auto vbox = obj.setLayoutType<QVBoxLayout>();
|
||||
|
||||
auto edit = vbox.emplace<QLabel>("not implemented");
|
||||
|
||||
NotebookTab2 *tab = notebook->addPage(obj.getElement());
|
||||
tab->setTitle("Irc");
|
||||
}*/
|
||||
|
||||
layout->setStretchFactor(notebook.getElement(), 1);
|
||||
|
||||
auto buttons = layout.emplace<QHBoxLayout>().emplace<QDialogButtonBox>(this);
|
||||
{
|
||||
auto *button_ok = buttons->addButton(QDialogButtonBox::Ok);
|
||||
QObject::connect(button_ok, &QPushButton::clicked, [=](bool) { this->ok(); });
|
||||
auto *button_cancel = buttons->addButton(QDialogButtonBox::Cancel);
|
||||
QObject::connect(button_cancel, &QAbstractButton::clicked, [=](bool) { this->close(); });
|
||||
}
|
||||
|
||||
this->setScaleIndependantSize(300, 210);
|
||||
this->ui_.notebook->selectIndex(TAB_TWITCH);
|
||||
this->ui_.twitch.channel->setFocus();
|
||||
|
||||
// Shortcuts
|
||||
auto *shortcut_ok = new QShortcut(QKeySequence("Return"), this);
|
||||
QObject::connect(shortcut_ok, &QShortcut::activated, [=] { this->ok(); });
|
||||
auto *shortcut_cancel = new QShortcut(QKeySequence("Esc"), this);
|
||||
QObject::connect(shortcut_cancel, &QShortcut::activated, [=] { this->close(); });
|
||||
}
|
||||
|
||||
void SelectChannelDialog::ok()
|
||||
{
|
||||
this->_hasSelectedChannel = true;
|
||||
this->close();
|
||||
}
|
||||
|
||||
void SelectChannelDialog::setSelectedChannel(IndirectChannel _channel)
|
||||
{
|
||||
auto channel = _channel.get();
|
||||
|
||||
assert(channel);
|
||||
|
||||
this->selectedChannel = channel;
|
||||
|
||||
switch (_channel.getType()) {
|
||||
case Channel::Twitch: {
|
||||
this->ui_.notebook->selectIndex(TAB_TWITCH);
|
||||
this->ui_.twitch.channel->setFocus();
|
||||
this->ui_.twitch.channelName->setText(channel->name);
|
||||
} break;
|
||||
case Channel::TwitchWatching: {
|
||||
this->ui_.notebook->selectIndex(TAB_TWITCH);
|
||||
this->ui_.twitch.watching->setFocus();
|
||||
} break;
|
||||
case Channel::TwitchMentions: {
|
||||
this->ui_.notebook->selectIndex(TAB_TWITCH);
|
||||
this->ui_.twitch.mentions->setFocus();
|
||||
} break;
|
||||
case Channel::TwitchWhispers: {
|
||||
this->ui_.notebook->selectIndex(TAB_TWITCH);
|
||||
this->ui_.twitch.whispers->setFocus();
|
||||
} break;
|
||||
default: {
|
||||
this->ui_.notebook->selectIndex(TAB_TWITCH);
|
||||
this->ui_.twitch.channel->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
this->_hasSelectedChannel = false;
|
||||
}
|
||||
|
||||
IndirectChannel SelectChannelDialog::getSelectedChannel() const
|
||||
{
|
||||
if (!this->_hasSelectedChannel) {
|
||||
return this->selectedChannel;
|
||||
}
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
switch (this->ui_.notebook->getSelectedIndex()) {
|
||||
case TAB_TWITCH: {
|
||||
if (this->ui_.twitch.channel->isChecked()) {
|
||||
return app->twitch.server->getOrAddChannel(this->ui_.twitch.channelName->text());
|
||||
} else if (this->ui_.twitch.watching->isChecked()) {
|
||||
return app->twitch.server->watchingChannel;
|
||||
} else if (this->ui_.twitch.mentions->isChecked()) {
|
||||
return app->twitch.server->mentionsChannel;
|
||||
} else if (this->ui_.twitch.whispers->isChecked()) {
|
||||
return app->twitch.server->whispersChannel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this->selectedChannel;
|
||||
}
|
||||
|
||||
bool SelectChannelDialog::hasSeletedChannel() const
|
||||
{
|
||||
return this->_hasSelectedChannel;
|
||||
}
|
||||
|
||||
bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
auto *widget = (QWidget *)watched;
|
||||
|
||||
if (event->type() == QEvent::FocusIn) {
|
||||
widget->grabKeyboard();
|
||||
|
||||
auto *radio = dynamic_cast<QRadioButton *>(watched);
|
||||
if (radio) {
|
||||
radio->setChecked(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (event->type() == QEvent::FocusOut) {
|
||||
widget->releaseKeyboard();
|
||||
return false;
|
||||
} else if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *event_key = static_cast<QKeyEvent *>(event);
|
||||
if ((event_key->key() == Qt::Key_Tab || event_key->key() == Qt::Key_Down) &&
|
||||
event_key->modifiers() == Qt::NoModifier) {
|
||||
if (widget == this->dialog->ui_.twitch.channelName) {
|
||||
this->dialog->ui_.twitch.whispers->setFocus();
|
||||
return true;
|
||||
} else {
|
||||
widget->nextInFocusChain()->setFocus();
|
||||
}
|
||||
return true;
|
||||
} else if (((event_key->key() == Qt::Key_Tab || event_key->key() == Qt::Key_Backtab) &&
|
||||
event_key->modifiers() == Qt::ShiftModifier) ||
|
||||
((event_key->key() == Qt::Key_Up) && event_key->modifiers() == Qt::NoModifier)) {
|
||||
if (widget == this->dialog->ui_.twitch.channelName) {
|
||||
this->dialog->ui_.twitch.watching->setFocus();
|
||||
return true;
|
||||
} else if (widget == this->dialog->ui_.twitch.whispers) {
|
||||
this->dialog->ui_.twitch.channel->setFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
widget->previousInFocusChain()->setFocus();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (event->type() == QEvent::KeyRelease) {
|
||||
QKeyEvent *event_key = static_cast<QKeyEvent *>(event);
|
||||
if ((event_key->key() == Qt::Key_Backtab || event_key->key() == Qt::Key_Down) &&
|
||||
event_key->modifiers() == Qt::NoModifier) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SelectChannelDialog::closeEvent(QCloseEvent *)
|
||||
{
|
||||
this->closed.invoke();
|
||||
}
|
||||
|
||||
void SelectChannelDialog::themeRefreshEvent()
|
||||
{
|
||||
BaseWindow::themeRefreshEvent();
|
||||
|
||||
if (this->themeManager->isLightTheme()) {
|
||||
this->setStyleSheet("QRadioButton { color: #000 } QLabel { color: #000 }");
|
||||
} else {
|
||||
this->setStyleSheet("QRadioButton { color: #fff } QLabel { color: #fff }");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QRadioButton>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class SelectChannelDialog : public BaseWindow
|
||||
{
|
||||
public:
|
||||
SelectChannelDialog(QWidget *parent = nullptr);
|
||||
|
||||
void setSelectedChannel(IndirectChannel selectedChannel);
|
||||
IndirectChannel getSelectedChannel() const;
|
||||
bool hasSeletedChannel() const;
|
||||
|
||||
pajlada::Signals::NoArgSignal closed;
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent *) override;
|
||||
virtual void themeRefreshEvent() override;
|
||||
|
||||
private:
|
||||
class EventFilter : public QObject
|
||||
{
|
||||
public:
|
||||
SelectChannelDialog *dialog;
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
};
|
||||
|
||||
struct {
|
||||
Notebook *notebook;
|
||||
struct {
|
||||
QRadioButton *channel;
|
||||
QLineEdit *channelName;
|
||||
QRadioButton *whispers;
|
||||
QRadioButton *mentions;
|
||||
QRadioButton *watching;
|
||||
} twitch;
|
||||
} ui_;
|
||||
|
||||
EventFilter tabFilter;
|
||||
|
||||
ChannelPtr selectedChannel;
|
||||
bool _hasSelectedChannel = false;
|
||||
|
||||
void ok();
|
||||
friend class EventFilter;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,228 @@
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/SettingsDialogTab.hpp"
|
||||
#include "widgets/settingspages/AboutPage.hpp"
|
||||
#include "widgets/settingspages/AccountsPage.hpp"
|
||||
#include "widgets/settingspages/AppearancePage.hpp"
|
||||
#include "widgets/settingspages/BehaviourPage.hpp"
|
||||
#include "widgets/settingspages/BrowserextensionPage.hpp"
|
||||
#include "widgets/settingspages/CommandPage.hpp"
|
||||
#include "widgets/settingspages/EmotesPage.hpp"
|
||||
#include "widgets/settingspages/ExternaltoolsPage.hpp"
|
||||
#include "widgets/settingspages/HighlightingPage.hpp"
|
||||
#include "widgets/settingspages/IgnoreusersPage.hpp"
|
||||
#include "widgets/settingspages/KeyboardsettingsPage.hpp"
|
||||
#include "widgets/settingspages/LogsPage.hpp"
|
||||
#include "widgets/settingspages/ModerationPage.hpp"
|
||||
#include "widgets/settingspages/SpecialChannelsPage.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
SettingsDialog *SettingsDialog::handle = nullptr;
|
||||
|
||||
SettingsDialog::SettingsDialog()
|
||||
: BaseWindow(nullptr, BaseWindow::DisableCustomScaling)
|
||||
{
|
||||
this->initUi();
|
||||
|
||||
this->addTabs();
|
||||
|
||||
this->scaleChangedEvent(this->getScale());
|
||||
}
|
||||
|
||||
void SettingsDialog::initUi()
|
||||
{
|
||||
util::LayoutCreator<SettingsDialog> layoutCreator(this);
|
||||
|
||||
// tab pages
|
||||
layoutCreator.emplace<QWidget>()
|
||||
.assign(&this->ui_.tabContainerContainer)
|
||||
.emplace<QVBoxLayout>()
|
||||
.withoutMargin()
|
||||
.assign(&this->ui_.tabContainer);
|
||||
|
||||
// right side layout
|
||||
auto right = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||
{
|
||||
right.emplace<QStackedLayout>().assign(&this->ui_.pageStack).withoutMargin();
|
||||
|
||||
auto buttons = right.emplace<QDialogButtonBox>(Qt::Horizontal);
|
||||
{
|
||||
this->ui_.okButton = buttons->addButton("Ok", QDialogButtonBox::YesRole);
|
||||
this->ui_.cancelButton = buttons->addButton("Cancel", QDialogButtonBox::NoRole);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
this->ui_.tabContainerContainer->setObjectName("tabWidget");
|
||||
this->ui_.pageStack->setObjectName("pages");
|
||||
|
||||
QObject::connect(this->ui_.okButton, &QPushButton::clicked, this,
|
||||
&SettingsDialog::okButtonClicked);
|
||||
QObject::connect(this->ui_.cancelButton, &QPushButton::clicked, this,
|
||||
&SettingsDialog::cancelButtonClicked);
|
||||
}
|
||||
|
||||
SettingsDialog *SettingsDialog::getHandle()
|
||||
{
|
||||
return SettingsDialog::handle;
|
||||
}
|
||||
|
||||
void SettingsDialog::addTabs()
|
||||
{
|
||||
this->ui_.tabContainer->setSpacing(0);
|
||||
|
||||
this->addTab(new settingspages::AccountsPage);
|
||||
|
||||
this->ui_.tabContainer->addSpacing(16);
|
||||
|
||||
this->addTab(new settingspages::AppearancePage);
|
||||
this->addTab(new settingspages::BehaviourPage);
|
||||
|
||||
this->ui_.tabContainer->addSpacing(16);
|
||||
|
||||
this->addTab(new settingspages::CommandPage);
|
||||
// this->addTab(new settingspages::EmotesPage);
|
||||
this->addTab(new settingspages::HighlightingPage);
|
||||
this->addTab(new settingspages::IgnoreUsersPage);
|
||||
|
||||
this->ui_.tabContainer->addSpacing(16);
|
||||
|
||||
this->addTab(new settingspages::KeyboardSettingsPage);
|
||||
// this->addTab(new settingspages::LogsPage);
|
||||
this->addTab(new settingspages::ModerationPage);
|
||||
// this->addTab(new settingspages::SpecialChannelsPage);
|
||||
this->addTab(new settingspages::BrowserExtensionPage);
|
||||
this->addTab(new settingspages::ExternalToolsPage);
|
||||
|
||||
this->ui_.tabContainer->addStretch(1);
|
||||
this->addTab(new settingspages::AboutPage, Qt::AlignBottom);
|
||||
}
|
||||
|
||||
void SettingsDialog::addTab(settingspages::SettingsPage *page, Qt::Alignment alignment)
|
||||
{
|
||||
auto tab = new SettingsDialogTab(this, page, page->getIconResource());
|
||||
|
||||
this->ui_.pageStack->addWidget(page);
|
||||
this->ui_.tabContainer->addWidget(tab, 0, alignment);
|
||||
this->tabs.push_back(tab);
|
||||
|
||||
if (this->tabs.size() == 1) {
|
||||
this->select(tab);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::select(SettingsDialogTab *tab)
|
||||
{
|
||||
this->ui_.pageStack->setCurrentWidget(tab->getSettingsPage());
|
||||
|
||||
if (this->selectedTab != nullptr) {
|
||||
this->selectedTab->setSelected(false);
|
||||
this->selectedTab->setStyleSheet("color: #FFF");
|
||||
}
|
||||
|
||||
tab->setSelected(true);
|
||||
tab->setStyleSheet("background: #555; color: #FFF");
|
||||
this->selectedTab = tab;
|
||||
}
|
||||
|
||||
void SettingsDialog::showDialog(PreferredTab preferredTab)
|
||||
{
|
||||
static SettingsDialog *instance = new SettingsDialog();
|
||||
instance->refresh();
|
||||
|
||||
switch (preferredTab) {
|
||||
case SettingsDialog::PreferredTab::Accounts: {
|
||||
instance->select(instance->tabs.at(0));
|
||||
} break;
|
||||
}
|
||||
|
||||
instance->show();
|
||||
instance->activateWindow();
|
||||
instance->raise();
|
||||
instance->setFocus();
|
||||
}
|
||||
|
||||
void SettingsDialog::refresh()
|
||||
{
|
||||
// this->ui.accountSwitchWidget->refresh();
|
||||
|
||||
getApp()->settings->saveSnapshot();
|
||||
|
||||
for (auto *tab : this->tabs) {
|
||||
tab->getSettingsPage()->onShow();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::scaleChangedEvent(float newDpi)
|
||||
{
|
||||
QFile file(":/qss/settings.qss");
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
styleSheet.replace("<font-size>", QString::number((int)(14 * newDpi)));
|
||||
styleSheet.replace("<checkbox-size>", QString::number((int)(14 * newDpi)));
|
||||
|
||||
for (SettingsDialogTab *tab : this->tabs) {
|
||||
tab->setFixedHeight((int)(30 * newDpi));
|
||||
}
|
||||
|
||||
this->setStyleSheet(styleSheet);
|
||||
|
||||
this->ui_.tabContainerContainer->setFixedWidth((int)(200 * newDpi));
|
||||
}
|
||||
|
||||
void SettingsDialog::themeRefreshEvent()
|
||||
{
|
||||
BaseWindow::themeRefreshEvent();
|
||||
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Background, QColor("#444"));
|
||||
this->setPalette(palette);
|
||||
}
|
||||
|
||||
// void SettingsDialog::setChildrensFont(QLayout *object, QFont &font, int indent)
|
||||
//{
|
||||
// // for (QWidget *widget : this->widgets) {
|
||||
// // widget->setFont(font);
|
||||
// // }
|
||||
// // for (int i = 0; i < object->count(); i++) {
|
||||
// // if (object->itemAt(i)->layout()) {
|
||||
// // setChildrensFont(object->layout()->itemAt(i)->layout(), font, indent + 2);
|
||||
// // }
|
||||
|
||||
// // if (object->itemAt(i)->widget()) {
|
||||
// // object->itemAt(i)->widget()->setFont(font);
|
||||
|
||||
// // if (object->itemAt(i)->widget()->layout() &&
|
||||
// // !object->itemAt(i)->widget()->layout()->isEmpty()) {
|
||||
// // setChildrensFont(object->itemAt(i)->widget()->layout(), font, indent +
|
||||
// 2);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
//}
|
||||
|
||||
///// Widget creation helpers
|
||||
void SettingsDialog::okButtonClicked()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
|
||||
void SettingsDialog::cancelButtonClicked()
|
||||
{
|
||||
for (auto &tab : this->tabs) {
|
||||
tab->getSettingsPage()->cancel();
|
||||
}
|
||||
|
||||
getApp()->settings->recallSnapshot();
|
||||
|
||||
this->close();
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QStackedLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <pajlada/settings/setting.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
namespace settingspages {
|
||||
class SettingsPage;
|
||||
} // namespace settingspages
|
||||
|
||||
class SettingsDialogTab;
|
||||
|
||||
class SettingsDialog : public BaseWindow
|
||||
{
|
||||
public:
|
||||
SettingsDialog();
|
||||
|
||||
static SettingsDialog *getHandle(); // may be NULL
|
||||
|
||||
enum class PreferredTab {
|
||||
NoPreference,
|
||||
Accounts,
|
||||
};
|
||||
|
||||
static void showDialog(PreferredTab preferredTab = PreferredTab::NoPreference);
|
||||
|
||||
protected:
|
||||
virtual void scaleChangedEvent(float newDpi) override;
|
||||
virtual void themeRefreshEvent() override;
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
static SettingsDialog *handle;
|
||||
|
||||
struct {
|
||||
QWidget *tabContainerContainer;
|
||||
QVBoxLayout *tabContainer;
|
||||
QStackedLayout *pageStack;
|
||||
QPushButton *okButton;
|
||||
QPushButton *cancelButton;
|
||||
} ui_;
|
||||
|
||||
std::vector<SettingsDialogTab *> tabs;
|
||||
|
||||
void initUi();
|
||||
void addTabs();
|
||||
void addTab(settingspages::SettingsPage *page, Qt::Alignment alignment = Qt::AlignTop);
|
||||
|
||||
void select(SettingsDialogTab *tab);
|
||||
|
||||
SettingsDialogTab *selectedTab = nullptr;
|
||||
|
||||
void okButtonClicked();
|
||||
void cancelButtonClicked();
|
||||
|
||||
friend class SettingsDialogTab;
|
||||
|
||||
// static void setChildrensFont(QLayout *object, QFont &font, int indent = 0);
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "widgets/dialogs/TextInputDialog.hpp"
|
||||
#include <QSizePolicy>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
TextInputDialog::TextInputDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _vbox(this)
|
||||
, _okButton("OK")
|
||||
, _cancelButton("Cancel")
|
||||
{
|
||||
_vbox.addWidget(&_lineEdit);
|
||||
_vbox.addLayout(&_buttonBox);
|
||||
_buttonBox.addStretch(1);
|
||||
_buttonBox.addWidget(&_okButton);
|
||||
_buttonBox.addWidget(&_cancelButton);
|
||||
|
||||
QObject::connect(&_okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked()));
|
||||
QObject::connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(cancelButtonClicked()));
|
||||
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
setWindowFlags((windowFlags() & ~(Qt::WindowContextHelpButtonHint)) | Qt::Dialog |
|
||||
Qt::MSWindowsFixedSizeDialogHint);
|
||||
}
|
||||
|
||||
void TextInputDialog::okButtonClicked()
|
||||
{
|
||||
accept();
|
||||
close();
|
||||
}
|
||||
|
||||
void TextInputDialog::cancelButtonClicked()
|
||||
{
|
||||
reject();
|
||||
close();
|
||||
}
|
||||
|
||||
void TextInputDialog::highlightText()
|
||||
{
|
||||
this->_lineEdit.selectAll();
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class TextInputDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TextInputDialog(QWidget *parent = nullptr);
|
||||
|
||||
QString getText() const
|
||||
{
|
||||
return _lineEdit.text();
|
||||
}
|
||||
|
||||
void setText(const QString &text)
|
||||
{
|
||||
_lineEdit.setText(text);
|
||||
}
|
||||
|
||||
void highlightText();
|
||||
|
||||
private:
|
||||
QVBoxLayout _vbox;
|
||||
QLineEdit _lineEdit;
|
||||
QHBoxLayout _buttonBox;
|
||||
QPushButton _okButton;
|
||||
QPushButton _cancelButton;
|
||||
|
||||
private slots:
|
||||
void okButtonClicked();
|
||||
void cancelButtonClicked();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,408 @@
|
||||
#include "UserInfoPopup.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "singletons/ResourceManager.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/PostToThread.hpp"
|
||||
#include "util/UrlFetch.hpp"
|
||||
#include "widgets/helper/Line.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
#include "widgets/Label.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QLabel>
|
||||
|
||||
#define TEXT_FOLLOWERS "Followers: "
|
||||
#define TEXT_VIEWS "Views: "
|
||||
#define TEXT_CREATED "Created: "
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
UserInfoPopup::UserInfoPopup()
|
||||
: BaseWindow(nullptr, BaseWindow::Flags(BaseWindow::Frameless | BaseWindow::DeleteOnFocusOut |
|
||||
BaseWindow::FramelessDraggable))
|
||||
, hack_(new bool)
|
||||
{
|
||||
this->setStayInScreenRect(true);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
this->setWindowFlag(Qt::Popup);
|
||||
#endif
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
auto layout = util::LayoutCreator<UserInfoPopup>(this).setLayoutType<QVBoxLayout>();
|
||||
|
||||
// first line
|
||||
auto head = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
// avatar
|
||||
auto avatar = head.emplace<RippleEffectButton>(nullptr).assign(&this->ui_.avatarButton);
|
||||
avatar->setScaleIndependantSize(100, 100);
|
||||
QObject::connect(avatar.getElement(), &RippleEffectButton::clicked, [this] {
|
||||
QDesktopServices::openUrl(QUrl("https://twitch.tv/" + this->userName_));
|
||||
});
|
||||
|
||||
// items on the right
|
||||
auto vbox = head.emplace<QVBoxLayout>();
|
||||
{
|
||||
auto name = vbox.emplace<Label>().assign(&this->ui_.nameLabel);
|
||||
|
||||
auto font = name->font();
|
||||
font.setBold(true);
|
||||
name->setFont(font);
|
||||
vbox.emplace<Label>(TEXT_VIEWS).assign(&this->ui_.viewCountLabel);
|
||||
vbox.emplace<Label>(TEXT_FOLLOWERS).assign(&this->ui_.followerCountLabel);
|
||||
vbox.emplace<Label>(TEXT_CREATED).assign(&this->ui_.createdDateLabel);
|
||||
}
|
||||
}
|
||||
|
||||
layout.emplace<Line>(false);
|
||||
|
||||
// second line
|
||||
auto user = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
user->addStretch(1);
|
||||
|
||||
user.emplace<QCheckBox>("Follow").assign(&this->ui_.follow);
|
||||
user.emplace<QCheckBox>("Ignore").assign(&this->ui_.ignore);
|
||||
user.emplace<QCheckBox>("Ignore highlights").assign(&this->ui_.ignoreHighlights);
|
||||
|
||||
auto mod = user.emplace<RippleEffectButton>(this);
|
||||
mod->setPixmap(app->resources->buttons.mod);
|
||||
mod->setScaleIndependantSize(30, 30);
|
||||
auto unmod = user.emplace<RippleEffectButton>(this);
|
||||
unmod->setPixmap(app->resources->buttons.unmod);
|
||||
unmod->setScaleIndependantSize(30, 30);
|
||||
|
||||
user->addStretch(1);
|
||||
|
||||
QObject::connect(mod.getElement(), &RippleEffectButton::clicked,
|
||||
[this] { this->channel_->sendMessage("/mod " + this->userName_); });
|
||||
QObject::connect(unmod.getElement(), &RippleEffectButton::clicked,
|
||||
[this] { this->channel_->sendMessage("/unmod " + this->userName_); });
|
||||
|
||||
// userstate
|
||||
this->userStateChanged.connect([this, mod, unmod]() mutable {
|
||||
providers::twitch::TwitchChannel *twitchChannel =
|
||||
dynamic_cast<providers::twitch::TwitchChannel *>(this->channel_.get());
|
||||
|
||||
if (twitchChannel) {
|
||||
qDebug() << this->userName_;
|
||||
|
||||
bool isMyself =
|
||||
QString::compare(getApp()->accounts->twitch.getCurrent()->getUserName(),
|
||||
this->userName_, Qt::CaseInsensitive) == 0;
|
||||
|
||||
mod->setVisible(twitchChannel->isBroadcaster() && !isMyself);
|
||||
unmod->setVisible((twitchChannel->isBroadcaster() && !isMyself) ||
|
||||
(twitchChannel->isMod() && isMyself));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto lineMod = layout.emplace<Line>(false);
|
||||
|
||||
// third line
|
||||
auto moderation = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
auto timeout = moderation.emplace<TimeoutWidget>();
|
||||
|
||||
this->userStateChanged.connect([this, lineMod, timeout]() mutable {
|
||||
providers::twitch::TwitchChannel *twitchChannel =
|
||||
dynamic_cast<providers::twitch::TwitchChannel *>(this->channel_.get());
|
||||
|
||||
if (twitchChannel) {
|
||||
lineMod->setVisible(twitchChannel->hasModRights());
|
||||
timeout->setVisible(twitchChannel->hasModRights());
|
||||
}
|
||||
});
|
||||
|
||||
timeout->buttonClicked.connect([this](auto item) {
|
||||
TimeoutWidget::Action action;
|
||||
int arg;
|
||||
std::tie(action, arg) = item;
|
||||
|
||||
switch (action) {
|
||||
case TimeoutWidget::Ban: {
|
||||
if (this->channel_) {
|
||||
this->channel_->sendMessage("/ban " + this->userName_);
|
||||
}
|
||||
} break;
|
||||
case TimeoutWidget::Unban: {
|
||||
if (this->channel_) {
|
||||
this->channel_->sendMessage("/unban " + this->userName_);
|
||||
}
|
||||
} break;
|
||||
case TimeoutWidget::Timeout: {
|
||||
if (this->channel_) {
|
||||
this->channel_->sendMessage("/timeout " + this->userName_ + " " +
|
||||
QString::number(arg));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this->setStyleSheet("font-size: 11pt;");
|
||||
|
||||
this->installEvents();
|
||||
}
|
||||
|
||||
void UserInfoPopup::themeRefreshEvent()
|
||||
{
|
||||
BaseWindow::themeRefreshEvent();
|
||||
|
||||
this->setStyleSheet("background: #333");
|
||||
}
|
||||
|
||||
void UserInfoPopup::installEvents()
|
||||
{
|
||||
std::weak_ptr<bool> hack = this->hack_;
|
||||
|
||||
// follow
|
||||
QObject::connect(this->ui_.follow, &QCheckBox::stateChanged, [this](int) mutable {
|
||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||
|
||||
QUrl requestUrl("https://api.twitch.tv/kraken/users/" + currentUser->getUserId() +
|
||||
"/follows/channels/" + this->userId_);
|
||||
|
||||
this->ui_.follow->setEnabled(false);
|
||||
if (this->ui_.follow->isChecked()) {
|
||||
util::twitch::put(requestUrl,
|
||||
[this](QJsonObject) { this->ui_.follow->setEnabled(true); });
|
||||
} else {
|
||||
util::twitch::sendDelete(requestUrl, [this] { this->ui_.follow->setEnabled(true); });
|
||||
}
|
||||
});
|
||||
|
||||
std::shared_ptr<bool> ignoreNext = std::make_shared<bool>(false);
|
||||
|
||||
// ignore
|
||||
QObject::connect(
|
||||
this->ui_.ignore, &QCheckBox::stateChanged, [this, ignoreNext, hack](int) mutable {
|
||||
if (*ignoreNext) {
|
||||
*ignoreNext = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this->ui_.ignore->setEnabled(false);
|
||||
|
||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||
if (this->ui_.ignore->isChecked()) {
|
||||
currentUser->ignoreByID(this->userId_, this->userName_,
|
||||
[=](auto result, const auto &message) mutable {
|
||||
if (hack.lock()) {
|
||||
if (result == IgnoreResult_Failed) {
|
||||
*ignoreNext = true;
|
||||
this->ui_.ignore->setChecked(false);
|
||||
}
|
||||
this->ui_.ignore->setEnabled(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
currentUser->unignoreByID(this->userId_, this->userName_,
|
||||
[=](auto result, const auto &message) mutable {
|
||||
if (hack.lock()) {
|
||||
if (result == UnignoreResult_Failed) {
|
||||
*ignoreNext = true;
|
||||
this->ui_.ignore->setChecked(true);
|
||||
}
|
||||
this->ui_.ignore->setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void UserInfoPopup::setData(const QString &name, const ChannelPtr &channel)
|
||||
{
|
||||
this->userName_ = name;
|
||||
this->channel_ = channel;
|
||||
|
||||
this->ui_.nameLabel->setText(name);
|
||||
|
||||
this->updateUserData();
|
||||
|
||||
this->userStateChanged.invoke();
|
||||
}
|
||||
|
||||
void UserInfoPopup::updateUserData()
|
||||
{
|
||||
std::weak_ptr<bool> hack = this->hack_;
|
||||
|
||||
// get user info
|
||||
util::twitch::getUserID(this->userName_, this, [this, hack](QString id) {
|
||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||
|
||||
this->userId_ = id;
|
||||
|
||||
// get channel info
|
||||
util::twitch::get(
|
||||
"https://api.twitch.tv/kraken/channels/" + id, this, [this](const QJsonObject &obj) {
|
||||
this->ui_.followerCountLabel->setText(
|
||||
TEXT_FOLLOWERS + QString::number(obj.value("followers").toInt()));
|
||||
this->ui_.viewCountLabel->setText(TEXT_VIEWS +
|
||||
QString::number(obj.value("views").toInt()));
|
||||
this->ui_.createdDateLabel->setText(
|
||||
TEXT_CREATED + obj.value("created_at").toString().section("T", 0, 0));
|
||||
|
||||
this->loadAvatar(QUrl(obj.value("logo").toString()));
|
||||
});
|
||||
|
||||
// get follow state
|
||||
currentUser->checkFollow(id, [this, hack](auto result) {
|
||||
if (hack.lock()) {
|
||||
if (result != FollowResult_Failed) {
|
||||
this->ui_.follow->setEnabled(true);
|
||||
this->ui_.follow->setChecked(result == FollowResult_Following);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// get ignore state
|
||||
bool isIgnoring = false;
|
||||
for (const auto &ignoredUser : currentUser->getIgnores()) {
|
||||
if (id == ignoredUser.id) {
|
||||
isIgnoring = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->ui_.ignore->setEnabled(true);
|
||||
this->ui_.ignore->setChecked(isIgnoring);
|
||||
});
|
||||
|
||||
this->ui_.follow->setEnabled(false);
|
||||
this->ui_.ignore->setEnabled(false);
|
||||
this->ui_.ignoreHighlights->setEnabled(false);
|
||||
}
|
||||
|
||||
void UserInfoPopup::loadAvatar(const QUrl &url)
|
||||
{
|
||||
QNetworkRequest req(url);
|
||||
static auto manager = new QNetworkAccessManager();
|
||||
auto *reply = manager->get(req);
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, [=] {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const auto data = reply->readAll();
|
||||
|
||||
// might want to cache the avatar image
|
||||
QPixmap avatar;
|
||||
avatar.loadFromData(data);
|
||||
this->ui_.avatarButton->setPixmap(avatar);
|
||||
} else {
|
||||
this->ui_.avatarButton->setPixmap(QPixmap());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// TimeoutWidget
|
||||
//
|
||||
UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
||||
: BaseWidget(nullptr)
|
||||
{
|
||||
auto layout =
|
||||
util::LayoutCreator<TimeoutWidget>(this).setLayoutType<QHBoxLayout>().withoutMargin();
|
||||
|
||||
QColor color1(255, 255, 255, 80);
|
||||
QColor color2(255, 255, 255, 0);
|
||||
|
||||
int buttonWidth = 24;
|
||||
int buttonWidth2 = 32;
|
||||
int buttonHeight = 32;
|
||||
|
||||
layout->setSpacing(16);
|
||||
|
||||
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<RippleEffectButton>(nullptr);
|
||||
button->setPixmap(pixmap);
|
||||
button->setScaleIndependantSize(buttonHeight, buttonHeight);
|
||||
button->setBorderColor(QColor(255, 255, 255, 127));
|
||||
|
||||
QObject::connect(button.getElement(), &RippleEffectButton::clicked, [this, action] {
|
||||
this->buttonClicked.invoke(std::make_pair(action, -1));
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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<RippleEffectLabel2>();
|
||||
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(), &RippleEffectLabel2::clicked, [
|
||||
this, timeout = std::get<1>(item)
|
||||
] { this->buttonClicked.invoke(std::make_pair(Action::Timeout, timeout)); });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addButton(Unban, "unban", getApp()->resources->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", getApp()->resources->buttons.ban);
|
||||
}
|
||||
|
||||
void UserInfoPopup::TimeoutWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
// QPainter painter(this);
|
||||
|
||||
// painter.setPen(QColor(255, 255, 255, 63));
|
||||
|
||||
// painter.drawLine(0, this->height() / 2, this->width(), this->height() / 2);
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class Label;
|
||||
|
||||
class UserInfoPopup final : public BaseWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserInfoPopup();
|
||||
|
||||
void setData(const QString &name, const ChannelPtr &channel);
|
||||
|
||||
protected:
|
||||
virtual void themeRefreshEvent() override;
|
||||
|
||||
private:
|
||||
bool isMod_;
|
||||
bool isBroadcaster_;
|
||||
|
||||
QString userName_;
|
||||
QString userId_;
|
||||
ChannelPtr channel_;
|
||||
|
||||
pajlada::Signals::NoArgSignal userStateChanged;
|
||||
|
||||
void installEvents();
|
||||
|
||||
void updateUserData();
|
||||
void loadAvatar(const QUrl &url);
|
||||
|
||||
std::shared_ptr<bool> hack_;
|
||||
|
||||
struct {
|
||||
RippleEffectButton *avatarButton = nullptr;
|
||||
|
||||
Label *nameLabel = nullptr;
|
||||
Label *viewCountLabel = nullptr;
|
||||
Label *followerCountLabel = nullptr;
|
||||
Label *createdDateLabel = nullptr;
|
||||
|
||||
QCheckBox *follow = nullptr;
|
||||
QCheckBox *ignore = nullptr;
|
||||
QCheckBox *ignoreHighlights = nullptr;
|
||||
} ui_;
|
||||
|
||||
class TimeoutWidget : public BaseWidget
|
||||
{
|
||||
public:
|
||||
enum Action { Ban, Unban, Timeout };
|
||||
|
||||
TimeoutWidget();
|
||||
|
||||
pajlada::Signals::Signal<std::pair<Action, int>> buttonClicked;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "WelcomeDialog.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
WelcomeDialog::WelcomeDialog()
|
||||
: BaseWindow(nullptr, BaseWindow::EnableCustomFrame)
|
||||
{
|
||||
this->setWindowTitle("Chatterino quick setup");
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class WelcomeDialog : public BaseWindow
|
||||
{
|
||||
public:
|
||||
WelcomeDialog();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace chatterino
|
||||
Reference in New Issue
Block a user