feat: multiplex default & apply to group

This commit is contained in:
arm64v8a
2023-05-14 16:37:20 +09:00
parent 79b49d6cc8
commit 7c74480b06
15 changed files with 463 additions and 152 deletions

View File

@@ -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") {

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)

View File

@@ -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,72 +570,112 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="core_settings">
<property name="text">
<string>Core Options</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="extra_core_box">
<property name="title">
<string>Extra Core</string>
<widget class="QGroupBox" name="groupBox_mux">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<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>
<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>
<item>
<widget class="QPushButton" name="extra_core_add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="extra_core_del">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="core_settings">
<property name="text">
<string>Core Options</string>
</property>
</widget>
</item>
</layout>
</widget>
<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>
<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_8">
<item>
<widget class="QPushButton" name="extra_core_add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="extra_core_del">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_5">
@@ -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>

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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); });
//

View File

@@ -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
View 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();
};
};