mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-17 12:34:37 +03:00
feat: multiplex default & apply to group
This commit is contained in:
@@ -620,6 +620,11 @@ namespace NekoRay {
|
||||
needMux = false;
|
||||
}
|
||||
}
|
||||
if (stream->multiplex_status == 0) {
|
||||
if (!dataStore->mux_default_on) needMux = false;
|
||||
} else if (stream->multiplex_status == 2) {
|
||||
needMux = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->type == "shadowsocks") {
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace NekoRay::fmt {
|
||||
// reality
|
||||
QString reality_pbk = "";
|
||||
QString reality_sid = "";
|
||||
// multiplex
|
||||
int multiplex_status = 0;
|
||||
|
||||
V2rayStreamSettings() : JsonStore() {
|
||||
_add(new configItem("net", &network, itemType::string));
|
||||
@@ -42,6 +44,7 @@ namespace NekoRay::fmt {
|
||||
_add(new configItem("utls", &utlsFingerprint, itemType::string));
|
||||
_add(new configItem("pbk", &reality_pbk, itemType::string));
|
||||
_add(new configItem("sid", &reality_sid, itemType::string));
|
||||
_add(new configItem("mux_s", &multiplex_status, itemType::integer));
|
||||
}
|
||||
|
||||
QJsonObject BuildStreamSettingsV2Ray();
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace NekoRay {
|
||||
_add(new configItem("log_level", &log_level, itemType::string));
|
||||
_add(new configItem("mux_protocol", &mux_protocol, itemType::string));
|
||||
_add(new configItem("mux_concurrency", &mux_concurrency, itemType::integer));
|
||||
_add(new configItem("mux_default_on", &mux_default_on, itemType::boolean));
|
||||
_add(new configItem("traffic_loop_interval", &traffic_loop_interval, itemType::integer));
|
||||
_add(new configItem("test_concurrent", &test_concurrent, itemType::integer));
|
||||
_add(new configItem("theme", &theme, itemType::string));
|
||||
@@ -201,6 +202,13 @@ namespace NekoRay {
|
||||
_map.insert(item->name, QSharedPointer<configItem>(item));
|
||||
}
|
||||
|
||||
QString JsonStore::_name(void *p) {
|
||||
for (const auto &_item: _map) {
|
||||
if (_item->ptr == p) return _item->name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QSharedPointer<configItem> JsonStore::_get(const QString &name) {
|
||||
// 直接 [] 会设置一个 nullptr ,所以先判断是否存在
|
||||
if (_map.contains(name)) {
|
||||
@@ -209,6 +217,31 @@ namespace NekoRay {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void JsonStore::_setValue(const QString &name, void *p) {
|
||||
auto item = _get(name);
|
||||
if (item == nullptr) return;
|
||||
|
||||
switch (item->type) {
|
||||
case NekoRay::itemType::string:
|
||||
*(QString *) item->ptr = *(QString *) p;
|
||||
break;
|
||||
case NekoRay::itemType::boolean:
|
||||
*(bool *) item->ptr = *(bool *) p;
|
||||
break;
|
||||
case NekoRay::itemType::integer:
|
||||
*(int *) item->ptr = *(int *) p;
|
||||
break;
|
||||
case NekoRay::itemType::integer64:
|
||||
*(long long *) item->ptr = *(long long *) p;
|
||||
break;
|
||||
// others...
|
||||
case stringList:
|
||||
case integerList:
|
||||
case jsonStore:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject JsonStore::ToJson() {
|
||||
QJsonObject object;
|
||||
for (const auto &_item: _map) {
|
||||
|
||||
@@ -46,8 +46,12 @@ namespace NekoRay {
|
||||
|
||||
void _add(configItem *item);
|
||||
|
||||
QString _name(void *p);
|
||||
|
||||
QSharedPointer<configItem> _get(const QString &name);
|
||||
|
||||
void _setValue(const QString &name, void *p);
|
||||
|
||||
QJsonObject ToJson();
|
||||
|
||||
QByteArray ToJsonBytes();
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace NekoRay {
|
||||
int current_group = 0; // group id
|
||||
QString mux_protocol = "";
|
||||
int mux_concurrency = 8;
|
||||
bool mux_default_on = false;
|
||||
QString theme = "0";
|
||||
QString v2ray_asset_dir = "";
|
||||
int language = 0;
|
||||
|
||||
@@ -235,6 +235,14 @@ For NekoBox, this rewrites the underlying(localhost) DNS in VPN mode, normal mod
|
||||
<source>If you VPN mode is not working, try to change this option.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default On</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Multiplex (mux)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DialogEditGroup</name>
|
||||
@@ -409,6 +417,30 @@ For NekoBox, this rewrites the underlying(localhost) DNS in VPN mode, normal mod
|
||||
<source>Custom Config Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply settings to this group</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Multiplex</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Keep Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation type="unfinished">خاموش</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DialogFirstSetup</name>
|
||||
@@ -1418,6 +1450,10 @@ End: %2</source>
|
||||
<source>Please run NekoBox as admin</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Restart Proxy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ProxyItem</name>
|
||||
|
||||
@@ -235,6 +235,14 @@ For NekoBox, this rewrites the underlying(localhost) DNS in VPN mode, normal mod
|
||||
<source>If you VPN mode is not working, try to change this option.</source>
|
||||
<translation>如果您的VPN模式有问题,请尝试更改此选项。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default On</source>
|
||||
<translation>默认开启</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Multiplex (mux)</source>
|
||||
<translation>多路复用 Mux</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DialogEditGroup</name>
|
||||
@@ -409,6 +417,30 @@ For NekoBox, this rewrites the underlying(localhost) DNS in VPN mode, normal mod
|
||||
<source>Custom Config Settings</source>
|
||||
<translation>自定义配置 JSON 设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Apply settings to this group</source>
|
||||
<translation>将设置应用于该组</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Multiplex</source>
|
||||
<translation>多路复用</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Keep Default</source>
|
||||
<translation>保持默认</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On</source>
|
||||
<translation>开启</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Off</source>
|
||||
<translation>关闭</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation>确认</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DialogFirstSetup</name>
|
||||
@@ -1425,6 +1457,10 @@ Split by line.</source>
|
||||
<source>Please run NekoBox as admin</source>
|
||||
<translation>请以管理员权限运行 NekoBox</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Restart Proxy</source>
|
||||
<translation>重启代理</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ProxyItem</name>
|
||||
|
||||
@@ -60,8 +60,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
|
||||
if (IS_NEKO_BOX) {
|
||||
ui->groupBox_http->hide();
|
||||
ui->inbound_socks_port_l->setText(ui->inbound_socks_port_l->text().replace("Socks", "Mixed"));
|
||||
ui->hlayout_l2->addWidget(ui->groupbox_custom_inbound);
|
||||
ui->inbound_socks_port_l->setText(ui->inbound_socks_port_l->text().replace("Socks", "Mixed (SOCKS+HTTP)"));
|
||||
ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" "));
|
||||
ui->mux_protocol->addItems({"", "h2mux", "smux", "yamux"});
|
||||
} else {
|
||||
@@ -76,8 +75,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
CACHE.custom_inbound = NekoRay::dataStore->custom_inbound;
|
||||
D_LOAD_INT(inbound_socks_port)
|
||||
D_LOAD_INT_ENABLE(inbound_http_port, http_enable)
|
||||
D_LOAD_INT(mux_concurrency)
|
||||
D_LOAD_COMBO_STRING(mux_protocol)
|
||||
D_LOAD_INT(test_concurrent)
|
||||
D_LOAD_STRING(test_url)
|
||||
|
||||
@@ -176,7 +173,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
|
||||
if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", "");
|
||||
//
|
||||
auto extra_core_layout = ui->extra_core_box->layout();
|
||||
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));
|
||||
}
|
||||
@@ -246,6 +243,11 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
connect(ui->switch_core_v2ray, &QRadioButton::clicked, this, switch_core_on_click);
|
||||
connect(ui->switch_core_sing_box, &QRadioButton::clicked, this, switch_core_on_click);
|
||||
|
||||
// Mux
|
||||
D_LOAD_INT(mux_concurrency)
|
||||
D_LOAD_COMBO_STRING(mux_protocol)
|
||||
D_LOAD_BOOL(mux_default_on)
|
||||
|
||||
// Security
|
||||
|
||||
ui->utlsFingerprint->addItems(IS_NEKO_BOX ? Preset::SingBox::UtlsFingerPrint : Preset::V2Ray::UtlsFingerPrint);
|
||||
@@ -267,8 +269,6 @@ void DialogBasicSettings::accept() {
|
||||
NekoRay::dataStore->custom_inbound = CACHE.custom_inbound;
|
||||
D_SAVE_INT(inbound_socks_port)
|
||||
D_SAVE_INT_ENABLE(inbound_http_port, http_enable)
|
||||
D_SAVE_INT(mux_concurrency)
|
||||
D_SAVE_COMBO_STRING(mux_protocol)
|
||||
D_SAVE_INT(test_concurrent)
|
||||
D_SAVE_STRING(test_url)
|
||||
|
||||
@@ -304,6 +304,11 @@ void DialogBasicSettings::accept() {
|
||||
NekoRay::dataStore->v2ray_asset_dir = ui->core_v2ray_asset->text();
|
||||
NekoRay::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true);
|
||||
|
||||
// Mux
|
||||
D_SAVE_INT(mux_concurrency)
|
||||
D_SAVE_COMBO_STRING(mux_protocol)
|
||||
D_SAVE_BOOL(mux_default_on)
|
||||
|
||||
// Security
|
||||
|
||||
D_SAVE_BOOL(skip_cert)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<width>600</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -20,6 +20,16 @@
|
||||
<string>Basic Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="8" column="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
@@ -120,6 +130,26 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlayout_l4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_log">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string notr="true">Loglevel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="log_level"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,8,1,1">
|
||||
@@ -146,52 +176,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="hlayout_l4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_log">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string notr="true">Loglevel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="log_level"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_mux">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_17">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string notr="true">Mux</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="mux_protocol"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>concurrency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="mux_concurrency"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="horizontalGroupBox1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18">
|
||||
@@ -253,8 +237,8 @@
|
||||
<item row="4" column="0">
|
||||
<layout class="QHBoxLayout" name="_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="horizontalGroupBox2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_20">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<layout class="QHBoxLayout" name="_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="set_custom_icon">
|
||||
<property name="sizePolicy">
|
||||
@@ -586,11 +570,48 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<widget class="QGroupBox" name="groupBox_mux">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_17">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Multiplex (mux)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="mux_protocol"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>concurrency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="mux_concurrency"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mux_default_on">
|
||||
<property name="text">
|
||||
<string>Default On</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -601,37 +622,39 @@
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="extra_core_box">
|
||||
<property name="title">
|
||||
<widget class="QWidget" name="tab_6">
|
||||
<attribute name="title">
|
||||
<string>Extra Core</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="extra_core_box_scrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="extra_core_box_scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>568</width>
|
||||
<height>297</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QWidget" name="horizontalWidget_4" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QPushButton" name="extra_core_add">
|
||||
<property name="text">
|
||||
@@ -651,6 +674,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -734,16 +758,6 @@
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
||||
@@ -132,6 +132,8 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
|
||||
connect(ui->type, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) {
|
||||
typeSelected(ui->type->itemData(index).toString());
|
||||
});
|
||||
|
||||
ui->apply_to_group->hide();
|
||||
} else {
|
||||
this->ent = NekoRay::profileManager->GetProfile(profileOrGroupId);
|
||||
if (this->ent == nullptr) return;
|
||||
@@ -226,6 +228,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
||||
ui->ws_early_data_length->setText(Int2String(stream->ws_early_data_length));
|
||||
ui->reality_pbk->setText(stream->reality_pbk);
|
||||
ui->reality_sid->setText(stream->reality_sid);
|
||||
ui->multiplex->setCurrentIndex(stream->multiplex_status);
|
||||
CACHE.certificate = stream->certificate;
|
||||
} else {
|
||||
ui->right_all_w->setVisible(false);
|
||||
@@ -299,6 +302,13 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
||||
ui->security->setVisible(false);
|
||||
ui->security_l->setVisible(false);
|
||||
}
|
||||
if (type == "vmess" || type == "vless" || type == "trojan" || type == "shadowsocks") {
|
||||
ui->multiplex->setVisible(true);
|
||||
ui->multiplex_l->setVisible(true);
|
||||
} else {
|
||||
ui->multiplex->setVisible(false);
|
||||
ui->multiplex_l->setVisible(false);
|
||||
}
|
||||
// 设置 是否可见
|
||||
int streamBoxVisible = 0;
|
||||
for (auto label: ui->stream_box->findChildren<QLabel *>()) {
|
||||
@@ -322,7 +332,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
||||
}
|
||||
}
|
||||
|
||||
void DialogEditProfile::accept() {
|
||||
bool DialogEditProfile::onEnd() {
|
||||
// 左边
|
||||
ent->bean->name = ui->name->text();
|
||||
ent->bean->serverAddress = ui->address->text();
|
||||
@@ -330,7 +340,7 @@ void DialogEditProfile::accept() {
|
||||
|
||||
// bean
|
||||
if (!innerEditor->onEnd()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 右边 stream
|
||||
@@ -348,15 +358,25 @@ void DialogEditProfile::accept() {
|
||||
stream->header_type = ui->header_type->currentText();
|
||||
stream->ws_early_data_name = ui->ws_early_data_name->text();
|
||||
stream->ws_early_data_length = ui->ws_early_data_length->text().toInt();
|
||||
stream->certificate = CACHE.certificate;
|
||||
stream->reality_pbk = ui->reality_pbk->text();
|
||||
stream->reality_sid = ui->reality_sid->text();
|
||||
stream->multiplex_status = ui->multiplex->currentIndex();
|
||||
stream->certificate = CACHE.certificate;
|
||||
}
|
||||
|
||||
// cached custom
|
||||
ent->bean->custom_outbound = CACHE.custom_outbound;
|
||||
ent->bean->custom_config = CACHE.custom_config;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DialogEditProfile::accept() {
|
||||
// save to ent
|
||||
if (!onEnd()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// finish
|
||||
QStringList msg = {"accept"};
|
||||
|
||||
@@ -421,3 +441,87 @@ void DialogEditProfile::on_certificate_edit_clicked() {
|
||||
editor_cache_updated_impl();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogEditProfile::on_apply_to_group_clicked() {
|
||||
if (apply_to_group_ui.empty()) {
|
||||
apply_to_group_ui[ui->multiplex] = new FloatCheckBox(ui->multiplex, this);
|
||||
apply_to_group_ui[ui->sni] = new FloatCheckBox(ui->sni, this);
|
||||
apply_to_group_ui[ui->alpn] = new FloatCheckBox(ui->alpn, this);
|
||||
apply_to_group_ui[ui->host] = new FloatCheckBox(ui->host, this);
|
||||
apply_to_group_ui[ui->path] = new FloatCheckBox(ui->path, this);
|
||||
apply_to_group_ui[ui->utlsFingerprint] = new FloatCheckBox(ui->utlsFingerprint, this);
|
||||
apply_to_group_ui[ui->insecure] = new FloatCheckBox(ui->insecure, this);
|
||||
apply_to_group_ui[ui->certificate_edit] = new FloatCheckBox(ui->certificate_edit, this);
|
||||
apply_to_group_ui[ui->custom_config_edit] = new FloatCheckBox(ui->custom_config_edit, this);
|
||||
apply_to_group_ui[ui->custom_outbound_edit] = new FloatCheckBox(ui->custom_outbound_edit, this);
|
||||
ui->apply_to_group->setText(tr("Confirm"));
|
||||
} else {
|
||||
auto group = NekoRay::profileManager->GetGroup(ent->gid);
|
||||
if (group == nullptr) {
|
||||
MessageBoxWarning("failed", "unknown group");
|
||||
return;
|
||||
}
|
||||
// save this
|
||||
if (onEnd()) {
|
||||
ent->Save();
|
||||
} else {
|
||||
MessageBoxWarning("failed", "failed to save");
|
||||
return;
|
||||
}
|
||||
// copy keys
|
||||
for (const auto &pair: apply_to_group_ui) {
|
||||
if (pair.second->isChecked()) {
|
||||
do_apply_to_group(group, pair.first);
|
||||
}
|
||||
delete pair.second;
|
||||
}
|
||||
apply_to_group_ui.clear();
|
||||
ui->apply_to_group->setText(tr("Apply settings to this group"));
|
||||
}
|
||||
}
|
||||
|
||||
void DialogEditProfile::do_apply_to_group(const QSharedPointer<NekoRay::Group> &group, QWidget *key) {
|
||||
auto stream = GetStreamSettings(ent->bean.data());
|
||||
|
||||
auto copyStream = [=](void *p) {
|
||||
for (const auto &profile: group->Profiles()) {
|
||||
auto newStream = GetStreamSettings(profile->bean.data());
|
||||
if (newStream == nullptr) continue;
|
||||
if (stream == newStream) continue;
|
||||
newStream->_setValue(stream->_name(p), p);
|
||||
// qDebug() << newStream->ToJsonBytes();
|
||||
profile->Save();
|
||||
}
|
||||
};
|
||||
|
||||
auto copyBean = [=](void *p) {
|
||||
for (const auto &profile: group->Profiles()) {
|
||||
if (profile == ent) continue;
|
||||
profile->bean->_setValue(ent->bean->_name(p), p);
|
||||
// qDebug() << profile->bean->ToJsonBytes();
|
||||
profile->Save();
|
||||
}
|
||||
};
|
||||
|
||||
if (key == ui->multiplex) {
|
||||
copyStream(&stream->multiplex_status);
|
||||
} else if (key == ui->sni) {
|
||||
copyStream(&stream->sni);
|
||||
} else if (key == ui->alpn) {
|
||||
copyStream(&stream->alpn);
|
||||
} else if (key == ui->host) {
|
||||
copyStream(&stream->host);
|
||||
} else if (key == ui->path) {
|
||||
copyStream(&stream->path);
|
||||
} else if (key == ui->utlsFingerprint) {
|
||||
copyStream(&stream->utlsFingerprint);
|
||||
} else if (key == ui->insecure) {
|
||||
copyStream(&stream->allow_insecure);
|
||||
} else if (key == ui->certificate_edit) {
|
||||
copyStream(&stream->certificate);
|
||||
} else if (key == ui->custom_config_edit) {
|
||||
copyBean(&ent->bean->custom_config);
|
||||
} else if (key == ui->custom_outbound_edit) {
|
||||
copyBean(&ent->bean->custom_outbound);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "db/Database.hpp"
|
||||
#include "profile_editor.h"
|
||||
|
||||
#include "ui/widget/FloatCheckBox.h"
|
||||
|
||||
namespace Ui {
|
||||
class DialogEditProfile;
|
||||
}
|
||||
@@ -29,8 +31,13 @@ private slots:
|
||||
|
||||
void on_certificate_edit_clicked();
|
||||
|
||||
void on_apply_to_group_clicked();
|
||||
|
||||
private:
|
||||
Ui::DialogEditProfile *ui;
|
||||
|
||||
std::map<QWidget *, FloatCheckBox *> apply_to_group_ui;
|
||||
|
||||
QWidget *innerWidget{};
|
||||
ProfileEditor *innerEditor{};
|
||||
|
||||
@@ -49,7 +56,11 @@ private:
|
||||
|
||||
void typeSelected(const QString &newType);
|
||||
|
||||
bool onEnd();
|
||||
|
||||
void editor_cache_updated_impl();
|
||||
|
||||
void do_apply_to_group(const QSharedPointer<NekoRay::Group> &group, QWidget *key);
|
||||
};
|
||||
|
||||
#endif // DIALOG_EDIT_PROFILE_H
|
||||
|
||||
@@ -157,6 +157,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="apply_to_group">
|
||||
<property name="text">
|
||||
<string>Apply settings to this group</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
@@ -211,30 +218,6 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="_2">
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="security">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">tls</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="network_l">
|
||||
<property name="toolTip">
|
||||
<string>The underlying transport method. It must be consistent with the server, otherwise, the connection cannot be established.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="network">
|
||||
<property name="sizePolicy">
|
||||
@@ -275,6 +258,49 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="packet_encoding">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">packet</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">xudp</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="network_l">
|
||||
<property name="toolTip">
|
||||
<string>The underlying transport method. It must be consistent with the server, otherwise, the connection cannot be established.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="security">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">tls</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="security_l">
|
||||
<property name="toolTip">
|
||||
@@ -295,21 +321,28 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="packet_encoding">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="multiplex_l">
|
||||
<property name="text">
|
||||
<string>Multiplex</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="multiplex">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
<string>Keep Default</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">packet</string>
|
||||
<string>On</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">xudp</string>
|
||||
<string>Off</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@@ -588,9 +621,11 @@ security (QUIC)</string>
|
||||
<tabstop>port</tabstop>
|
||||
<tabstop>custom_outbound_edit</tabstop>
|
||||
<tabstop>custom_config_edit</tabstop>
|
||||
<tabstop>apply_to_group</tabstop>
|
||||
<tabstop>network</tabstop>
|
||||
<tabstop>security</tabstop>
|
||||
<tabstop>packet_encoding</tabstop>
|
||||
<tabstop>multiplex</tabstop>
|
||||
<tabstop>header_type</tabstop>
|
||||
<tabstop>path</tabstop>
|
||||
<tabstop>host</tabstop>
|
||||
|
||||
@@ -197,6 +197,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
ui->tableWidget_conn->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
ui->tableWidget_conn->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
||||
ui->tableWidget_conn->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
|
||||
ui->proxyListTable->verticalHeader()->setDefaultSectionSize(24);
|
||||
|
||||
// search box
|
||||
ui->search->setVisible(false);
|
||||
@@ -258,6 +259,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
connect(ui->menu_open_config_folder, &QAction::triggered, this, [=] { QDesktopServices::openUrl(QUrl::fromLocalFile(QDir::currentPath())); });
|
||||
ui->menu_program_preference->addActions(ui->menu_preferences->actions());
|
||||
connect(ui->menu_add_from_clipboard2, &QAction::triggered, ui->menu_add_from_clipboard, &QAction::trigger);
|
||||
connect(ui->actionRestart_Proxy, &QAction::triggered, this, [=] { if (NekoRay::dataStore->started_id>=0) neko_start(NekoRay::dataStore->started_id); });
|
||||
connect(ui->actionRestart_Program, &QAction::triggered, this, [=] { MW_dialog_message("", "RestartProgram"); });
|
||||
connect(ui->actionShow_window, &QAction::triggered, this, [=] { tray->activated(QSystemTrayIcon::ActivationReason::Trigger); });
|
||||
//
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderDefaultSectionSize">
|
||||
<number>26</number>
|
||||
<number>30</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
@@ -496,6 +496,7 @@
|
||||
<addaction name="menu_spmode"/>
|
||||
<addaction name="menu_program_preference"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionRestart_Proxy"/>
|
||||
<addaction name="actionRestart_Program"/>
|
||||
<addaction name="menu_exit"/>
|
||||
</widget>
|
||||
@@ -885,6 +886,11 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRestart_Proxy">
|
||||
<property name="text">
|
||||
<string>Restart Proxy</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
16
ui/widget/FloatCheckBox.h
Normal file
16
ui/widget/FloatCheckBox.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
class FloatCheckBox : public QCheckBox {
|
||||
public:
|
||||
explicit FloatCheckBox(QWidget *parent, QWidget *window) : QCheckBox(window) {
|
||||
setFixedSize(24, 24);
|
||||
auto pos = parent->rect().topRight();
|
||||
pos = parent->mapTo(window, pos);
|
||||
pos.setX(pos.x() - 48); // ?
|
||||
move(pos);
|
||||
raise();
|
||||
if (parent->isVisible()) show();
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user