diff --git a/.gitignore b/.gitignore index cb6d3bd5..82708c26 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .vs/ *.qm ./.vscode +CMakeSettings.json SourceTrail/ diff --git a/README.md b/README.md index f5f7b4fe..d2d30bac 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,22 @@ # Qv2ray - Make v2ray real cross-platform -[![archlinuxcn](https://img.shields.io/badge/archlinuxcn-available-success?style=flat-square)](https://build.archlinuxcn.org/packages/#/qv2ray) -[![flathub](https://img.shields.io/badge/flathub-available-success?style=flat-square)](https://flathub.org/apps/details/com.github.Qv2ray) [![HitCount](http://hits.dwyl.io/Qv2ray/Qv2ray.svg)](http://hits.dwyl.io/Qv2ray/Qv2ray) -![GitHub Releases](https://img.shields.io/github/downloads/Qv2ray/Qv2ray/latest/total?style=flat-square&logo=github) -![GitHub All Releases](https://img.shields.io/github/downloads/Qv2ray/Qv2ray/total?label=downloads-total&logo=github&style=flat-square) +[![GitHub Releases](https://img.shields.io/github/downloads/Qv2ray/Qv2ray/latest/total?style=flat-square&logo=github)](https://github.com/Qv2ray/Qv2ray/releases) +[![GitHub All Releases](https://img.shields.io/github/downloads/Qv2ray/Qv2ray/total?label=downloads-total&logo=github&style=flat-square)](https://github.com/Qv2ray/Qv2ray/releases) + +[![flathub](https://img.shields.io/badge/flathub-available-success?style=flat-square)](https://flathub.org/apps/details/com.github.Qv2ray) +[![Snap](https://snapcraft.io/qv2ray/badge.svg)](https://snapcraft.io/qv2ray/) + [![AUR Stable](https://img.shields.io/aur/version/qv2ray?label=aur-stable&style=flat-square)](https://aur.archlinux.org/packages/qv2ray) +[![AUR Development](https://img.shields.io/aur/version/qv2ray-dev-git?label=aur-development&style=flat-square)](https://aur.archlinux.org/packages/qv2ray-dev-git) +[![ArchlinuxCN Stable](https://img.shields.io/badge/dynamic/json?label=archlinuxcn-stable&query=%24.latest.pkgver&url=https%3A%2F%2Fbuild.archlinuxcn.org%2Fapi%2Fpackages%2Fqv2ray)](https://build.archlinuxcn.org/packages/#/qv2ray) +[![ArchlinuxCN Development](https://img.shields.io/badge/dynamic/json?label=archlinuxcn-dev-git&query=%24.latest.pkgver&url=https%3A%2F%2Fbuild.archlinuxcn.org%2Fapi%2Fpackages%2Fqv2ray-dev-git)](https://build.archlinuxcn.org/packages/#/qv2ray-dev-git) + +[![Qv2ray AUR Build](https://github.com/Qv2ray/Qv2ray/workflows/Build%20Qv2ray%20AUR/badge.svg)](https://github.com/Qv2ray/Qv2ray/actions?query=workflow%3A%22Build+Qv2ray+AUR%22) +[![Qv2ray Debian Package](https://github.com/Qv2ray/Qv2ray/workflows/Qv2ray%20build%20debian%20package/badge.svg)](https://github.com/Qv2ray/Qv2ray/actions?query=workflow%3A%22Qv2ray+build+debian+package%22) +[![Qv2ray Build Matrix](https://github.com/Qv2ray/Qv2ray/workflows/Qv2ray%20build%20matrix%20-%20cmake/badge.svg)](https://github.com/Qv2ray/Qv2ray/actions?query=workflow%3A%22Qv2ray+build+matrix+-+cmake%22) + +Snap Build Status: [![Snap Status](https://travis-ci.com/Qv2ray/Qv2ray.svg?branch=master)](https://travis-ci.com/Qv2ray/Qv2ray) 使用 Qt 框架的跨平台 v2ray 客户端。支持 Windows, Linux, macOS。 diff --git a/debian/changelog b/debian/changelog index cd2d2245..aa414708 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,17 @@ +qv2ray (2.3.1-1) unstable; urgency=medium + + * fixed file loading if a source file was not in UTF-8 + + -- Guobang Bi Sat, 21 Mar 2020 08:50:17 +0800 + +qv2ray (2.3.0-1) unstable; urgency=medium + + * misc ui tweaks + * fully support setting the block,proxy,direct geosite/plain domains + * fixed vmess:// 'h2' import issue + + -- Guobang Bi Fri, 20 Mar 2020 22:26:20 +0800 + qv2ray (2.2.3-1) unstable; urgency=medium * Initial release diff --git a/makespec/BUILDVERSION b/makespec/BUILDVERSION index b072e3cf..2b3bcc61 100644 --- a/makespec/BUILDVERSION +++ b/makespec/BUILDVERSION @@ -1 +1 @@ -4752 \ No newline at end of file +5052 diff --git a/makespec/VERSION b/makespec/VERSION index 58594069..2bf1c1cc 100644 --- a/makespec/VERSION +++ b/makespec/VERSION @@ -1 +1 @@ -2.2.3 +2.3.1 diff --git a/src/base/models/QvStartupConfig.hpp b/src/base/models/QvStartupConfig.hpp index 4003dfb1..258a1631 100644 --- a/src/base/models/QvStartupConfig.hpp +++ b/src/base/models/QvStartupConfig.hpp @@ -14,10 +14,8 @@ namespace Qv2ray bool debugLog; /// Enable Network toolbar plugin. bool enableToolbarPlguin; - /// Endable HiDPI support. - bool hiDPI; - /// Force endable HiDPI support. - bool forceHiDPI; + /// Disable Qt scale factors support. + bool noScaleFactors; }; } // namespace base inline base::QvStartupOptions StartupOption = base::QvStartupOptions(); diff --git a/src/common/CommandArgs.cpp b/src/common/CommandArgs.cpp index 64fa8d1a..2a2c8077 100644 --- a/src/common/CommandArgs.cpp +++ b/src/common/CommandArgs.cpp @@ -8,8 +8,7 @@ namespace Qv2ray::common : QObject(), noAPIOption("noAPI", tr("Disable gRPC API subsystems.")), // runAsRootOption("I-just-wanna-run-with-root", tr("Explicitly run Qv2ray as root.")), // debugOption("debug", tr("Enable Debug Output")), // - hiDpiOption("hiDPI", tr("Enable HiDPI support for Qt")), // - forceHiDpiOption("force-hiDPI", tr("Force enable HiDPI support for Qt")), // + noScaleFactorOption("noScaleFactor", tr("Disable manually set QT_SCALE_FACTOR")), // withToolbarOption("withToolbarPlugin", tr("Enable Qv2ray network toolbar plugin")), // // helpOption("FAKE"), versionOption("FAKE") @@ -20,8 +19,7 @@ namespace Qv2ray::common parser.addOption(noAPIOption); parser.addOption(runAsRootOption); parser.addOption(debugOption); - parser.addOption(hiDpiOption); - parser.addOption(forceHiDpiOption); + parser.addOption(noScaleFactorOption); parser.addOption(withToolbarOption); helpOption = parser.addHelpOption(); versionOption = parser.addVersionOption(); @@ -59,16 +57,10 @@ namespace Qv2ray::common StartupOption.debugLog = true; } - if (parser.isSet(hiDpiOption)) + if (parser.isSet(noScaleFactorOption)) { - DEBUG(MODULE_INIT, "hiDPI is set.") - StartupOption.hiDPI = true; - } - - if (parser.isSet(forceHiDpiOption)) - { - DEBUG(MODULE_INIT, "forceHiDPI is set.") - StartupOption.forceHiDPI = true; + DEBUG(MODULE_INIT, "noScaleFactorOption is set.") + StartupOption.noScaleFactors = true; } if (parser.isSet(withToolbarOption)) diff --git a/src/common/CommandArgs.hpp b/src/common/CommandArgs.hpp index f2f2c21b..61483122 100644 --- a/src/common/CommandArgs.hpp +++ b/src/common/CommandArgs.hpp @@ -27,8 +27,7 @@ namespace Qv2ray::common QCommandLineOption noAPIOption; QCommandLineOption runAsRootOption; QCommandLineOption debugOption; - QCommandLineOption hiDpiOption; - QCommandLineOption forceHiDpiOption; + QCommandLineOption noScaleFactorOption; QCommandLineOption withToolbarOption; QCommandLineOption helpOption; QCommandLineOption versionOption; diff --git a/src/common/QvHelpers.cpp b/src/common/QvHelpers.cpp index b1d16922..e2791a5e 100644 --- a/src/common/QvHelpers.cpp +++ b/src/common/QvHelpers.cpp @@ -29,25 +29,25 @@ namespace Qv2ray::common QString StringFromFile(const QString &filePath) { QFile f(filePath); - return StringFromFile(&f); + return StringFromFile(f); } - QString StringFromFile(QFile *source) + QString StringFromFile(QFile &source) { - bool wasOpened = source->isOpen(); + bool wasOpened = source.isOpen(); if (!wasOpened) - source->open(QFile::ReadOnly); - auto byteArray = source->readAll(); + source.open(QFile::ReadOnly); + auto byteArray = source.readAll(); if (!wasOpened) - source->close(); + source.close(); // QTextCodec::ConverterState state; QTextCodec *codec = QTextCodec::codecForName("UTF-8"); const QString text = codec->toUnicode(byteArray.constData(), byteArray.size(), &state); if (state.invalidChars > 0) { - LOG(MODULE_FILEIO, "Not a valid UTF-8 sequence: " + source->fileName()) - return source->readAll(); + LOG(MODULE_FILEIO, "Not a valid UTF-8 sequence: " + source.fileName()) + return byteArray; } else { @@ -74,12 +74,6 @@ namespace Qv2ray::common return override; } - QJsonObject JSONFromFile(QFile *sourceFile) - { - QString json = StringFromFile(sourceFile); - return JsonFromString(json); - } - QString JsonToString(const QJsonObject &json, QJsonDocument::JsonFormat format) { QJsonDocument doc; @@ -239,10 +233,14 @@ namespace Qv2ray::common QGraphicsBlurEffect pBlur; // view.setScene(&scene); + view.resize(pixmap.size() / QWidget().devicePixelRatio()); + view.setSceneRect(pixmap.rect()); scene.setSceneRect(pixmap.rect()); pBlur.setBlurRadius(rad); QGraphicsPixmapItem *p = view.scene()->addPixmap(pixmap); p->setGraphicsEffect(&pBlur); + view.setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view.setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); return view.grab(); } @@ -255,9 +253,13 @@ namespace Qv2ray::common pColor.setStrength(factor); // view.setScene(&scene); + view.resize(pixmap.size() / QWidget().devicePixelRatio()); + view.setSceneRect(pixmap.rect()); scene.setSceneRect(pixmap.rect()); QGraphicsPixmapItem *p = view.scene()->addPixmap(pixmap); p->setGraphicsEffect(&pColor); + view.setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view.setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); return view.grab(); } } // namespace Qv2ray::common diff --git a/src/common/QvHelpers.hpp b/src/common/QvHelpers.hpp index 0f015f6e..d0111d05 100644 --- a/src/common/QvHelpers.hpp +++ b/src/common/QvHelpers.hpp @@ -26,7 +26,7 @@ namespace Qv2ray::common QMessageBox::StandardButton extraButtons = QMessageBox::NoButton); // QString StringFromFile(const QString &filePath); - QString StringFromFile(QFile *source); + QString StringFromFile(QFile &source); bool StringToFile(const QString &text, QFile &target); bool StringToFile(const QString &text, const QString &targetpath); // @@ -50,7 +50,7 @@ namespace Qv2ray::common } // template - QString StructToJsonString(const TYPE t) + QString StructToJsonString(const TYPE &t) { return QString::fromStdString(x2struct::X::tojson(t, "", 4, ' ')); } @@ -100,12 +100,9 @@ namespace Qv2ray::common inline QString timeToString(const time_t &t) { - auto _tm = std::localtime(&t); - char MY_TIME[128]; - setlocale(1, "3"); - // using strftime to display time - strftime(MY_TIME, sizeof(MY_TIME), "%x - %I:%M%p", _tm); - return QString(MY_TIME); + QDateTime timestamp; + timestamp.setSecsSinceEpoch(t); + return timestamp.toString(Qt::SystemLocaleShortDate); } inline void FastAppendTextDocument(const QString &message, QTextDocument *doc) diff --git a/src/core/connection/ConnectionIO.cpp b/src/core/connection/ConnectionIO.cpp index b666b488..879784bd 100644 --- a/src/core/connection/ConnectionIO.cpp +++ b/src/core/connection/ConnectionIO.cpp @@ -6,7 +6,7 @@ namespace Qv2ray::core::connection { namespace ConnectionIO { - CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex) + CONFIGROOT ConvertConfigFromFile(const QString &sourceFilePath, bool importComplex) { QFile source(sourceFilePath); @@ -15,7 +15,7 @@ namespace Qv2ray::core::connection LOG(MODULE_FILEIO, "Trying to import from an non-existing file.") return CONFIGROOT(); } - auto root = CONFIGROOT(JsonFromString(StringFromFile(&source))); + auto root = CONFIGROOT(JsonFromString(StringFromFile(source))); if (!importComplex) { diff --git a/src/core/connection/ConnectionIO.hpp b/src/core/connection/ConnectionIO.hpp index c6114159..0bb01a4f 100644 --- a/src/core/connection/ConnectionIO.hpp +++ b/src/core/connection/ConnectionIO.hpp @@ -1,12 +1,12 @@ +#pragma once #include "base/Qv2rayBase.hpp" #include "core/CoreSafeTypes.hpp" - namespace Qv2ray::core::connection { namespace ConnectionIO { // File Protocol - CONFIGROOT ConvertConfigFromFile(QString sourceFilePath, bool importComplex); + CONFIGROOT ConvertConfigFromFile(const QString &sourceFilePath, bool importComplex); } // namespace ConnectionIO } // namespace Qv2ray::core::connection diff --git a/src/core/connection/Generation.hpp b/src/core/connection/Generation.hpp index e2a15c99..add99c11 100644 --- a/src/core/connection/Generation.hpp +++ b/src/core/connection/Generation.hpp @@ -1,3 +1,4 @@ +#pragma once #include "base/Qv2rayBase.hpp" namespace Qv2ray::core::connection diff --git a/src/core/connection/Serialization.hpp b/src/core/connection/Serialization.hpp index d9fa6620..25a44a30 100644 --- a/src/core/connection/Serialization.hpp +++ b/src/core/connection/Serialization.hpp @@ -1,3 +1,4 @@ +#pragma once #include "base/Qv2rayBase.hpp" #include "core/CoreSafeTypes.hpp" diff --git a/src/core/settings/SettingsBackend.cpp b/src/core/settings/SettingsBackend.cpp index f1a255ff..f03431cb 100644 --- a/src/core/settings/SettingsBackend.cpp +++ b/src/core/settings/SettingsBackend.cpp @@ -86,7 +86,7 @@ namespace Qv2ray::core::config // // Verify JSON file format. (only) because this file version may // not be upgraded and may contain unsupported structure. - auto err = VerifyJsonString(StringFromFile(&configFile)); + auto err = VerifyJsonString(StringFromFile(configFile)); if (!err.isEmpty()) { @@ -96,7 +96,7 @@ namespace Qv2ray::core::config else { // If the file format is valid. - auto conf = JsonFromString(StringFromFile(&configFile)); + auto conf = JsonFromString(StringFromFile(configFile)); LOG(MODULE_SETTINGS, "Path: " + path + " contains a config file, in version " + conf["config_version"].toVariant().toString()) configFile.close(); diff --git a/src/core/settings/SettingsBackend.hpp b/src/core/settings/SettingsBackend.hpp index 1e54ffb4..cfcc20b1 100644 --- a/src/core/settings/SettingsBackend.hpp +++ b/src/core/settings/SettingsBackend.hpp @@ -1,3 +1,4 @@ +#pragma once #include "base/Qv2rayBase.hpp" namespace Qv2ray::core::config diff --git a/src/main.cpp b/src/main.cpp index b9841747..9c3c76fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ void signalHandler(int signum) { cout << "Qv2ray: Interrupt signal (" << signum << ") received." << endl; + ExitQv2ray(); qApp->exit(-99); } @@ -227,17 +228,16 @@ int main(int argc, char *argv[]) SingleApplication::setApplicationName("qv2ray_debug"); SingleApplication::setApplicationDisplayName("Qv2ray - " + QObject::tr("Debug version")); #endif - if ((!qEnvironmentVariableIsSet("QT_DEVICE_PIXEL_RATIO") && // - !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR") && // - !qEnvironmentVariableIsSet("QT_SCALE_FACTOR") && // - !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) || // - StartupOption.forceHiDPI) + if (StartupOption.noScaleFactors) { - if (StartupOption.forceHiDPI || StartupOption.hiDPI) - { - DEBUG(MODULE_INIT, "High DPI scaling is enabled.") - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - } + LOG(MODULE_INIT, "Force set QT_SCALE_FACTOR to 0.") + LOG(MODULE_UI, "Original QT_SCALE_FACTOR was: " + qEnvironmentVariable("QT_SCALE_FACTOR")) + qputenv("QT_SCALE_FACTOR", "1"); + } + else + { + LOG(MODULE_INIT, "High DPI scaling is enabled.") + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); } SingleApplication _qApp(argc, argv, false, SingleApplication::User | SingleApplication::ExcludeAppPath | SingleApplication::ExcludeAppVersion); @@ -251,42 +251,36 @@ int main(int argc, char *argv[]) bool _result_ = Qv2rayTranslator->InstallTranslation(_lang); LOG(MODULE_UI, "Installing a tranlator from OS: " + _lang + " -- " + (_result_ ? "OK" : "Failed")) // - LOG("LICENCE", NEWLINE - "This program comes with ABSOLUTELY NO WARRANTY." NEWLINE "This is free software, and you are welcome to redistribute it" NEWLINE - "under certain conditions." NEWLINE NEWLINE "Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE NEWLINE NEWLINE - "Libraries that have been used in Qv2ray are listed below (Sorted by date added):" NEWLINE - "Copyright (c) 2020 dridk (@dridk): X2Struct (Apache)" NEWLINE "Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE - "Copyright (c) 2020 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)" NEWLINE - "Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)" NEWLINE - "Copyright (c) 2016 Nikhil Marathe (@nikhilm): QHttpServer (MIT)" NEWLINE - "Copyright (c) 2020 Itay Grudev (@itay-grudev): SingleApplication (MIT)" NEWLINE - "Copyright (c) 2020 paceholder (@paceholder): nodeeditor (QNodeEditor modified by lhy0403) (BSD-3-Clause)" NEWLINE - "Copyright (c) 2019 TheWanderingCoel (@TheWanderingCoel): ShadowClash (launchatlogin) (GPLv3)" NEWLINE - "Copyright (c) 2020 Ram Pani (@DuckSoft): QvRPCBridge (WTFPL)" NEWLINE - "Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)" NEWLINE - "Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE NEWLINE) + LOG("LICENCE", NEWLINE // + "This program comes with ABSOLUTELY NO WARRANTY." NEWLINE // + "This is free software, and you are welcome to redistribute it" NEWLINE // + "under certain conditions." NEWLINE // + NEWLINE // + "Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE // + NEWLINE // + "Libraries that have been used in Qv2ray are listed below (Sorted by date added):" NEWLINE // + "Copyright (c) 2020 dridk (@dridk): X2Struct (Apache)" NEWLINE // + "Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE // + "Copyright (c) 2020 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)" NEWLINE // + "Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)" NEWLINE // + "Copyright (c) 2016 Nikhil Marathe (@nikhilm): QHttpServer (MIT)" NEWLINE // + "Copyright (c) 2020 Itay Grudev (@itay-grudev): SingleApplication (MIT)" NEWLINE // + "Copyright (c) 2020 paceholder (@paceholder): nodeeditor (QNodeEditor modified by lhy0403) (BSD-3-Clause)" NEWLINE // + "Copyright (c) 2019 TheWanderingCoel (@TheWanderingCoel): ShadowClash (launchatlogin) (GPLv3)" NEWLINE // + "Copyright (c) 2020 Ram Pani (@DuckSoft): QvRPCBridge (WTFPL)" NEWLINE // + "Copyright (c) 2019 ShadowSocks (@shadowsocks): libQtShadowsocks (LGPLv3)" NEWLINE // + "Copyright (c) 2015-2020 qBittorrent (Anton Lashkov) (@qBittorrent): speedplotview (GPLv2)" NEWLINE NEWLINE) // // LOG(MODULE_INIT, "Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay())) // #ifdef QT_DEBUG - cout << "WARNING: ============================== This is a debug build, many features are not stable enough. ==============================" - << endl; + cout << "WARNING: ========================= This is a debug build, many features are not stable enough. =========================" << endl; #endif // - // Load the language translation list. - // auto translationDir = Qv - - // auto translationDir = QvTranslator::deduceTranslationDir(); - // if (!translationDir) - // { - // LOG(MODULE_INIT, "FAILED to find any translations. THIS IS A BUILD ERROR.") - // QvMessageBoxWarn(nullptr, QObject::tr("Cannot load languages"), - // QObject::tr("Qv2ray will continue running, but you cannot change the UI language.")); - // } - // Qv2ray Initialize, find possible config paths and verify them. if (!initialiseQv2ray()) { + LOG(MODULE_INIT, "Failed to initialise Qv2ray, exiting.") return -1; } @@ -324,7 +318,7 @@ int main(int argc, char *argv[]) if (Qv2rayTranslator->InstallTranslation(confObject.uiConfig.language)) { - LOG(MODULE_INIT, "Successfully installed a translator for " + confObject.uiConfig.language); + LOG(MODULE_INIT, "Successfully installed a translator for " + confObject.uiConfig.language) } else { diff --git a/src/ui/w_ImportConfig.cpp b/src/ui/w_ImportConfig.cpp index efcc1ce4..a71396a4 100644 --- a/src/ui/w_ImportConfig.cpp +++ b/src/ui/w_ImportConfig.cpp @@ -254,7 +254,7 @@ void ImportConfigWindow::on_cancelImportBtn_clicked() void ImportConfigWindow::on_subscriptionButton_clicked() { hide(); - SubscribeEditor w; + SubscriptionEditor w; w.exec(); auto importToComplex = !keepImportedInboundCheckBox->isEnabled(); connections.clear(); diff --git a/src/ui/w_ImportConfig.ui b/src/ui/w_ImportConfig.ui index 8f3e0da5..9f916307 100644 --- a/src/ui/w_ImportConfig.ui +++ b/src/ui/w_ImportConfig.ui @@ -211,21 +211,35 @@ Subscriptions / Manually Input - - + + - Manually Input Connections + Subscription Link - + + + + Subscription Manager + + + + + + + Open Subscription Manager + + + + Connection Editor - + Open Connection Editor @@ -235,14 +249,14 @@ - + Route Editor - + Open Route Editor @@ -252,8 +266,38 @@ - + + + + Json Editor + + + + + + + Open JSON Editor + + + false + + + + + + + Manually Input Connections + + + + + + + 0 + 0 + + 0 @@ -265,44 +309,6 @@ - - - - Subscription Link - - - - - - - Subscription Manager - - - - - - - Open Subscription Manager - - - - - - - Json Editor - - - - - - - Open JSON Editor - - - false - - - @@ -392,7 +398,6 @@ errorsList connectionEditBtn routeEditBtn - subscriptionButton beginImportBtn cancelImportBtn diff --git a/src/ui/w_MainWindow.cpp b/src/ui/w_MainWindow.cpp index f969a3f4..35b4e5e0 100644 --- a/src/ui/w_MainWindow.cpp +++ b/src/ui/w_MainWindow.cpp @@ -312,7 +312,7 @@ void MainWindow::timerEvent(QTimerEvent *event) auto log = readLastLog().trimmed(); if (!log.isEmpty()) { - FastAppendTextDocument(NEWLINE + log, qvLogDocument); + FastAppendTextDocument(NEWLINE + log, qvLogDocument); /*end*/ // qvLogDocument->setPlainText(qvLogDocument->toPlainText() + NEWLINE + log); } } @@ -379,11 +379,15 @@ void MainWindow::VersionUpdate(QByteArray &data) { LOG(MODULE_UPDATE, "New version detected.") auto link = root["html_url"].toString(""); - auto result = - QvMessageBoxAsk(this, tr("Update"), - tr("Found a new version: ") + root["tag_name"].toString("") + "\r\n" + root["name"].toString("") + - "\r\n------------\r\n" + root["body"].toString("") + "\r\n------------\r\n" + tr("Download Link: ") + link, - QMessageBox::Ignore); + auto result = QvMessageBoxAsk(this, tr("Update"), + tr("Found a new version: ") + // + root["tag_name"].toString("") + NEWLINE + // + root["name"].toString("") + // + NEWLINE "------------" NEWLINE + // + root["body"].toString("") + // + NEWLINE "------------" NEWLINE + // + tr("Download Link: ") + link, + QMessageBox::Ignore); if (result == QMessageBox::Yes) { @@ -393,7 +397,7 @@ void MainWindow::VersionUpdate(QByteArray &data) { // Set and save ingored version. GlobalConfig.ignoredVersion = newVersion.toString(); - // SaveGlobalConfig(GlobalConfig); + SaveGlobalSettings(); } } } @@ -567,7 +571,7 @@ void MainWindow::on_action_RCM_EditAsComplex_triggered() void MainWindow::on_subsButton_clicked() { - SubscribeEditor().exec(); + SubscriptionEditor().exec(); } void MainWindow::on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column) diff --git a/src/ui/w_MainWindow.hpp b/src/ui/w_MainWindow.hpp index 23c53046..fc3515e5 100644 --- a/src/ui/w_MainWindow.hpp +++ b/src/ui/w_MainWindow.hpp @@ -34,6 +34,7 @@ class MainWindow public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow() override; + static MainWindow *mwInstance; signals: void StartConnection() const; void StopConnection() const; @@ -42,47 +43,29 @@ class MainWindow private: QvMessageBusSlotDecl; private slots: +#ifndef DISABLE_AUTO_UPDATE + void VersionUpdate(QByteArray &data); +#endif void on_activatedTray(QSystemTrayIcon::ActivationReason reason); - void on_actionExit_triggered(); void on_preferencesBtn_clicked(); void on_clearlogButton_clicked(); void on_connectionListWidget_customContextMenuRequested(const QPoint &pos); void on_importConfigButton_clicked(); void on_subsButton_clicked(); // - void ToggleVisibility(); -#ifndef DISABLE_AUTO_UPDATE - void VersionUpdate(QByteArray &data); -#endif + void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column); + void on_connectionFilterTxt_textEdited(const QString &arg1); + void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column); + void on_locateBtn_clicked(); // + void on_chartVisibilityBtn_clicked(); + void on_logVisibilityBtn_clicked(); + void on_clearChartBtn_clicked(); + void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_masterLogBrowser_textChanged(); - public: - static MainWindow *mwInstance; - - protected: - void keyPressEvent(QKeyEvent *e) override; - void keyReleaseEvent(QKeyEvent *e) override; - void closeEvent(QCloseEvent *) override; - - private slots: - void OnEditRequested(const ConnectionId &id); - void OnEditJsonRequested(const ConnectionId &id); - // - void OnConnectionWidgetFocusRequested(const ConnectionItemWidget *widget); - // - void OnConnected(const ConnectionId &id); - void OnDisconnected(const ConnectionId &id); - // - void OnStatsAvailable(const ConnectionId &id, const quint64 upS, const quint64 downS, const quint64 upD, const quint64 downD); - void OnVCoreLogAvailable(const ConnectionId &id, const QString &log); - // - void OnConnectionCreated(const ConnectionId &id, const QString &displayName); - void OnConnectionDeleted(const ConnectionId &id, const GroupId &groupId); - void OnConnectionGroupChanged(const ConnectionId &id, const GroupId &originalGroup, const GroupId &newGroup); - // - void OnGroupCreated(const GroupId &id, const QString &displayName); - void OnGroupDeleted(const GroupId &id, const QList &connections); - // + private: + void on_actionExit_triggered(); void on_action_StartThis_triggered(); void on_action_RCM_SetAutoConnection_triggered(); void on_action_RCM_EditThis_triggered(); @@ -96,23 +79,33 @@ class MainWindow void on_action_RCM_tovCoreLog_triggered(); void on_action_RCM_toQvLog_triggered(); // - void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column); - void on_connectionFilterTxt_textEdited(const QString &arg1); - void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column); - void on_locateBtn_clicked(); + void OnConnectionWidgetFocusRequested(const ConnectionItemWidget *widget); + // + void ToggleVisibility(); + void OnEditRequested(const ConnectionId &id); + void OnEditJsonRequested(const ConnectionId &id); + void OnConnected(const ConnectionId &id); + void OnDisconnected(const ConnectionId &id); + // + void OnStatsAvailable(const ConnectionId &id, const quint64 upS, const quint64 downS, const quint64 upD, const quint64 downD); + void OnVCoreLogAvailable(const ConnectionId &id, const QString &log); + // + void OnConnectionCreated(const ConnectionId &id, const QString &displayName); + void OnConnectionDeleted(const ConnectionId &id, const GroupId &groupId); + void OnConnectionGroupChanged(const ConnectionId &id, const GroupId &originalGroup, const GroupId &newGroup); + // + void OnGroupCreated(const GroupId &id, const QString &displayName); + void OnGroupDeleted(const GroupId &id, const QList &connections); // void SortConnectionList(MW_ITEM_COL byCol, bool asending); - void on_chartVisibilityBtn_clicked(); - void on_logVisibilityBtn_clicked(); - void on_clearChartBtn_clicked(); - void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); - - void on_masterLogBrowser_textChanged(); void on_pluginsBtn_clicked(); protected: void timerEvent(QTimerEvent *event) override; + void keyPressEvent(QKeyEvent *e) override; + void keyReleaseEvent(QKeyEvent *e) override; + void closeEvent(QCloseEvent *) override; private: QHash> groupNodes; diff --git a/src/ui/w_MainWindow.ui b/src/ui/w_MainWindow.ui index be5e7f4a..375d087a 100644 --- a/src/ui/w_MainWindow.ui +++ b/src/ui/w_MainWindow.ui @@ -6,22 +6,19 @@ 0 0 - 880 - 660 + 860 + 650 - 780 - 530 + 790 + 600 Qv2ray - - - @@ -50,6 +47,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -60,7 +70,7 @@ - 999999999 + 0 0 diff --git a/src/ui/w_PreferencesWindow.cpp b/src/ui/w_PreferencesWindow.cpp index 4080aff0..f73ef239 100644 --- a/src/ui/w_PreferencesWindow.cpp +++ b/src/ui/w_PreferencesWindow.cpp @@ -211,8 +211,8 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QDialog(parent), Current QSTRN(pacPortSB->value()) + "/pac"); // finishedLoading = true; - routeSettingsWidget = new RouteSettingsMatrixWidget(this); - routeSettingsWidget->SetRouteConfig(CurrentConfig.connectionConfig.routeConfig, CurrentConfig.kernelConfig.AssetsPath()); + routeSettingsWidget = new RouteSettingsMatrixWidget(CurrentConfig.kernelConfig.AssetsPath(), this); + routeSettingsWidget->SetRouteConfig(CurrentConfig.connectionConfig.routeConfig); advRouteSettingsLayout->addWidget(routeSettingsWidget); } @@ -806,7 +806,7 @@ void PreferencesWindow::on_nsBarFontSizeSB_valueChanged(double arg1) SET_LINE_LIST_TEXT } -QString PreferencesWindow::GetBarLineDescription(QvBarLine barLine) +QString PreferencesWindow::GetBarLineDescription(const QvBarLine &barLine) { QString result = "Empty"; result = NetSpeedPluginMessages[barLine.ContentType]; diff --git a/src/ui/w_PreferencesWindow.hpp b/src/ui/w_PreferencesWindow.hpp index 7d39f52b..442ca246 100644 --- a/src/ui/w_PreferencesWindow.hpp +++ b/src/ui/w_PreferencesWindow.hpp @@ -172,7 +172,7 @@ class PreferencesWindow void SetAutoStartButtonsState(bool isAutoStart); // Set ui parameters for a line; void ShowLineParameters(QvBarLine &line); - QString GetBarLineDescription(QvBarLine line); + QString GetBarLineDescription(const QvBarLine &barLine); // int CurrentBarLineId; int CurrentBarPageId; diff --git a/src/ui/w_SubscriptionManager.cpp b/src/ui/w_SubscriptionManager.cpp index db28224c..ac3c7ae8 100644 --- a/src/ui/w_SubscriptionManager.cpp +++ b/src/ui/w_SubscriptionManager.cpp @@ -4,10 +4,10 @@ #include "core/handler/ConfigHandler.hpp" #include "core/settings/SettingsBackend.hpp" -SubscribeEditor::SubscribeEditor(QWidget *parent) : QDialog(parent) +SubscriptionEditor::SubscriptionEditor(QWidget *parent) : QDialog(parent) { setupUi(this); - QvMessageBusConnect(SubscribeEditor); + QvMessageBusConnect(SubscriptionEditor); UpdateColorScheme(); for (auto subs : ConnectionManager->Subscriptions()) { @@ -19,13 +19,13 @@ SubscribeEditor::SubscribeEditor(QWidget *parent) : QDialog(parent) } } -void SubscribeEditor::UpdateColorScheme() +void SubscriptionEditor::UpdateColorScheme() { addSubsButton->setIcon(QICON_R("add.png")); removeSubsButton->setIcon(QICON_R("delete.png")); } -QvMessageBusSlotImpl(SubscribeEditor) +QvMessageBusSlotImpl(SubscriptionEditor) { switch (msg) { @@ -33,16 +33,16 @@ QvMessageBusSlotImpl(SubscribeEditor) } } -tuple SubscribeEditor::GetSelectedConfig() +tuple SubscriptionEditor::GetSelectedConfig() { return { GetDisplayName(currentConnectionId), ConnectionManager->GetConnectionRoot(currentConnectionId) }; } -SubscribeEditor::~SubscribeEditor() +SubscriptionEditor::~SubscriptionEditor() { } -void SubscribeEditor::on_addSubsButton_clicked() +void SubscriptionEditor::on_addSubsButton_clicked() { auto const key = QSTRN(QTime::currentTime().msecsSinceStartOfDay()); auto id = ConnectionManager->CreateGroup(key, true); @@ -50,7 +50,7 @@ void SubscribeEditor::on_addSubsButton_clicked() subscriptionList->addTopLevelItem(new QTreeWidgetItem(QStringList{ key, id.toString() })); } -void SubscribeEditor::on_updateButton_clicked() +void SubscriptionEditor::on_updateButton_clicked() { if (QvMessageBoxAsk(this, tr("Reload Subscription"), tr("Would you like to reload the subscription?")) == QMessageBox::Yes) { @@ -61,7 +61,7 @@ void SubscribeEditor::on_updateButton_clicked() } } -void SubscribeEditor::on_removeSubsButton_clicked() +void SubscriptionEditor::on_removeSubsButton_clicked() { if (QvMessageBoxAsk(this, tr("Deleting a subscription"), tr("All connections will be moved to default group, do you want to continue?")) == QMessageBox::Yes) @@ -82,17 +82,17 @@ void SubscribeEditor::on_removeSubsButton_clicked() } } -void SubscribeEditor::on_buttonBox_accepted() +void SubscriptionEditor::on_buttonBox_accepted() { // Nothing? } -void SubscribeEditor::on_subscriptionList_itemSelectionChanged() +void SubscriptionEditor::on_subscriptionList_itemSelectionChanged() { groupBox_2->setEnabled(subscriptionList->selectedItems().count() > 0); } -void SubscribeEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int column) +void SubscriptionEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int column) { Q_UNUSED(column) @@ -119,31 +119,31 @@ void SubscribeEditor::on_subscriptionList_itemClicked(QTreeWidgetItem *item, int } } -void SubscribeEditor::on_subscriptionList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +void SubscriptionEditor::on_subscriptionList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { Q_UNUSED(previous) on_subscriptionList_itemClicked(current, 0); } -void SubscribeEditor::on_subNameTxt_textEdited(const QString &arg1) +void SubscriptionEditor::on_subNameTxt_textEdited(const QString &arg1) { subscriptionList->selectedItems().first()->setText(0, arg1); ConnectionManager->RenameGroup(currentSubId, arg1.trimmed()); } -void SubscribeEditor::on_subAddrTxt_textEdited(const QString &arg1) +void SubscriptionEditor::on_subAddrTxt_textEdited(const QString &arg1) { auto newUpdateInterval = updateIntervalSB->value(); ConnectionManager->SetSubscriptionData(currentSubId, arg1, newUpdateInterval); } -void SubscribeEditor::on_updateIntervalSB_valueChanged(double arg1) +void SubscriptionEditor::on_updateIntervalSB_valueChanged(double arg1) { auto newAddress = subAddrTxt->text().trimmed(); ConnectionManager->SetSubscriptionData(currentSubId, newAddress, arg1); } -void SubscribeEditor::on_connectionsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +void SubscriptionEditor::on_connectionsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) { Q_UNUSED(previous) if (current != nullptr) diff --git a/src/ui/w_SubscriptionManager.hpp b/src/ui/w_SubscriptionManager.hpp index cf1b6c43..01134023 100644 --- a/src/ui/w_SubscriptionManager.hpp +++ b/src/ui/w_SubscriptionManager.hpp @@ -7,15 +7,15 @@ #include -class SubscribeEditor +class SubscriptionEditor : public QDialog , private Ui::w_SubscribeEditor { Q_OBJECT public: - explicit SubscribeEditor(QWidget *parent = nullptr); - ~SubscribeEditor(); + explicit SubscriptionEditor(QWidget *parent = nullptr); + ~SubscriptionEditor(); tuple GetSelectedConfig(); private: diff --git a/src/ui/widgets/ConnectionInfoWidget.cpp b/src/ui/widgets/ConnectionInfoWidget.cpp index 6a94f813..8e5651d4 100644 --- a/src/ui/widgets/ConnectionInfoWidget.cpp +++ b/src/ui/widgets/ConnectionInfoWidget.cpp @@ -84,7 +84,7 @@ void ConnectionInfoWidget::ShowDetails(const tuple &_iden // QZXingEncoderConfig conf; conf.border = true; - conf.imageSize = QSize(400, 400); + conf.imageSize = qrLabel->size() * devicePixelRatio(); conf.errorCorrectionLevel = QZXing::EncodeErrorCorrectionLevel_M; QZXing qzx; qrPixmap = QPixmap::fromImage(qzx.encodeData(shareLink, conf)); diff --git a/src/ui/widgets/QvAutoCompleteTextEdit.cpp b/src/ui/widgets/QvAutoCompleteTextEdit.cpp index b94e226d..5859e551 100644 --- a/src/ui/widgets/QvAutoCompleteTextEdit.cpp +++ b/src/ui/widgets/QvAutoCompleteTextEdit.cpp @@ -62,56 +62,23 @@ namespace Qv2ray::ui::widgets { - AutoCompleteTextEdit::AutoCompleteTextEdit(const QString &prefix, QWidget *parent) : QTextEdit(parent) - { - SetPrefix(prefix); - } - - AutoCompleteTextEdit::~AutoCompleteTextEdit() - { - } - - void AutoCompleteTextEdit::SetPrefix(const QString &prefix) + AutoCompleteTextEdit::AutoCompleteTextEdit(const QString &prefix, const QStringList &sourceStrings, QWidget *parent) : QTextEdit(parent) { this->prefix = prefix; - } - - void AutoCompleteTextEdit::SetSourceStrings(QStringList sourceStrings) - { - auto x = new QCompleter(this); - auto model = new QStringListModel(sourceStrings); - x->setModel(model); - SetCompleter(x); - } - - void AutoCompleteTextEdit::SetCompleter(QCompleter *completer) - { - if (c) - c->disconnect(this); - - c = completer; - - if (!c) - { - return; - } - + c = new QCompleter(this); + c->setModel(new QStringListModel(sourceStrings, c)); c->setWidget(this); c->setCompletionMode(QCompleter::PopupCompletion); c->setCaseSensitivity(Qt::CaseInsensitive); QObject::connect(c, QOverload::of(&QCompleter::activated), this, &AutoCompleteTextEdit::insertCompletion); } - QCompleter *AutoCompleteTextEdit::completer() const + AutoCompleteTextEdit::~AutoCompleteTextEdit() { - return c; } void AutoCompleteTextEdit::insertCompletion(const QString &completion) { - if (c->widget() != this) - return; - QTextCursor tc = textCursor(); int extra = completion.length() - c->completionPrefix().length(); tc.movePosition(QTextCursor::Left); diff --git a/src/ui/widgets/QvAutoCompleteTextEdit.h b/src/ui/widgets/QvAutoCompleteTextEdit.h index 2cdf1aa3..f369cb34 100644 --- a/src/ui/widgets/QvAutoCompleteTextEdit.h +++ b/src/ui/widgets/QvAutoCompleteTextEdit.h @@ -62,14 +62,9 @@ namespace Qv2ray::ui::widgets Q_OBJECT public: - AutoCompleteTextEdit(const QString &prefix, QWidget *parent = nullptr); + AutoCompleteTextEdit(const QString &prefix, const QStringList &sourceStrings, QWidget *parent = nullptr); ~AutoCompleteTextEdit(); - void SetPrefix(const QString &prefix); - void SetCompleter(QCompleter *c); - void SetSourceStrings(QStringList sourceStrings); - QCompleter *completer() const; - protected: void keyPressEvent(QKeyEvent *e) override; void focusInEvent(QFocusEvent *e) override; @@ -81,9 +76,7 @@ namespace Qv2ray::ui::widgets QString lineUnderCursor() const; QString wordUnderCursor() const; - private: QString prefix; - QAbstractItemModel *modelFromStringList(const QStringList &list); QCompleter *c = nullptr; }; } // namespace Qv2ray::ui::widgets diff --git a/src/ui/widgets/RouteSettingsMatrix.cpp b/src/ui/widgets/RouteSettingsMatrix.cpp index 7b7ee677..d4cce411 100644 --- a/src/ui/widgets/RouteSettingsMatrix.cpp +++ b/src/ui/widgets/RouteSettingsMatrix.cpp @@ -3,38 +3,27 @@ #include "common/QvHelpers.hpp" #include "components/geosite/QvGeositeReader.hpp" -RouteSettingsMatrixWidget::RouteSettingsMatrixWidget(QWidget *parent) : QWidget(parent) +#include +#include + +RouteSettingsMatrixWidget::RouteSettingsMatrixWidget(const QString &assetsDirPath, QWidget *parent) + : QWidget(parent), assetsDirPath(assetsDirPath) { setupUi(this); // - directDomainTxt = new AutoCompleteTextEdit("geosite", this); - proxyDomainTxt = new AutoCompleteTextEdit("geosite", this); - blockDomainTxt = new AutoCompleteTextEdit("geosite", this); - // - directIPTxt = new AutoCompleteTextEdit("geoip", this); - proxyIPTxt = new AutoCompleteTextEdit("geoip", this); - blockIPTxt = new AutoCompleteTextEdit("geoip", this); -} - -void RouteSettingsMatrixWidget::SetRouteConfig(const config::Qv2rayRouteConfig conf, const QString &assetsDirPath) -{ - directDomainTxt->setText(conf.domains.direct.join(NEWLINE)); - proxyDomainTxt->setText(conf.domains.proxy.join(NEWLINE)); - blockDomainTxt->setText(conf.domains.block.join(NEWLINE)); - // - blockIPTxt->setText(conf.ips.block.join(NEWLINE)); - directIPTxt->setText(conf.ips.direct.join(NEWLINE)); - proxyIPTxt->setText(conf.ips.proxy.join(NEWLINE)); + builtInSchemesMenu = new QMenu(this); + builtInSchemesMenu->addActions(this->getBuiltInSchemes()); + builtInSchemeBtn->setMenu(builtInSchemesMenu); // auto sourceStringsDomain = ReadGeoSiteFromFile(assetsDirPath + "/geosite.dat"); - directDomainTxt->SetSourceStrings(sourceStringsDomain); - proxyDomainTxt->SetSourceStrings(sourceStringsDomain); - blockDomainTxt->SetSourceStrings(sourceStringsDomain); + directDomainTxt = new AutoCompleteTextEdit("geosite", sourceStringsDomain, this); + proxyDomainTxt = new AutoCompleteTextEdit("geosite", sourceStringsDomain, this); + blockDomainTxt = new AutoCompleteTextEdit("geosite", sourceStringsDomain, this); // auto sourceStringsIP = ReadGeoSiteFromFile(assetsDirPath + "/geoip.dat"); - directIPTxt->SetSourceStrings(sourceStringsIP); - proxyIPTxt->SetSourceStrings(sourceStringsIP); - blockIPTxt->SetSourceStrings(sourceStringsIP); + directIPTxt = new AutoCompleteTextEdit("geoip", sourceStringsIP, this); + proxyIPTxt = new AutoCompleteTextEdit("geoip", sourceStringsIP, this); + blockIPTxt = new AutoCompleteTextEdit("geoip", sourceStringsIP, this); // directTxtLayout->addWidget(directDomainTxt, 0, 0); proxyTxtLayout->addWidget(proxyDomainTxt, 0, 0); @@ -43,6 +32,195 @@ void RouteSettingsMatrixWidget::SetRouteConfig(const config::Qv2rayRouteConfig c directIPLayout->addWidget(directIPTxt, 0, 0); proxyIPLayout->addWidget(proxyIPTxt, 0, 0); blockIPLayout->addWidget(blockIPTxt, 0, 0); + // +} + +/** + * @brief RouteSettingsMatrixWidget::getBuiltInSchemes + * @return + */ +QList RouteSettingsMatrixWidget::getBuiltInSchemes() +{ + QList list; + + Qv2ray::base::config::Qv2rayRouteConfig emptyScheme; + list.append(this->schemeToAction(tr("empty scheme"), emptyScheme)); + + // v2rayN scheme from 2dust/v2rayCustomRoutingList + // License: GPL3 + Qv2ray::base::config::Qv2rayRouteConfig v2rayNScheme; + v2rayNScheme.ips.proxy = { + "91.108.4.0/22", "91.108.8.0/22", "91.108.12.0/22", "91.108.20.0/22", "91.108.36.0/23", + "91.108.38.0/23", "91.108.56.0/22", "149.154.160.0/20", "149.154.164.0/22", "149.154.172.0/22", + "74.125.0.0/16", "173.194.0.0/16", "172.217.0.0/16", "216.58.200.0/24", "216.58.220.0/24", + "91.108.56.116", "91.108.56.0/24", "109.239.140.0/24", "149.154.167.0/24", "149.154.175.0/24", + }; + v2rayNScheme.domains.direct = { + "domain:12306.com", + "domain:51ym.me", + "domain:52pojie.cn", + "domain:8686c.com", + "domain:abercrombie.com", + "domain:adobesc.com", + "domain:air-matters.com", + "domain:air-matters.io", + "domain:airtable.com", + "domain:akadns.net", + "domain:apache.org", + "domain:api.crisp.chat", + "domain:api.termius.com", + "domain:appshike.com", + "domain:appstore.com", + "domain:aweme.snssdk.com", + "domain:bababian.com", + "domain:battle.net", + "domain:beatsbydre.com", + "domain:bet365.com", + "domain:bilibili.cn", + "domain:ccgslb.com", + "domain:ccgslb.net", + "domain:chunbo.com", + "domain:chunboimg.com", + "domain:clashroyaleapp.com", + "domain:cloudsigma.com", + "domain:cloudxns.net", + "domain:cmfu.com", + "domain:culturedcode.com", + "domain:dct-cloud.com", + "domain:didialift.com", + "domain:douyutv.com", + "domain:duokan.com", + "domain:dytt8.net", + "domain:easou.com", + "domain:ecitic.net", + "domain:eclipse.org", + "domain:eudic.net", + "domain:ewqcxz.com", + "domain:fir.im", + "domain:frdic.com", + "domain:fresh-ideas.cc", + "domain:godic.net", + "domain:goodread.com", + "domain:haibian.com", + "domain:hdslb.net", + "domain:hollisterco.com", + "domain:hongxiu.com", + "domain:hxcdn.net", + "domain:images.unsplash.com", + "domain:img4me.com", + "domain:ipify.org", + "domain:ixdzs.com", + "domain:jd.hk", + "domain:jianshuapi.com", + "domain:jomodns.com", + "domain:jsboxbbs.com", + "domain:knewone.com", + "domain:kuaidi100.com", + "domain:lemicp.com", + "domain:letvcloud.com", + "domain:lizhi.io", + "domain:localizecdn.com", + "domain:lucifr.com", + "domain:luoo.net", + "domain:mai.tn", + "domain:maven.org", + "domain:miwifi.com", + "domain:moji.com", + "domain:moke.com", + "domain:mtalk.google.com", + "domain:mxhichina.com", + "domain:myqcloud.com", + "domain:myunlu.com", + "domain:netease.com", + "domain:nfoservers.com", + "domain:nssurge.com", + "domain:nuomi.com", + "domain:ourdvs.com", + "domain:overcast.fm", + "domain:paypal.com", + "domain:paypalobjects.com", + "domain:pgyer.com", + "domain:qdaily.com", + "domain:qdmm.com", + "domain:qin.io", + "domain:qingmang.me", + "domain:qingmang.mobi", + "domain:qqurl.com", + "domain:rarbg.to", + "domain:rrmj.tv", + "domain:ruguoapp.com", + "domain:sm.ms", + "domain:snwx.com", + "domain:soku.com", + "domain:startssl.com", + "domain:store.steampowered.com", + "domain:symcd.com", + "domain:teamviewer.com", + "domain:tmzvps.com", + "domain:trello.com", + "domain:trellocdn.com", + "domain:ttmeiju.com", + "domain:udache.com", + "domain:uxengine.net", + "domain:weather.bjango.com", + "domain:weather.com", + "domain:webqxs.com", + "domain:weico.cc", + "domain:wenku8.net", + "domain:werewolf.53site.com", + "domain:windowsupdate.com", + "domain:wkcdn.com", + "domain:workflowy.com", + "domain:xdrig.com", + "domain:xiaojukeji.com", + "domain:xiaomi.net", + "domain:xiaomicp.com", + "domain:ximalaya.com", + "domain:xitek.com", + "domain:xmcdn.com", + "domain:xslb.net", + "domain:xteko.com", + "domain:yach.me", + "domain:yixia.com", + "domain:yunjiasu-cdn.net", + "domain:zealer.com", + "domain:zgslb.net", + "domain:zimuzu.tv", + "domain:zmz002.com", + "domain:samsungdm.com", + }; + + v2rayNScheme.domains.proxy = { + "geosite:google", "geosite:github", "geosite:netflix", "geosite:steam", "geosite:telegram", + "geosite:tumblr", "geosite:speedtest", "geosite:bbc", "domain:gvt1.com", "domain:textnow.com", + "domain:twitch.tv", "domain:wikileaks.org", "domain:naver.com", + }; + + v2rayNScheme.domains.block = { + "geosite:category-ads-all", + }; + + list.append(this->schemeToAction(tr("v2rayN preset"), v2rayNScheme)); + return list; +} + +QAction *RouteSettingsMatrixWidget::schemeToAction(const QString &name, Qv2ray::base::config::Qv2rayRouteConfig scheme) +{ + QAction *action = new QAction(); + action->setText(name); + connect(action, &QAction::triggered, [=] { this->SetRouteConfig(scheme); }); + return action; +} + +void RouteSettingsMatrixWidget::SetRouteConfig(const config::Qv2rayRouteConfig &conf) +{ + directDomainTxt->setText(conf.domains.direct.join(NEWLINE)); + proxyDomainTxt->setText(conf.domains.proxy.join(NEWLINE)); + blockDomainTxt->setText(conf.domains.block.join(NEWLINE)); + // + blockIPTxt->setText(conf.ips.block.join(NEWLINE)); + directIPTxt->setText(conf.ips.direct.join(NEWLINE)); + proxyIPTxt->setText(conf.ips.proxy.join(NEWLINE)); } config::Qv2rayRouteConfig RouteSettingsMatrixWidget::GetRouteConfig() const @@ -61,3 +239,164 @@ config::Qv2rayRouteConfig RouteSettingsMatrixWidget::GetRouteConfig() const RouteSettingsMatrixWidget::~RouteSettingsMatrixWidget() { } + +/** + * @brief The Qv2rayRouteScheme struct + * @author DuckSoft + */ +struct Qv2rayRouteScheme : config::Qv2rayRouteConfig +{ + /** + * @brief the name of the scheme. + * @example "Untitled Scheme" + */ + QString name; + /** + * @brief the author of the scheme. + * @example "DuckSoft " + */ + QString author; + /** + * @brief details of this scheme. + * @example "A scheme to bypass China mainland, while allowing bilibili to go through proxy." + */ + QString description; + + // M: all these fields are mandatory + XTOSTRUCT(M(name, author, description, domains, ips)); +}; + +/** + * @brief RouteSettingsMatrixWidget::on_importSchemeBtn_clicked + * @author DuckSoft + * @todo add some debug output + */ +void RouteSettingsMatrixWidget::on_importSchemeBtn_clicked() +{ + try + { + // open up the file dialog and choose a file. + auto filePath = this->openFileDialog(); + if (!filePath) + return; + + // read the file and parse back to struct. + // if error occurred on parsing, an exception will be thrown. + auto content = StringFromFile(filePath.value()); + auto scheme = StructFromJsonString(content); + + // show the information of this scheme to user, + // and ask user if he/she wants to import and apply this. + auto strPrompt = tr("Import scheme '%1' by '%2'?" NEWLINE "Description: %3").arg(scheme.name, scheme.author, scheme.description); + auto decision = QvMessageBoxAsk(this, tr("Importing Scheme"), strPrompt); + + // if user don't want to import, just leave. + if (decision != QMessageBox::Yes) + return; + + // write the scheme onto the window + this->SetRouteConfig(static_cast(scheme)); + + // done + LOG(MODULE_SETTINGS, "Imported route config: " + scheme.name + " by: " + scheme.author) + } + catch (exception e) + { + LOG(MODULE_UI, "Exception: " + QString(e.what())) + // TODO: Give some error as Notification + } +} + +/** + * @brief RouteSettingsMatrixWidget::on_exportSchemeBtn_clicked + * @author DuckSoft + */ +void RouteSettingsMatrixWidget::on_exportSchemeBtn_clicked() +{ + try + { + // parse the config back from the window components + auto config = this->GetRouteConfig(); + + // init some constants + const auto dialogTitle = tr("Exporting Scheme"); + + // scheme name? + bool ok = false; + auto schemeName = QInputDialog::getText(this, dialogTitle, tr("Scheme name:"), QLineEdit::Normal, tr("Unnamed Scheme"), &ok); + if (!ok) + return; + + // scheme author? + auto schemeAuthor = QInputDialog::getText(this, dialogTitle, tr("Author:"), QLineEdit::Normal, "Anonymous ", &ok); + if (!ok) + return; + + // scheme description? + auto schemeDescription = + QInputDialog::getText(this, dialogTitle, tr("Description:"), QLineEdit::Normal, tr("The author is too lazy to leave a comment")); + if (!ok) + return; + + // where to save? + auto savePath = this->saveFileDialog(); + if (!savePath) + return; + + // construct the data structure + Qv2rayRouteScheme scheme; + scheme.name = schemeName; + scheme.author = schemeAuthor; + scheme.description = schemeDescription; + scheme.ips = config.ips; + scheme.domains = config.domains; + + // serialize and write out + auto content = StructToJsonString(scheme); + StringToFile(content, savePath.value()); + + // done + // TODO: Give some success as Notification + } + catch (exception) + { + + // TODO: Give some error as Notification + } +} + +/** + * @brief opens a save dialog and asks user to specify the save path. + * @return the selected file path, if any + * @author DuckSoft + */ +std::optional RouteSettingsMatrixWidget::saveFileDialog() +{ + QFileDialog dialog; + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setOption(QFileDialog::Option::DontConfirmOverwrite, !true); + dialog.setNameFilter(tr("QvRoute Schemes(*.json)")); + dialog.setAcceptMode(QFileDialog::AcceptMode::AcceptSave); + if (!dialog.exec() || dialog.selectedFiles().length() != 1) + { + return std::nullopt; + } + return dialog.selectedFiles().first(); +} + +/** + * @brief opens up a dialog and asks user to choose a scheme file. + * @return the selected file path, if any + * @author DuckSoft + */ +std::optional RouteSettingsMatrixWidget::openFileDialog() +{ + QFileDialog dialog; + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setNameFilter(tr("QvRoute Schemes(*.json)")); + if (!dialog.exec() || dialog.selectedFiles().length() != 1) + { + return std::nullopt; + } + return dialog.selectedFiles().first(); +} diff --git a/src/ui/widgets/RouteSettingsMatrix.hpp b/src/ui/widgets/RouteSettingsMatrix.hpp index 71597bcc..af68afec 100644 --- a/src/ui/widgets/RouteSettingsMatrix.hpp +++ b/src/ui/widgets/RouteSettingsMatrix.hpp @@ -3,7 +3,9 @@ #include "base/models/QvSettingsObject.hpp" #include "ui_RouteSettingsMatrix.h" +#include #include +#include class RouteSettingsMatrixWidget : public QWidget @@ -12,11 +14,27 @@ class RouteSettingsMatrixWidget Q_OBJECT public: - explicit RouteSettingsMatrixWidget(QWidget *parent = nullptr); - void SetRouteConfig(const Qv2ray::base::config::Qv2rayRouteConfig conf, const QString &assetsDirPath); + RouteSettingsMatrixWidget(const QString &assetsDirPath, QWidget *parent = nullptr); + void SetRouteConfig(const Qv2ray::base::config::Qv2rayRouteConfig &conf); Qv2ray::base::config::Qv2rayRouteConfig GetRouteConfig() const; ~RouteSettingsMatrixWidget(); + private: + std::optional openFileDialog(); + std::optional saveFileDialog(); + QList getBuiltInSchemes(); + QAction *schemeToAction(const QString &name, Qv2ray::base::config::Qv2rayRouteConfig scheme); + + private: + QMenu *builtInSchemesMenu; + + private slots: + void on_importSchemeBtn_clicked(); + void on_exportSchemeBtn_clicked(); + + private: + const QString &assetsDirPath; + private: Qv2ray::ui::widgets::AutoCompleteTextEdit *directDomainTxt; Qv2ray::ui::widgets::AutoCompleteTextEdit *proxyDomainTxt; diff --git a/src/ui/widgets/RouteSettingsMatrix.ui b/src/ui/widgets/RouteSettingsMatrix.ui index 199a8406..39927756 100644 --- a/src/ui/widgets/RouteSettingsMatrix.ui +++ b/src/ui/widgets/RouteSettingsMatrix.ui @@ -2,6 +2,14 @@ RouteSettingsMatrix + + + 0 + 0 + 927 + 198 + + Form @@ -14,7 +22,45 @@ - + + + + + IP + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Domain + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + + + + + @@ -45,52 +91,27 @@ - - - - Domain - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - - - IP - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - false + true Qt::CustomContextMenu @@ -99,7 +120,7 @@ Use built-in route schemes - Built-in Schemes + Built-in Schemes... QToolButton::InstantPopup @@ -108,40 +129,33 @@ Qt::ToolButtonTextBesideIcon - Qt::DownArrow + Qt::NoArrow - false + true Import route scheme from file - Import Scheme + Import Scheme... - false + true Export route scheme to file - Export Scheme - - - - - - - Coming soon! + Export Scheme... diff --git a/translations/en_US.ts b/translations/en_US.ts index aabbe4e9..096491ad 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -305,42 +305,42 @@ - + Select file to import - + Capture QRCode - + Cannot find a valid QRCode from this region. - + Import config file - + Failed to check the validity of the config file. - + Select an image to import - + QRCode scanning failed - + Cannot find any QRCode from the image. @@ -1216,11 +1216,11 @@ PreferencesWindow - - - - - + + + + + Preferences @@ -1606,13 +1606,13 @@ - + Bold - + Italic @@ -1737,13 +1737,13 @@ - - + + Enable tProxy Support - + to this path: @@ -1753,115 +1753,115 @@ - + Duplicated port numbers detected, please check the port number settings. - + Invalid inbound listening address. - + Open V2ray assets folder - + Open V2ray core file - + This will append capabilities to the V2ray executable. - + Qv2ray will copy your V2ray core to this path: - + If anything goes wrong after enabling this, please check issue #57 or the link below: - + Qv2ray cannot copy one or both V2ray files from: - - + + Failed to setcap onto V2ray executable. You may need to run `setcap` manually. - + tProxy is not supported on macOS and Windows - + Apply network toolbar settings - + All other modified settings will be applied as well after this object. - + Do you want to continue? - + Select GFWList in base64 - - + + Download GFWList - + Operation is cancelled. - + Successfully downloaded GFWList. - + Start with boot - + Failed to set auto start option. - - + + V2ray Core Settings - + V2ray path configuration check passed. - + Current version of V2ray is: @@ -2056,7 +2056,7 @@ p, li { white-space: pre-wrap; } - + Qv2ray will now exit. @@ -2071,57 +2071,57 @@ p, li { white-space: pre-wrap; } - + You cannot run Qv2ray as root, please use --I-just-wanna-run-with-root if you REALLY want to do so. - + --> USE IT AT YOUR OWN RISK! - + Debug version - + Qv2ray Cannot Continue - + You are running a lower version of Qv2ray compared to the current config file. - + Please check if there's an issue explaining about it. - + Or submit a new issue if you think this is an error. - + Dependency Missing - + This could be caused by a missing of `openssl` package in your system. - + If you are using an AppImage from Github Action, please report a bug. - + Cannot find openssl libs @@ -2141,7 +2141,7 @@ p, li { white-space: pre-wrap; } - + Technical Details @@ -2164,25 +2164,25 @@ p, li { white-space: pre-wrap; } - + Deprecated - + PAC is now deprecated and is not encouraged to be used anymore. - + It will be removed or be provided as a plugin in the future. - + PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible. @@ -3015,21 +3015,11 @@ p, li { white-space: pre-wrap; } Use built-in route schemes - - - Built-in Schemes - - Import route scheme from file - - - Import Scheme - - Export route scheme to file @@ -3037,12 +3027,76 @@ p, li { white-space: pre-wrap; } - Export Scheme + Built-in Schemes... - Coming soon! + Import Scheme... + + + + + Export Scheme... + + + + + RouteSettingsMatrixWidget + + + empty scheme + + + + + v2rayN preset + + + + + Import scheme '%1' by '%2'? + + + + + Importing Scheme + + + + + Exporting Scheme + + + + + Scheme name: + + + + + Unnamed Scheme + + + + + Author: + + + + + Description: + + + + + The author is too lazy to leave a comment + + + + + + QvRoute Schemes(*.json) @@ -3243,22 +3297,22 @@ p, li { white-space: pre-wrap; } SubscribeEditor - + Reload Subscription - + Would you like to reload the subscription? - + Deleting a subscription - + All connections will be moved to default group, do you want to continue? diff --git a/translations/ja_JP.ts b/translations/ja_JP.ts index 3199d790..2768918e 100644 --- a/translations/ja_JP.ts +++ b/translations/ja_JP.ts @@ -415,42 +415,42 @@ 取り消し - + Select file to import インポートするファイルを選択 - + Capture QRCode QRCodeをキャプチャ - + Cannot find a valid QRCode from this region. この地域から有効なQRコードが見つかりません。 - + Import config file 設定ファイルをインポートする - + Failed to check the validity of the config file. 構成ファイルの有効性を確認できませんでした。 - + Select an image to import インポートする画像を選択してください - + QRCode scanning failed QRコードのスキャンに失敗しました - + Cannot find any QRCode from the image. 画像からQRコードが見つかりません。 @@ -1619,11 +1619,11 @@ PreferencesWindow - - - - - + + + + + Preferences 設定 @@ -2093,13 +2093,13 @@ - + Bold Bold - + Italic 斜体 @@ -2224,13 +2224,13 @@ アイテム - - + + Enable tProxy Support tProxyサポートを有効にする - + to this path: このパスへ: @@ -2240,68 +2240,68 @@ Qv2rayネットワークツールバーは無効になっており、まだテスト中です。 --withToolbarPluginを追加して有効にします。 - + Duplicated port numbers detected, please check the port number settings. 重複したポート番号が検出されました。ポート番号の設定を確認してください。 - + Invalid inbound listening address. 無効なインバウンドリスニングアドレス。 - + Open V2ray assets folder V2rayアセットフォルダーを開く - + Open V2ray core file V2rayコアファイルを開く - + This will append capabilities to the V2ray executable. これにより、V2ray実行可能ファイルに機能が追加されます。 - + Qv2ray will copy your V2ray core to this path: Qv2rayは、V2rayコアを次のパスにコピーします: - + If anything goes wrong after enabling this, please check issue #57 or the link below: これを有効にした後に何か問題が発生した場合は、問題#57または以下のリンクを確認してください: - + Qv2ray cannot copy one or both V2ray files from: Qv2rayは、V2rayファイルの一方または両方を以下からコピーできません: - - + + Failed to setcap onto V2ray executable. You may need to run `setcap` manually. V2ray実行可能ファイルへのsetcapに失敗しました。`setcap`を手動で実行する必要がある場合があります。 - + tProxy is not supported on macOS and Windows tProxyはmacOSおよびWindowsではサポートされていません - + Apply network toolbar settings ネットワークツールバー設定を適用する - + All other modified settings will be applied as well after this object. All other modified settings will be applied as well after this object. - + Do you want to continue? 続けますか? @@ -2314,49 +2314,49 @@ Please restart Qv2ray to fully apply this feature. - + Select GFWList in base64 Base64でGFWListを選択します - - + + Download GFWList GFWListをダウンロードする - + Operation is cancelled. 操作はキャンセルされます。 - + Successfully downloaded GFWList. GFWListを正常にダウンロードしました。 - + Start with boot ブート時に起動します - + Failed to set auto start option. 自動開始オプションの設定に失敗しました。 - - + + V2ray Core Settings V2ray Core設定 - + V2ray path configuration check passed. V2rayパス構成チェックに合格しました。 - + Current version of V2ray is: V2rayの現在のバージョンは次のとおりです: @@ -2487,7 +2487,7 @@ p, li { white-space: pre-wrap; } - + Qv2ray will now exit. Qv2rayは終了します。 @@ -2506,12 +2506,12 @@ p, li { white-space: pre-wrap; } バグだと思われる場合は報告してください。 - + You cannot run Qv2ray as root, please use --I-just-wanna-run-with-root if you REALLY want to do so. Qv2rayをルートとして実行することはできません。本当に実行したい場合は、--I-just-wanna-run-with-rootを使用してください。 - + --> USE IT AT YOUR OWN RISK! --> 自分の責任で使用してください! @@ -2524,42 +2524,42 @@ p, li { white-space: pre-wrap; } Qv2ray will continue running, but you cannot change the UI language. - + Qv2ray Cannot Continue Qv2rayを続行できません - + You are running a lower version of Qv2ray compared to the current config file. 現在の構成ファイルと比較して、より低いバージョンのQv2rayを実行しています。 - + Please check if there's an issue explaining about it. それについて説明する問題があるかどうかを確認してください。 - + Or submit a new issue if you think this is an error. または、これがエラーだと思われる場合は、新しい問題を送信してください。 - + Dependency Missing 依存関係がありません - + This could be caused by a missing of `openssl` package in your system. これは、システムに `openssl`パッケージが存在しないことが原因である可能性があります。 - + If you are using an AppImage from Github Action, please report a bug. Github ActionsのAppImageを使用している場合は、バグを報告してください。 - + Cannot find openssl libs OpenSSLライブラリが見つかりません @@ -2579,12 +2579,12 @@ p, li { white-space: pre-wrap; } 回避策は、このファイルを削除してQv2rayを再起動することです: - + Debug version デバッグバージョン - + Technical Details 技術的な詳細 @@ -2803,25 +2803,25 @@ p, li { white-space: pre-wrap; } - + Deprecated 非推奨 - + PAC is now deprecated and is not encouraged to be used anymore. PACは非推奨になり、使用を推奨されなくなりました。 - + It will be removed or be provided as a plugin in the future. 今後削除されるか、プラグインとして提供されます。 - + PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible. PACは現在も機能しますが、できるだけ早くV2Rayの組み込みルーティングに切り替えてください。 @@ -3515,9 +3515,8 @@ p, li { white-space: pre-wrap; } 組み込みのルートスキームを使用する - Built-in Schemes - 組み込みスキーム + 組み込みスキーム @@ -3525,9 +3524,8 @@ p, li { white-space: pre-wrap; } ファイルからルートスキームをインポートする - Import Scheme - スキームをインポート + スキームをインポート @@ -3535,14 +3533,86 @@ p, li { white-space: pre-wrap; } ルートスキームをファイルにエクスポート - Export Scheme - スキームをエクスポート + スキームをエクスポート + + + Coming soon! + 近日公開! - Coming soon! - 近日公開! + Built-in Schemes... + 組み込みスキーム... + + + + Import Scheme... + スキームをインポート... + + + + Export Scheme... + スキームをエクスポート... + + + + RouteSettingsMatrixWidget + + + empty scheme + 空策略 + + + + v2rayN preset + v2rayN 策略 + + + + Import scheme '%1' by '%2'? + 「%2」によるスキーム「%1」をインポートしますか? + + + + Importing Scheme + スキームをインポート + + + + Exporting Scheme + スキームをエクスポート + + + + Scheme name: + スキーム名: + + + + Unnamed Scheme + 無名スキーム + + + + Author: + 著者: + + + + Description: + 説明: + + + + The author is too lazy to leave a comment + 著者はコメントを残すのが面倒です + + + + + QvRoute Schemes(*.json) + QvRouteスキーム(* .json) @@ -3782,22 +3852,22 @@ p, li { white-space: pre-wrap; } Failed to process the result from the upstream, please check your Url. - + Reload Subscription サブスクリプションを更新 - + Would you like to reload the subscription? サブスクリプションを更新しますか? - + Deleting a subscription サブスクリプションを削除する - + All connections will be moved to default group, do you want to continue? すべての接続がデフォルトグループに移動します。続行しますか? diff --git a/translations/ru_RU.ts b/translations/ru_RU.ts index 21bbca31..b8be1119 100644 --- a/translations/ru_RU.ts +++ b/translations/ru_RU.ts @@ -399,42 +399,42 @@ Отмена - + Select file to import Выберите файл для Импорта - + Capture QRCode Захват QRCode - + Cannot find a valid QRCode from this region. Не удается найти QRCode из этой области. - + Import config file Выберите файл конфигурации - + Failed to check the validity of the config file. Не удалось проверить правильность файла конфигурации. - + Select an image to import Выберите изображение для импорта - + QRCode scanning failed Ошибка сканирования QRCode - + Cannot find any QRCode from the image. Не удается найти QRCode в изображении. @@ -1603,11 +1603,11 @@ PreferencesWindow - - - - - + + + + + Preferences Настройки @@ -2077,13 +2077,13 @@ - + Bold Жирный - + Italic Курсив @@ -2208,13 +2208,13 @@ Объекты - - + + Enable tProxy Support Включить tProxy поддержку - + to this path: на этот путь: @@ -2224,68 +2224,68 @@ Панель инструментов сети Qv2ray отключена и все еще тестируется. Добавьте --withToolbarPlugin для включения. - + Duplicated port numbers detected, please check the port number settings. Обнаружены дублированные номера портов, проверьте настройки номера порта. - + Invalid inbound listening address. Неверный входящий адрес прослушивания. - + Open V2ray assets folder Откройте папку активов v2ray - + Open V2ray core file Открыть основной файл V2ray - + This will append capabilities to the V2ray executable. Это добавит возможности к исполняемому файлу V2ray. - + Qv2ray will copy your V2ray core to this path: Qv2ray скопирует ваше ядро V2ray по этому пути: - + If anything goes wrong after enabling this, please check issue #57 or the link below: Если после включения этого параметра что-то пойдет не так, проверьте проблему № 57 или ссылку ниже: - + Qv2ray cannot copy one or both V2ray files from: Qv2ray не может скопировать один или оба файла V2ray из: - - + + Failed to setcap onto V2ray executable. You may need to run `setcap` manually. Не удалось установить setcap на исполняемый файл V2ray. Возможно, вам придется запустить `setcap` вручную. - + tProxy is not supported on macOS and Windows tProxy не поддерживается на macOS и Windows - + Apply network toolbar settings Применить настройки панели инструментов сети - + All other modified settings will be applied as well after this object. Все остальные измененные настройки будут применены и после этого объекта. - + Do you want to continue? Вы хотите продолжить? @@ -2298,49 +2298,49 @@ Пожалуйста, перезапустите Qv2ray, чтобы полностью применить эту функцию. - + Select GFWList in base64 Выберите GFWList в base64 - - + + Download GFWList Скачать GFWList - + Operation is cancelled. Операция отменена. - + Successfully downloaded GFWList. Успешно загружено %1$s. - + Start with boot Автозапуск - + Failed to set auto start option. Не удалось установить опцию автозапуска. - - + + V2ray Core Settings Настройки ядра V2ray - + V2ray path configuration check passed. Проверка конфигурации пути V2ray пройдена. - + Current version of V2ray is: Текущая версия V2ray: @@ -2459,7 +2459,7 @@ p, li { white-space: pre-wrap; } - + Qv2ray will now exit. Qv2ray теперь выйдет. @@ -2478,12 +2478,12 @@ p, li { white-space: pre-wrap; } Пожалуйста, сообщите, если вы считаете об этом, если это ошибка. - + You cannot run Qv2ray as root, please use --I-just-wanna-run-with-root if you REALLY want to do so. Вы не можете запустить Qv2ray как root, пожалуйста, используйте --I-just-wanna-run-with-root, если вы хотите это сделать. - + --> USE IT AT YOUR OWN RISK! --> ИСПОЛЬЗУЙТЕ ЕГО НА СВОЙ СТРАХ И РИСК! @@ -2496,42 +2496,42 @@ p, li { white-space: pre-wrap; } Qv2ray продолжит работу, но вы не сможете изменить язык интерфейса. - + Qv2ray Cannot Continue Qv2ray не может продолжить - + You are running a lower version of Qv2ray compared to the current config file. Вы используете более низкую версию Qv2ray по сравнению с текущим файлом конфигурации. - + Please check if there's an issue explaining about it. Пожалуйста, проверьте, есть ли проблема с объяснением этого. - + Or submit a new issue if you think this is an error. Или отправьте новую проблему, если вы считаете, что это ошибка. - + Dependency Missing Зависимость отсутствует - + This could be caused by a missing of `openssl` package in your system. Это может быть вызвано отсутствием пакета `openssl` в вашей системе. - + If you are using an AppImage from Github Action, please report a bug. Если вы используете AppImage из Github Action, пожалуйста, сообщите об ошибке. - + Cannot find openssl libs Не удается найти openssl libs @@ -2551,12 +2551,12 @@ p, li { white-space: pre-wrap; } - + Debug version - + Technical Details Технические детали @@ -2775,25 +2775,25 @@ p, li { white-space: pre-wrap; } - + Deprecated - + PAC is now deprecated and is not encouraged to be used anymore. - + It will be removed or be provided as a plugin in the future. - + PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible. @@ -3486,21 +3486,11 @@ p, li { white-space: pre-wrap; } Use built-in route schemes - - - Built-in Schemes - - Import route scheme from file - - - Import Scheme - - Export route scheme to file @@ -3508,12 +3498,76 @@ p, li { white-space: pre-wrap; } - Export Scheme + Built-in Schemes... - Coming soon! + Import Scheme... + + + + + Export Scheme... + + + + + RouteSettingsMatrixWidget + + + empty scheme + + + + + v2rayN preset + + + + + Import scheme '%1' by '%2'? + + + + + Importing Scheme + + + + + Exporting Scheme + + + + + Scheme name: + + + + + Unnamed Scheme + + + + + Author: + + + + + Description: + + + + + The author is too lazy to leave a comment + + + + + + QvRoute Schemes(*.json) @@ -3754,22 +3808,22 @@ p, li { white-space: pre-wrap; } Не удалось обработать результат из апстрима, проверьте ваш URL. - + Reload Subscription - + Would you like to reload the subscription? - + Deleting a subscription - + All connections will be moved to default group, do you want to continue? diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index 4c4013f2..5a936852 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -320,42 +320,42 @@ 取消 - + Select file to import 选择要导入的文件 - + Capture QRCode 抓取二维码 - + Cannot find a valid QRCode from this region. 无法从这个区域找到有效的二维码。 - + Import config file 导入配置文件 - + Failed to check the validity of the config file. 检查配置文件有效性时失败。 - + Select an image to import 选择要导入的图像 - + QRCode scanning failed 二维码扫描失败 - + Cannot find any QRCode from the image. 无法从图像中找到任何二维码。 @@ -1257,11 +1257,11 @@ PreferencesWindow - - - - - + + + + + Preferences 首选项 @@ -1651,13 +1651,13 @@ - + Bold 粗体 - + Italic 斜体 @@ -1782,13 +1782,13 @@ 项目 - - + + Enable tProxy Support 启用 tProxy 支持 - + to this path: 到此路径: @@ -1798,115 +1798,115 @@ Qv2ray 的网络工具栏已被禁用,请使用 --withToolbarPlugin 来启用。 - + Duplicated port numbers detected, please check the port number settings. 检测到重复的端口号,请检查端口号设置。 - + Invalid inbound listening address. 入站监听地址不可用。 - + Open V2ray assets folder 打开 V2ray 资源文件夹 - + Open V2ray core file 打开 V2ray 核心文件 - + This will append capabilities to the V2ray executable. 这会将功能附加到 V2ray 可执行文件。 - + Qv2ray will copy your V2ray core to this path: Qv2ray 会将您的 V2ray 核心复制到以下路径: - + If anything goes wrong after enabling this, please check issue #57 or the link below: 如果有出现任何问题,请参阅 Issue #57 或以下链接: - + Qv2ray cannot copy one or both V2ray files from: Qv2ray 无法从以下位置复制一个或两个 V2ray 文件: - - + + Failed to setcap onto V2ray executable. You may need to run `setcap` manually. 无法将 Capcap 设置到 V2ray 可执行文件上。 您可能需要手动运行“ setcap”。 - + tProxy is not supported on macOS and Windows 在 macOS 和 Windows 上不支持 tProxy - + Apply network toolbar settings 应用网络工具栏设置 - + All other modified settings will be applied as well after this object. 已经编辑的其它设置也会被同时应用。 - + Do you want to continue? 你想继续吗? - + Select GFWList in base64 选择 base64 格式的 GFWList - - + + Download GFWList 下载 GFWList - + Operation is cancelled. 操作已经取消 - + Successfully downloaded GFWList. 下载 GFWList 成功。 - + Start with boot 开机启动 - + Failed to set auto start option. 无法设置自动启动选项。 - - + + V2ray Core Settings V2ray 核心设置 - + V2ray path configuration check passed. V2ray 路径配置检查通过。 - + Current version of V2ray is: V2ray 当前版本是: @@ -2113,7 +2113,7 @@ p, li { white-space: pre-wrap; } - + Qv2ray will now exit. Qv2ray 现在将退出。 @@ -2128,57 +2128,57 @@ p, li { white-space: pre-wrap; } 如果您认为它是一个bug,请'报告。 - + You cannot run Qv2ray as root, please use --I-just-wanna-run-with-root if you REALLY want to do so. 您不能以root用户身份运行Qv2ray,如果您确实想这样做,请使用 --I-just-wanna-run-with-root。 - + --> USE IT AT YOUR OWN RISK! --> 请自负风险! - + Debug version 调试版 - + Qv2ray Cannot Continue Qv2ray 无法继续 - + You are running a lower version of Qv2ray compared to the current config file. 与当前配置文件相比,您正在运行一个较低版本的 Qv2ray。 - + Please check if there's an issue explaining about it. 请检查是否存在'有关此问题的说明。 - + Or submit a new issue if you think this is an error. 或者如果你认为这是一个错误,请提交一个新问题。 - + Dependency Missing 缺少依赖关系 - + This could be caused by a missing of `openssl` package in your system. 这可能是系统中缺少`openssl`软件包造成的。 - + If you are using an AppImage from Github Action, please report a bug. 如果您使用的是来自 Github Action 的 AppImage,请报告错误。 - + Cannot find openssl libs 找不到 OpenSSL 库 @@ -2198,7 +2198,7 @@ p, li { white-space: pre-wrap; } 一种解决方法是删除此文件并重新启动Qv2ray: - + Technical Details 技术细节 @@ -2237,25 +2237,25 @@ p, li { white-space: pre-wrap; } - + Deprecated 已经过时 - + PAC is now deprecated and is not encouraged to be used anymore. PAC 已经被标记为过时的功能,并且我们不建议您继续使用。 - + It will be removed or be provided as a plugin in the future. 它可能会在将来某个版本被移除,或者作为单独的插件提供。 - + PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible. PAC 目前将会继续工作,但是我们强烈建议您切换使用 V2ray 自带的路由功能。 @@ -3089,9 +3089,8 @@ p, li { white-space: pre-wrap; } 使用预置路由方案 - Built-in Schemes - 预置方案 + 预置方案 @@ -3099,9 +3098,8 @@ p, li { white-space: pre-wrap; } 从文件导入路由方案 - Import Scheme - 导入方案 + 导入方案 @@ -3109,14 +3107,86 @@ p, li { white-space: pre-wrap; } 导出方案到文件 - Export Scheme - 导出方案 + 导出方案 + + + Coming soon! + 即将推出! - Coming soon! - 即将推出! + Built-in Schemes... + 预置方案... + + + + Import Scheme... + 导入方案... + + + + Export Scheme... + 导出方案... + + + + RouteSettingsMatrixWidget + + + empty scheme + 空白方案 + + + + v2rayN preset + v2rayN 方案 + + + + Import scheme '%1' by '%2'? + 要导入 '%2' 的方案 '%1' 吗? + + + + Importing Scheme + 导入方案 + + + + Exporting Scheme + 导出方案 + + + + Scheme name: + 方案名称: + + + + Unnamed Scheme + 无名方案 + + + + Author: + 作者: + + + + Description: + 描述: + + + + The author is too lazy to leave a comment + 作者太懒,没有写描述 + + + + + QvRoute Schemes(*.json) + QvRoute 方案(*.json) @@ -3320,22 +3390,22 @@ p, li { white-space: pre-wrap; } SubscribeEditor - + Reload Subscription 更新订阅 - + Would you like to reload the subscription? 您要更新此订阅吗? - + Deleting a subscription 删除订阅 - + All connections will be moved to default group, do you want to continue? 本订阅中的所有连接都将移动到默认分组,您确定要继续吗?