mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 20:44:38 +03:00
417 lines
15 KiB
C++
417 lines
15 KiB
C++
#include "dialog_basic_settings.h"
|
|
#include "ui_dialog_basic_settings.h"
|
|
|
|
#include "3rdparty/qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
|
|
#include "fmt/Preset.hpp"
|
|
#include "ui/ThemeManager.hpp"
|
|
#include "ui/Icon.hpp"
|
|
#include "main/GuiUtils.hpp"
|
|
#include "main/NekoGui.hpp"
|
|
|
|
#include <QStyleFactory>
|
|
#include <QFileDialog>
|
|
#include <QInputDialog>
|
|
#include <QMessageBox>
|
|
#include <QTimer>
|
|
|
|
class ExtraCoreWidget : public QWidget {
|
|
public:
|
|
QString coreName;
|
|
|
|
QLabel *label_name;
|
|
MyLineEdit *lineEdit_path;
|
|
QPushButton *pushButton_pick;
|
|
|
|
explicit ExtraCoreWidget(QJsonObject *extraCore, const QString &coreName_,
|
|
QWidget *parent = nullptr)
|
|
: QWidget(parent) {
|
|
coreName = coreName_;
|
|
label_name = new QLabel;
|
|
label_name->setText(coreName);
|
|
lineEdit_path = new MyLineEdit;
|
|
lineEdit_path->setText(extraCore->value(coreName).toString());
|
|
pushButton_pick = new QPushButton;
|
|
pushButton_pick->setText(QObject::tr("Select"));
|
|
auto layout = new QHBoxLayout;
|
|
layout->addWidget(label_name);
|
|
layout->addWidget(lineEdit_path);
|
|
layout->addWidget(pushButton_pick);
|
|
setLayout(layout);
|
|
setContentsMargins(0, 0, 0, 0);
|
|
//
|
|
connect(pushButton_pick, &QPushButton::clicked, this, [=] {
|
|
auto fn = QFileDialog::getOpenFileName(this, QObject::tr("Select"), QDir::currentPath(),
|
|
"", nullptr, QFileDialog::Option::ReadOnly);
|
|
if (!fn.isEmpty()) {
|
|
lineEdit_path->setText(fn);
|
|
}
|
|
});
|
|
connect(lineEdit_path, &QLineEdit::textChanged, this, [=](const QString &newTxt) {
|
|
extraCore->insert(coreName, newTxt);
|
|
});
|
|
}
|
|
};
|
|
|
|
DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
|
: QDialog(parent), ui(new Ui::DialogBasicSettings) {
|
|
ui->setupUi(this);
|
|
ADD_ASTERISK(this);
|
|
|
|
// Common
|
|
|
|
ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" "));
|
|
ui->mux_protocol->addItems({"h2mux", "smux", "yamux"});
|
|
|
|
refresh_auth();
|
|
|
|
D_LOAD_STRING(inbound_address)
|
|
D_LOAD_COMBO_STRING(log_level)
|
|
CACHE.custom_inbound = NekoGui::dataStore->custom_inbound;
|
|
D_LOAD_INT(inbound_socks_port)
|
|
D_LOAD_INT(test_concurrent)
|
|
D_LOAD_INT(test_download_timeout)
|
|
D_LOAD_STRING(test_latency_url)
|
|
D_LOAD_STRING(test_download_url)
|
|
D_LOAD_BOOL(old_share_link_format)
|
|
|
|
connect(ui->custom_inbound_edit, &QPushButton::clicked, this, [=] {
|
|
C_EDIT_JSON_ALLOW_EMPTY(custom_inbound)
|
|
});
|
|
|
|
#ifdef Q_OS_WIN
|
|
connect(ui->sys_proxy_format, &QPushButton::clicked, this, [=] {
|
|
bool ok;
|
|
auto str = QInputDialog::getItem(this, ui->sys_proxy_format->text() + " (Windows)",
|
|
tr("Advanced system proxy settings. Please select a format."),
|
|
Preset::Windows::system_proxy_format,
|
|
Preset::Windows::system_proxy_format.indexOf(NekoGui::dataStore->system_proxy_format),
|
|
false, &ok);
|
|
if (ok) NekoGui::dataStore->system_proxy_format = str;
|
|
});
|
|
#else
|
|
ui->sys_proxy_format->hide();
|
|
#endif
|
|
|
|
// Style
|
|
ui->connection_statistics_box->setDisabled(true);
|
|
//
|
|
D_LOAD_BOOL(check_include_pre)
|
|
D_LOAD_BOOL(connection_statistics)
|
|
D_LOAD_BOOL(start_minimal)
|
|
D_LOAD_INT(max_log_line)
|
|
//
|
|
if (NekoGui::dataStore->traffic_loop_interval == 500) {
|
|
ui->rfsh_r->setCurrentIndex(0);
|
|
} else if (NekoGui::dataStore->traffic_loop_interval == 1000) {
|
|
ui->rfsh_r->setCurrentIndex(1);
|
|
} else if (NekoGui::dataStore->traffic_loop_interval == 2000) {
|
|
ui->rfsh_r->setCurrentIndex(2);
|
|
} else if (NekoGui::dataStore->traffic_loop_interval == 3000) {
|
|
ui->rfsh_r->setCurrentIndex(3);
|
|
} else if (NekoGui::dataStore->traffic_loop_interval == 5000) {
|
|
ui->rfsh_r->setCurrentIndex(4);
|
|
} else {
|
|
ui->rfsh_r->setCurrentIndex(5);
|
|
}
|
|
//
|
|
ui->language->setCurrentIndex(NekoGui::dataStore->language);
|
|
connect(ui->language, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
|
CACHE.needRestart = true;
|
|
});
|
|
//
|
|
int built_in_len = ui->theme->count();
|
|
ui->theme->addItems(QStyleFactory::keys());
|
|
//
|
|
bool ok;
|
|
auto themeId = NekoGui::dataStore->theme.toInt(&ok);
|
|
if (ok) {
|
|
ui->theme->setCurrentIndex(themeId);
|
|
} else {
|
|
ui->theme->setCurrentText(NekoGui::dataStore->theme);
|
|
}
|
|
//
|
|
connect(ui->theme, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
|
if (index + 1 <= built_in_len) {
|
|
themeManager->ApplyTheme(Int2String(index));
|
|
NekoGui::dataStore->theme = Int2String(index);
|
|
} else {
|
|
themeManager->ApplyTheme(ui->theme->currentText());
|
|
NekoGui::dataStore->theme = ui->theme->currentText();
|
|
}
|
|
repaint();
|
|
mainwindow->repaint();
|
|
NekoGui::dataStore->Save();
|
|
});
|
|
|
|
// Subscription
|
|
|
|
ui->user_agent->setText(NekoGui::dataStore->user_agent);
|
|
ui->user_agent->setPlaceholderText(NekoGui::dataStore->GetUserAgent(true));
|
|
D_LOAD_BOOL(sub_use_proxy)
|
|
D_LOAD_BOOL(sub_clear)
|
|
D_LOAD_BOOL(sub_insecure)
|
|
D_LOAD_INT_ENABLE(sub_auto_update, sub_auto_update_enable)
|
|
|
|
// Core
|
|
|
|
ui->groupBox_core->setTitle(software_core_name);
|
|
//
|
|
CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
|
|
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
|
|
if (!CACHE.extraCore.contains("hysteria2")) CACHE.extraCore.insert("hysteria2", "");
|
|
if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", "");
|
|
//
|
|
auto extra_core_layout = ui->extra_core_box_scrollAreaWidgetContents->layout();
|
|
for (const auto &s: CACHE.extraCore.keys()) {
|
|
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
|
|
}
|
|
//
|
|
connect(ui->extra_core_add, &QPushButton::clicked, this, [=] {
|
|
bool ok;
|
|
auto s = QInputDialog::getText(nullptr, tr("Add"),
|
|
tr("Please input the core name."),
|
|
QLineEdit::Normal, "", &ok)
|
|
.trimmed();
|
|
if (s.isEmpty() || !ok) return;
|
|
if (CACHE.extraCore.contains(s)) return;
|
|
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
|
|
CACHE.extraCore.insert(s, "");
|
|
});
|
|
connect(ui->extra_core_del, &QPushButton::clicked, this, [=] {
|
|
bool ok;
|
|
auto s = QInputDialog::getItem(nullptr, tr("Delete"),
|
|
tr("Please select the core name."),
|
|
CACHE.extraCore.keys(), 0, false, &ok);
|
|
if (s.isEmpty() || !ok) return;
|
|
for (int i = 0; i < extra_core_layout->count(); i++) {
|
|
auto item = extra_core_layout->itemAt(i);
|
|
auto ecw = dynamic_cast<ExtraCoreWidget *>(item->widget());
|
|
if (ecw != nullptr && ecw->coreName == s) {
|
|
ecw->deleteLater();
|
|
CACHE.extraCore.remove(s);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Mux
|
|
D_LOAD_INT(mux_concurrency)
|
|
D_LOAD_COMBO_STRING(mux_protocol)
|
|
D_LOAD_BOOL(mux_padding)
|
|
D_LOAD_BOOL(mux_default_on)
|
|
|
|
// Security
|
|
|
|
ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
|
|
|
|
D_LOAD_BOOL(skip_cert)
|
|
ui->utlsFingerprint->setCurrentText(NekoGui::dataStore->utlsFingerprint);
|
|
}
|
|
|
|
DialogBasicSettings::~DialogBasicSettings() {
|
|
delete ui;
|
|
}
|
|
|
|
void DialogBasicSettings::accept() {
|
|
// Common
|
|
|
|
D_SAVE_STRING(inbound_address)
|
|
D_SAVE_COMBO_STRING(log_level)
|
|
NekoGui::dataStore->custom_inbound = CACHE.custom_inbound;
|
|
D_SAVE_INT(inbound_socks_port)
|
|
D_SAVE_INT(test_concurrent)
|
|
D_SAVE_INT(test_download_timeout)
|
|
D_SAVE_STRING(test_latency_url)
|
|
D_SAVE_STRING(test_download_url)
|
|
D_SAVE_BOOL(old_share_link_format)
|
|
|
|
// Style
|
|
|
|
NekoGui::dataStore->language = ui->language->currentIndex();
|
|
D_SAVE_BOOL(connection_statistics)
|
|
D_SAVE_BOOL(check_include_pre)
|
|
D_SAVE_BOOL(start_minimal)
|
|
D_SAVE_INT(max_log_line)
|
|
|
|
if (NekoGui::dataStore->max_log_line <= 0) {
|
|
NekoGui::dataStore->max_log_line = 200;
|
|
}
|
|
|
|
if (ui->rfsh_r->currentIndex() == 0) {
|
|
NekoGui::dataStore->traffic_loop_interval = 500;
|
|
} else if (ui->rfsh_r->currentIndex() == 1) {
|
|
NekoGui::dataStore->traffic_loop_interval = 1000;
|
|
} else if (ui->rfsh_r->currentIndex() == 2) {
|
|
NekoGui::dataStore->traffic_loop_interval = 2000;
|
|
} else if (ui->rfsh_r->currentIndex() == 3) {
|
|
NekoGui::dataStore->traffic_loop_interval = 3000;
|
|
} else if (ui->rfsh_r->currentIndex() == 4) {
|
|
NekoGui::dataStore->traffic_loop_interval = 5000;
|
|
} else {
|
|
NekoGui::dataStore->traffic_loop_interval = 0;
|
|
}
|
|
|
|
// Subscription
|
|
|
|
if (ui->sub_auto_update_enable->isChecked()) {
|
|
TM_auto_update_subsctiption_Reset_Minute(ui->sub_auto_update->text().toInt());
|
|
} else {
|
|
TM_auto_update_subsctiption_Reset_Minute(0);
|
|
}
|
|
|
|
NekoGui::dataStore->user_agent = ui->user_agent->text();
|
|
D_SAVE_BOOL(sub_use_proxy)
|
|
D_SAVE_BOOL(sub_clear)
|
|
D_SAVE_BOOL(sub_insecure)
|
|
D_SAVE_INT_ENABLE(sub_auto_update, sub_auto_update_enable)
|
|
|
|
// Core
|
|
|
|
NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true);
|
|
|
|
// Mux
|
|
D_SAVE_INT(mux_concurrency)
|
|
D_SAVE_COMBO_STRING(mux_protocol)
|
|
D_SAVE_BOOL(mux_padding)
|
|
D_SAVE_BOOL(mux_default_on)
|
|
|
|
// Security
|
|
|
|
D_SAVE_BOOL(skip_cert)
|
|
NekoGui::dataStore->utlsFingerprint = ui->utlsFingerprint->currentText();
|
|
|
|
// 关闭连接统计,停止刷新前清空记录。
|
|
if (NekoGui::dataStore->traffic_loop_interval == 0 || !NekoGui::dataStore->connection_statistics) {
|
|
MW_dialog_message("", "ClearConnectionList");
|
|
}
|
|
|
|
QStringList str{"UpdateDataStore"};
|
|
if (CACHE.needRestart) str << "NeedRestart";
|
|
MW_dialog_message(Dialog_DialogBasicSettings, str.join(","));
|
|
QDialog::accept();
|
|
}
|
|
|
|
// slots
|
|
|
|
void DialogBasicSettings::refresh_auth() {
|
|
ui->inbound_auth->setText({});
|
|
if (NekoGui::dataStore->inbound_auth->NeedAuth()) {
|
|
ui->inbound_auth->setIcon(Icon::GetMaterialIcon("lock-outline"));
|
|
} else {
|
|
ui->inbound_auth->setIcon(Icon::GetMaterialIcon("lock-open-outline"));
|
|
}
|
|
}
|
|
|
|
void DialogBasicSettings::on_set_custom_icon_clicked() {
|
|
auto title = ui->set_custom_icon->text();
|
|
QString user_icon_path = "./" + software_name.toLower() + ".png";
|
|
auto c = QMessageBox::question(this, title, tr("Please select a PNG file."),
|
|
tr("Select"), tr("Reset"), tr("Cancel"), 2, 2);
|
|
if (c == 0) {
|
|
auto fn = QFileDialog::getOpenFileName(this, QObject::tr("Select"), QDir::currentPath(),
|
|
"*.png", nullptr, QFileDialog::Option::ReadOnly);
|
|
QImage img(fn);
|
|
if (img.isNull() || img.height() != img.width()) {
|
|
MessageBoxWarning(title, tr("Please select a valid square image."));
|
|
return;
|
|
}
|
|
QFile::remove(user_icon_path);
|
|
QFile::copy(fn, user_icon_path);
|
|
} else if (c == 1) {
|
|
QFile::remove(user_icon_path);
|
|
} else {
|
|
return;
|
|
}
|
|
MW_dialog_message(Dialog_DialogBasicSettings, "UpdateIcon");
|
|
}
|
|
|
|
void DialogBasicSettings::on_inbound_auth_clicked() {
|
|
auto w = new QDialog(this);
|
|
w->setWindowTitle(tr("Inbound Auth"));
|
|
auto layout = new QGridLayout;
|
|
w->setLayout(layout);
|
|
//
|
|
auto user_l = new QLabel(tr("Username"));
|
|
auto pass_l = new QLabel(tr("Password"));
|
|
auto user = new MyLineEdit;
|
|
auto pass = new MyLineEdit;
|
|
user->setText(NekoGui::dataStore->inbound_auth->username);
|
|
pass->setText(NekoGui::dataStore->inbound_auth->password);
|
|
//
|
|
layout->addWidget(user_l, 0, 0);
|
|
layout->addWidget(user, 0, 1);
|
|
layout->addWidget(pass_l, 1, 0);
|
|
layout->addWidget(pass, 1, 1);
|
|
auto box = new QDialogButtonBox;
|
|
box->setOrientation(Qt::Horizontal);
|
|
box->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
|
connect(box, &QDialogButtonBox::accepted, w, [=] {
|
|
NekoGui::dataStore->inbound_auth->username = user->text();
|
|
NekoGui::dataStore->inbound_auth->password = pass->text();
|
|
MW_dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore");
|
|
w->accept();
|
|
});
|
|
connect(box, &QDialogButtonBox::rejected, w, &QDialog::reject);
|
|
layout->addWidget(box, 2, 1);
|
|
//
|
|
w->exec();
|
|
w->deleteLater();
|
|
refresh_auth();
|
|
}
|
|
|
|
void DialogBasicSettings::on_core_settings_clicked() {
|
|
auto w = new QDialog(this);
|
|
w->setWindowTitle(software_core_name + " Core Options");
|
|
auto layout = new QGridLayout;
|
|
w->setLayout(layout);
|
|
//
|
|
auto line = -1;
|
|
QCheckBox *core_box_enable_clash_api;
|
|
MyLineEdit *core_box_clash_api;
|
|
MyLineEdit *core_box_clash_api_secret;
|
|
MyLineEdit *core_box_underlying_dns;
|
|
//
|
|
auto core_box_underlying_dns_l = new QLabel(tr("Override underlying DNS"));
|
|
core_box_underlying_dns = new MyLineEdit;
|
|
core_box_underlying_dns->setText(NekoGui::dataStore->core_box_underlying_dns);
|
|
core_box_underlying_dns->setMinimumWidth(300);
|
|
layout->addWidget(core_box_underlying_dns_l, ++line, 0);
|
|
layout->addWidget(core_box_underlying_dns, line, 1);
|
|
//
|
|
auto core_box_enable_clash_api_l = new QLabel("Enable Clash API");
|
|
core_box_enable_clash_api = new QCheckBox;
|
|
core_box_enable_clash_api->setChecked(NekoGui::dataStore->core_box_clash_api > 0);
|
|
layout->addWidget(core_box_enable_clash_api_l, ++line, 0);
|
|
layout->addWidget(core_box_enable_clash_api, line, 1);
|
|
//
|
|
auto core_box_clash_api_l = new QLabel("Clash API Listen Port");
|
|
core_box_clash_api = new MyLineEdit;
|
|
core_box_clash_api->setText(Int2String(std::abs(NekoGui::dataStore->core_box_clash_api)));
|
|
layout->addWidget(core_box_clash_api_l, ++line, 0);
|
|
layout->addWidget(core_box_clash_api, line, 1);
|
|
//
|
|
auto core_box_clash_api_secret_l = new QLabel("Clash API Secret");
|
|
core_box_clash_api_secret = new MyLineEdit;
|
|
core_box_clash_api_secret->setText(NekoGui::dataStore->core_box_clash_api_secret);
|
|
layout->addWidget(core_box_clash_api_secret_l, ++line, 0);
|
|
layout->addWidget(core_box_clash_api_secret, line, 1);
|
|
//
|
|
auto box = new QDialogButtonBox;
|
|
box->setOrientation(Qt::Horizontal);
|
|
box->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
|
connect(box, &QDialogButtonBox::accepted, w, [=] {
|
|
NekoGui::dataStore->core_box_underlying_dns = core_box_underlying_dns->text();
|
|
NekoGui::dataStore->core_box_clash_api = core_box_clash_api->text().toInt() * (core_box_enable_clash_api->isChecked() ? 1 : -1);
|
|
NekoGui::dataStore->core_box_clash_api_secret = core_box_clash_api_secret->text();
|
|
MW_dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore");
|
|
w->accept();
|
|
});
|
|
connect(box, &QDialogButtonBox::rejected, w, &QDialog::reject);
|
|
layout->addWidget(box, ++line, 1);
|
|
//
|
|
ADD_ASTERISK(w)
|
|
w->exec();
|
|
w->deleteLater();
|
|
refresh_auth();
|
|
}
|