diff --git a/db/Database.cpp b/db/Database.cpp index 85152d0..eb05f31 100644 --- a/db/Database.cpp +++ b/db/Database.cpp @@ -136,12 +136,11 @@ namespace NekoGui { if (latency < 0) { return Qt::red; } else if (latency > 0) { - if (latency < 100) { + auto greenMs = dataStore->test_latency_url.startsWith("https://") ? 200 : 100; + if (latency < greenMs) { return Qt::darkGreen; - } else if (latency < 200) { - return Qt::darkYellow; } else { - return Qt::red; + return Qt::darkYellow; } } else { return {}; diff --git a/fmt/CustomBean.hpp b/fmt/CustomBean.hpp index c30f763..16efd99 100644 --- a/fmt/CustomBean.hpp +++ b/fmt/CustomBean.hpp @@ -31,7 +31,7 @@ namespace NekoGui_fmt { return core; }; - QString DisplayCoreType() override { return NeedExternal(false) ? core : software_core_name; }; + QString DisplayCoreType() override { return NeedExternal(true) == 0 ? software_core_name : core; }; QString DisplayAddress() override { if (core == "internal") { diff --git a/fmt/HysteriaBean.hpp b/fmt/HysteriaBean.hpp index 1a8b49f..9695894 100644 --- a/fmt/HysteriaBean.hpp +++ b/fmt/HysteriaBean.hpp @@ -63,7 +63,7 @@ namespace NekoGui_fmt { return ::DisplayAddress(serverAddress, serverPort); } - QString DisplayCoreType() override { return NeedExternal(false) == 0 ? software_core_name : "Hysteria"; }; + QString DisplayCoreType() override { return NeedExternal(true) == 0 ? software_core_name : "Hysteria"; }; QString DisplayType() override { return "Hysteria"; }; diff --git a/go/cmd/updater/launcher.go b/go/cmd/updater/launcher.go new file mode 100644 index 0000000..ed9b0e0 --- /dev/null +++ b/go/cmd/updater/launcher.go @@ -0,0 +1,12 @@ +//go:build !linux + +package main + +import ( + "log" + "runtime" +) + +func Launcher() { + log.Fatalln("launcher is not for your platform", runtime.GOOS) +} diff --git a/go/cmd/updater/launcher_darwin.go b/go/cmd/updater/launcher_darwin.go deleted file mode 100644 index 201e3e6..0000000 --- a/go/cmd/updater/launcher_darwin.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func Launcher() { - println("?") -} diff --git a/go/cmd/updater/launcher_windows.go b/go/cmd/updater/launcher_windows.go deleted file mode 100644 index ec63e6b..0000000 --- a/go/cmd/updater/launcher_windows.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "log" - "runtime" -) - -func Launcher() { - log.Fatalf("launcher is not for your platform", runtime.GOOS) -} diff --git a/go/cmd/updater/msgbox.go b/go/cmd/updater/msgbox.go new file mode 100644 index 0000000..f94ba8f --- /dev/null +++ b/go/cmd/updater/msgbox.go @@ -0,0 +1,7 @@ +//go:build !windows + +package main + +func MessageBoxPlain(title, caption string) int { + return 0 +} diff --git a/go/cmd/updater/msgbox_windows.go b/go/cmd/updater/msgbox_windows.go new file mode 100644 index 0000000..216f489 --- /dev/null +++ b/go/cmd/updater/msgbox_windows.go @@ -0,0 +1,26 @@ +package main + +import ( + "syscall" + "unsafe" +) + +// MessageBoxPlain of Win32 API. +func MessageBoxPlain(title, caption string) int { + const ( + NULL = 0 + MB_OK = 0 + ) + return MessageBox(NULL, caption, title, MB_OK) +} + +// MessageBox of Win32 API. +func MessageBox(hwnd uintptr, caption, title string, flags uint) int { + ret, _, _ := syscall.NewLazyDLL("user32.dll").NewProc("MessageBoxW").Call( + uintptr(hwnd), + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))), + uintptr(flags)) + + return int(ret) +} diff --git a/go/cmd/updater/updater.go b/go/cmd/updater/updater.go index 170c58a..5db0b63 100644 --- a/go/cmd/updater/updater.go +++ b/go/cmd/updater/updater.go @@ -64,6 +64,7 @@ func Updater() { // update move err := Mv("./nekoray_update/nekoray", "./") if err != nil { + MessageBoxPlain("NekoGui Updater", "Update failed. Please close the running instance and run the updater again.\n\n"+err.Error()) log.Fatalln(err.Error()) } diff --git a/main/NekoGui_Utils.cpp b/main/NekoGui_Utils.cpp index 1226bf6..a81ef23 100644 --- a/main/NekoGui_Utils.cpp +++ b/main/NekoGui_Utils.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -194,9 +195,12 @@ QString DisplayTime(long long time, int formatType) { } QWidget *GetMessageBoxParent() { - if (mainwindow == nullptr) return nullptr; - if (mainwindow->isVisible()) return mainwindow; - return nullptr; + auto activeWindow = QApplication::activeWindow(); + if (activeWindow == nullptr && mainwindow != nullptr) { + if (mainwindow->isVisible()) return mainwindow; + return nullptr; + } + return activeWindow; } int MessageBoxWarning(const QString &title, const QString &text) { diff --git a/translations/fa_IR.ts b/translations/fa_IR.ts index be49b42..4c304c1 100644 --- a/translations/fa_IR.ts +++ b/translations/fa_IR.ts @@ -769,6 +769,10 @@ This needs to be run NekoBox with administrator privileges. Select Profile انتخاب کردن پروفایل + + Name cannot be empty. + + EditCustom @@ -816,6 +820,10 @@ This needs to be run NekoBox with administrator privileges. Please fill the complete config. + + Name cannot be empty. + + EditHysteria @@ -1360,10 +1368,6 @@ This needs to be run NekoBox with administrator privileges. Remove %1 item(s) ? - - Reset traffic of %1 item(s) ? - - Copied %1 item(s) diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index 16efe96..bf7a0a2 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -767,6 +767,10 @@ This needs to be run NekoBox with administrator privileges. Traffic order is from top to bottom 流量顺序是从上到下(最后一个配置为流量的出口) + + Name cannot be empty. + 名称 不能为空 + EditCustom @@ -814,6 +818,10 @@ This needs to be run NekoBox with administrator privileges. Please fill the complete config. 请填写完整配置。 + + Name cannot be empty. + 名称 不能为空 + EditHysteria @@ -1169,10 +1177,6 @@ This needs to be run NekoBox with administrator privileges. Remove %1 item(s) ? 删除 %1 个项目? - - Reset traffic of %1 item(s) ? - 重置 %1 个项目的流量? - Config copied 配置已复制 diff --git a/ui/dialog_basic_settings.ui b/ui/dialog_basic_settings.ui index 22d83cd..fa4beca 100644 --- a/ui/dialog_basic_settings.ui +++ b/ui/dialog_basic_settings.ui @@ -522,113 +522,88 @@ - - - - - Asset Location - - - - - - - Default: dir of "nekoray" - - - - - - - Select - - - - - - - - - - - Switch core - - - - - - - V2Ray - - - - - - - sing-box - - - - - - - - - - - - - 0 - 0 - - - - - - - Loglevel - + + + + + + Asset Location + + + + + + + + + Default: dir of "nekoray" + + + + + + + Select + + + + + + + + + Loglevel + + + + + + + + 0 + 0 + + + + + + + + Multiplex (mux) + + + + + + + + + + + + concurrency + + + + + + + + + + Default On + + + + + + - - - - - - - - - - 0 - 0 - - - - - + - Multiplex (mux) - - - - - - - - - - concurrency - - - - - - - - - - Default On + Core Options @@ -636,10 +611,52 @@ - - - Core Options + + + Switch core + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + V2Ray + + + + + + + sing-box + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -662,8 +679,8 @@ 0 0 - 568 - 297 + 198 + 58 diff --git a/ui/edit/dialog_edit_profile.cpp b/ui/edit/dialog_edit_profile.cpp index 75817d4..1363266 100644 --- a/ui/edit/dialog_edit_profile.cpp +++ b/ui/edit/dialog_edit_profile.cpp @@ -333,16 +333,16 @@ void DialogEditProfile::typeSelected(const QString &newType) { } bool DialogEditProfile::onEnd() { - // 左边 - ent->bean->name = ui->name->text(); - ent->bean->serverAddress = ui->address->text(); - ent->bean->serverPort = ui->port->text().toInt(); - // bean if (!innerEditor->onEnd()) { return false; } + // 左边 + ent->bean->name = ui->name->text(); + ent->bean->serverAddress = ui->address->text(); + ent->bean->serverPort = ui->port->text().toInt(); + // 右边 stream auto stream = GetStreamSettings(ent->bean.get()); if (stream != nullptr) { diff --git a/ui/edit/edit_chain.cpp b/ui/edit/edit_chain.cpp index cbdec3f..a84d365 100644 --- a/ui/edit/edit_chain.cpp +++ b/ui/edit/edit_chain.cpp @@ -25,6 +25,11 @@ void EditChain::onStart(std::shared_ptr _ent) { } bool EditChain::onEnd() { + if (get_edit_text_name().isEmpty()) { + MessageBoxWarning(software_name, tr("Name cannot be empty.")); + return false; + } + auto bean = this->ent->ChainBean(); QList idList; diff --git a/ui/edit/edit_custom.cpp b/ui/edit/edit_custom.cpp index 1d75ad4..d8a669d 100644 --- a/ui/edit/edit_custom.cpp +++ b/ui/edit/edit_custom.cpp @@ -129,15 +129,19 @@ void EditCustom::onStart(std::shared_ptr _ent) { } bool EditCustom::onEnd() { - auto bean = this->ent->CustomBean(); - - SAVE_CUSTOM_BEAN - - if (bean->core.isEmpty()) { + if (get_edit_text_name().isEmpty()) { + MessageBoxWarning(software_name, tr("Name cannot be empty.")); + return false; + } + if (ui->core->currentText().isEmpty()) { MessageBoxWarning(software_name, tr("Please pick a core.")); return false; } + auto bean = this->ent->CustomBean(); + + SAVE_CUSTOM_BEAN + return true; } diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 5664988..56ca2e3 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -529,13 +529,19 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info) refresh_status(); } if (info.contains("UpdateDataStore")) { - auto changed = NekoGui::dataStore->Save(); - if (info.contains("RouteChanged")) changed = true; + auto suggestRestartProxy = NekoGui::dataStore->Save(); + if (info.contains("RouteChanged")) { + suggestRestartProxy = true; + } + if (info.contains("NeedRestart")) { + suggestRestartProxy = false; + } refresh_proxy_list(); if (info.contains("VPNChanged") && NekoGui::dataStore->spmode_vpn) { MessageBoxWarning(tr("VPN settings changed"), tr("Restart VPN to take effect.")); - } else if (changed && NekoGui::dataStore->started_id >= 0 && - QMessageBox::question(GetMessageBoxParent(), tr("Confirmation"), tr("Settings changed, restart proxy?")) == QMessageBox::StandardButton::Yes) { + } + if (suggestRestartProxy && NekoGui::dataStore->started_id >= 0 && + QMessageBox::question(GetMessageBoxParent(), tr("Confirmation"), tr("Settings changed, restart proxy?")) == QMessageBox::StandardButton::Yes) { neko_start(NekoGui::dataStore->started_id); } refresh_status(); @@ -1141,12 +1147,10 @@ void MainWindow::on_menu_delete_triggered() { void MainWindow::on_menu_reset_traffic_triggered() { auto ents = get_now_selected(); if (ents.count() == 0) return; - if (QMessageBox::question(this, tr("Confirmation"), QString(tr("Reset traffic of %1 item(s) ?")).arg(ents.count())) == QMessageBox::StandardButton::Yes) { - for (const auto &ent: ents) { - ent->traffic_data->Reset(); - ent->Save(); - refresh_proxy_list(ent->id); - } + for (const auto &ent: ents) { + ent->traffic_data->Reset(); + ent->Save(); + refresh_proxy_list(ent->id); } } @@ -1193,10 +1197,10 @@ void MainWindow::on_menu_export_config_triggered() { auto ents = get_now_selected(); if (ents.count() != 1) return; auto ent = ents.first(); - QString config_core; + if (ent->bean->DisplayCoreType() != software_core_name) return; auto result = BuildConfig(ent, false, true); - config_core = QJsonObject2QString(result->coreConfig, true); + QString config_core = QJsonObject2QString(result->coreConfig, true); QApplication::clipboard()->setText(config_core); QMessageBox msg(QMessageBox::Information, tr("Config copied"), config_core); diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 317f89a..43947a9 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -684,6 +684,9 @@ Export %1 config + + Ctrl+E +