diff --git a/Build.Counter b/Build.Counter
index b9e5dd76..32884547 100644
--- a/Build.Counter
+++ b/Build.Counter
@@ -1 +1 @@
-540
+682
diff --git a/Qv2ray.pro b/Qv2ray.pro
index f540a4c8..a0723880 100644
--- a/Qv2ray.pro
+++ b/Qv2ray.pro
@@ -25,8 +25,8 @@ write_file("Build.Counter", _BUILD_NUMBER)
DEFINES += QT_DEPRECATED_WARNINGS QV2RAY_VERSION_STRING=\"\\\"v$${VERSION}\\\"\"
SOURCES += \
- src/QvCoreConfigOperations.cpp \
src/main.cpp \
+ src/QvCoreConfigOperations.cpp \
src/QvConfigUpgrade.cpp \
src/QvCoreConfigOperations_Convertion.cpp \
src/QvCoreConfigOperations_Generation.cpp \
@@ -57,7 +57,6 @@ INCLUDEPATH += \
src/ui/ \
src/utils/ \
libs/gen/
-
HEADERS += \
src/Qv2rayBase.hpp \
src/QvCoreConfigObjects.hpp \
@@ -74,6 +73,7 @@ HEADERS += \
src/ui/w_RoutesEditor.hpp \
src/ui/w_SubscriptionEditor.hpp \
src/ui/w_ScreenShot_Core.hpp \
+ src/utils/QvTinyLog.hpp \
src/utils/QJsonModel.hpp \
src/utils/QJsonObjectInsertMacros.h \
src/utils/QObjectMessageProxy.hpp \
@@ -82,8 +82,7 @@ HEADERS += \
src/utils/QvPingModel.hpp \
src/utils/QvRunguard.hpp \
libs/gen/v2ray_api_commands.pb.h \
- libs/gen/v2ray_api_commands.grpc.pb.h \
- src/utils/QvTinyLog.hpp
+ libs/gen/v2ray_api_commands.grpc.pb.h
FORMS += \
src/ui/w_ExportConfig.ui \
@@ -94,8 +93,8 @@ FORMS += \
src/ui/w_OutboundEditor.ui \
src/ui/w_PrefrencesWindow.ui \
src/ui/w_RoutesEditor.ui \
- src/ui/w_SubscriptionEditor.ui \
- src/ui/w_ScreenShot_Core.ui
+ src/ui/w_ScreenShot_Core.ui \
+ src/ui/w_SubscriptionEditor.ui
RESOURCES += \
resources.qrc
@@ -113,8 +112,10 @@ message("| |")
message("| See: https://www.gnu.org/licenses/gpl-3.0.html |")
message("|-------------------------------------------------|")
message(" ")
-RC_ICONS += ./icons/Qv2ray.ico
-ICON = ./icons/Qv2ray.icns
+
+
+RC_ICONS += ./icons/qv2ray.ico
+ICON = ./icons/qv2ray.icns
# ------------------------------------------ Begin checking gRPC and protobuf headers.
!exists(libs/gen/v2ray_api_commands.grpc.pb.h) || !exists(libs/gen/v2ray_api_commands.grpc.pb.cc) || !exists(libs/gen/v2ray_api_commands.pb.h) || !exists(libs/gen/v2ray_api_commands.pb.cc) {
diff --git a/icons/add_connection_btn.png b/icons/add_connection_btn.png
deleted file mode 100644
index 5c19da4b..00000000
Binary files a/icons/add_connection_btn.png and /dev/null differ
diff --git a/icons/add_connection_btn.svg b/icons/add_connection_btn.svg
deleted file mode 100644
index 140c385a..00000000
--- a/icons/add_connection_btn.svg
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
diff --git a/icons/designs/Applogo_Circle.svg b/icons/designs/Applogo_Circle.svg
new file mode 100644
index 00000000..738f6b41
--- /dev/null
+++ b/icons/designs/Applogo_Circle.svg
@@ -0,0 +1,319 @@
+
+
+
+
diff --git a/icons/designs/Applogo_Frameless.svg b/icons/designs/Applogo_Frameless.svg
new file mode 100644
index 00000000..8bb81ca8
--- /dev/null
+++ b/icons/designs/Applogo_Frameless.svg
@@ -0,0 +1,271 @@
+
+
+
+
diff --git a/icons/designs/Applogo_Square.svg b/icons/designs/Applogo_Square.svg
new file mode 100644
index 00000000..b8c4c283
--- /dev/null
+++ b/icons/designs/Applogo_Square.svg
@@ -0,0 +1,383 @@
+
+
+
+
diff --git a/icons/designs/banner.svg b/icons/designs/banner.svg
new file mode 100644
index 00000000..5c2af858
--- /dev/null
+++ b/icons/designs/banner.svg
@@ -0,0 +1,471 @@
+
+
+
+
diff --git a/icons/designs/banner.svg.png b/icons/designs/banner.svg.png
new file mode 100644
index 00000000..d9e4a98f
Binary files /dev/null and b/icons/designs/banner.svg.png differ
diff --git a/icons/edit_connection_btn.png b/icons/edit_connection_btn.png
deleted file mode 100644
index c201cb29..00000000
Binary files a/icons/edit_connection_btn.png and /dev/null differ
diff --git a/icons/edit_connection_btn.svg b/icons/edit_connection_btn.svg
deleted file mode 100644
index df6019df..00000000
--- a/icons/edit_connection_btn.svg
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
diff --git a/icons/import_connection_btn.png b/icons/import_connection_btn.png
deleted file mode 100644
index efb21c3b..00000000
Binary files a/icons/import_connection_btn.png and /dev/null differ
diff --git a/icons/import_connection_btn.svg b/icons/import_connection_btn.svg
deleted file mode 100644
index 00972496..00000000
--- a/icons/import_connection_btn.svg
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
diff --git a/icons/netspeed-arrows.svg b/icons/netspeed-arrows.svg
deleted file mode 100644
index cf0d0029..00000000
--- a/icons/netspeed-arrows.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/icons/qv2ray.icns b/icons/qv2ray.icns
index 9102bdfb..a3d54215 100644
Binary files a/icons/qv2ray.icns and b/icons/qv2ray.icns differ
diff --git a/icons/qv2ray.ico b/icons/qv2ray.ico
index 39157eb7..ba3d41bc 100644
Binary files a/icons/qv2ray.ico and b/icons/qv2ray.ico differ
diff --git a/icons/qv2ray.png b/icons/qv2ray.png
index d1c3e07d..e12ad919 100644
Binary files a/icons/qv2ray.png and b/icons/qv2ray.png differ
diff --git a/icons/qv2ray.xcf b/icons/qv2ray.xcf
deleted file mode 100644
index ec0ce043..00000000
Binary files a/icons/qv2ray.xcf and /dev/null differ
diff --git a/icons/remove_connection_btn.png b/icons/remove_connection_btn.png
deleted file mode 100644
index aebcf977..00000000
Binary files a/icons/remove_connection_btn.png and /dev/null differ
diff --git a/icons/remove_connection_btn.svg b/icons/remove_connection_btn.svg
deleted file mode 100644
index 4cefec16..00000000
--- a/icons/remove_connection_btn.svg
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
-
diff --git a/icons/remove_connection_btn_red.png b/icons/remove_connection_btn_red.png
deleted file mode 100644
index 5bfc94ba..00000000
Binary files a/icons/remove_connection_btn_red.png and /dev/null differ
diff --git a/icons/ui_dark/add.png b/icons/ui_dark/add.png
new file mode 100644
index 00000000..fa0f056e
Binary files /dev/null and b/icons/ui_dark/add.png differ
diff --git a/icons/ui_dark/delete.png b/icons/ui_dark/delete.png
new file mode 100644
index 00000000..ffef336b
Binary files /dev/null and b/icons/ui_dark/delete.png differ
diff --git a/icons/ui_dark/design/add.svg b/icons/ui_dark/design/add.svg
new file mode 100644
index 00000000..08beefbd
--- /dev/null
+++ b/icons/ui_dark/design/add.svg
@@ -0,0 +1,145 @@
+
+
+
+
diff --git a/icons/ui_dark/design/delete.svg b/icons/ui_dark/design/delete.svg
new file mode 100644
index 00000000..3838d69f
--- /dev/null
+++ b/icons/ui_dark/design/delete.svg
@@ -0,0 +1,153 @@
+
+
+
+
diff --git a/icons/ui_dark/design/duplicate.svg b/icons/ui_dark/design/duplicate.svg
new file mode 100644
index 00000000..e00d526f
--- /dev/null
+++ b/icons/ui_dark/design/duplicate.svg
@@ -0,0 +1,166 @@
+
+
+
+
diff --git a/icons/ui_dark/design/edit.svg b/icons/ui_dark/design/edit.svg
new file mode 100644
index 00000000..11102a86
--- /dev/null
+++ b/icons/ui_dark/design/edit.svg
@@ -0,0 +1,213 @@
+
+
+
+
diff --git a/icons/ui_dark/design/import.svg b/icons/ui_dark/design/import.svg
new file mode 100644
index 00000000..9044bde1
--- /dev/null
+++ b/icons/ui_dark/design/import.svg
@@ -0,0 +1,151 @@
+
+
+
+
diff --git a/icons/ui_dark/design/json.svg b/icons/ui_dark/design/json.svg
new file mode 100644
index 00000000..9460eeeb
--- /dev/null
+++ b/icons/ui_dark/design/json.svg
@@ -0,0 +1,170 @@
+
+
+
+
diff --git a/icons/ui_dark/design/netspeed_arrow.svg b/icons/ui_dark/design/netspeed_arrow.svg
new file mode 100644
index 00000000..f03da8b7
--- /dev/null
+++ b/icons/ui_dark/design/netspeed_arrow.svg
@@ -0,0 +1,162 @@
+
+
+
+
diff --git a/icons/ui_dark/design/ping_gauge.svg b/icons/ui_dark/design/ping_gauge.svg
new file mode 100644
index 00000000..32b47d3e
--- /dev/null
+++ b/icons/ui_dark/design/ping_gauge.svg
@@ -0,0 +1,180 @@
+
+
+
+
diff --git a/icons/ui_dark/design/share.svg b/icons/ui_dark/design/share.svg
new file mode 100644
index 00000000..e5d027a6
--- /dev/null
+++ b/icons/ui_dark/design/share.svg
@@ -0,0 +1,160 @@
+
+
+
+
diff --git a/icons/ui_dark/design/tray.svg b/icons/ui_dark/design/tray.svg
new file mode 100644
index 00000000..bd679ad8
--- /dev/null
+++ b/icons/ui_dark/design/tray.svg
@@ -0,0 +1,292 @@
+
+
+
+
diff --git a/icons/ui_dark/duplicate.png b/icons/ui_dark/duplicate.png
new file mode 100644
index 00000000..98ba56f4
Binary files /dev/null and b/icons/ui_dark/duplicate.png differ
diff --git a/icons/ui_dark/edit.png b/icons/ui_dark/edit.png
new file mode 100644
index 00000000..63442afe
Binary files /dev/null and b/icons/ui_dark/edit.png differ
diff --git a/icons/ui_dark/import.png b/icons/ui_dark/import.png
new file mode 100644
index 00000000..76255de2
Binary files /dev/null and b/icons/ui_dark/import.png differ
diff --git a/icons/ui_dark/json.png b/icons/ui_dark/json.png
new file mode 100644
index 00000000..f95ed9e7
Binary files /dev/null and b/icons/ui_dark/json.png differ
diff --git a/icons/ui_dark/netspeed_arrow.png b/icons/ui_dark/netspeed_arrow.png
new file mode 100644
index 00000000..cb62e58e
Binary files /dev/null and b/icons/ui_dark/netspeed_arrow.png differ
diff --git a/icons/ui_dark/ping_gauge.png b/icons/ui_dark/ping_gauge.png
new file mode 100644
index 00000000..4699a059
Binary files /dev/null and b/icons/ui_dark/ping_gauge.png differ
diff --git a/icons/ui_dark/share.png b/icons/ui_dark/share.png
new file mode 100644
index 00000000..ef8c18e6
Binary files /dev/null and b/icons/ui_dark/share.png differ
diff --git a/icons/ui_dark/tray.png b/icons/ui_dark/tray.png
new file mode 100644
index 00000000..704297f5
Binary files /dev/null and b/icons/ui_dark/tray.png differ
diff --git a/icons/ui_light/add.png b/icons/ui_light/add.png
new file mode 100644
index 00000000..fadb12d8
Binary files /dev/null and b/icons/ui_light/add.png differ
diff --git a/icons/ui_light/delete.png b/icons/ui_light/delete.png
new file mode 100644
index 00000000..0a7c766b
Binary files /dev/null and b/icons/ui_light/delete.png differ
diff --git a/icons/ui_light/design/add.svg b/icons/ui_light/design/add.svg
new file mode 100644
index 00000000..fc4951ba
--- /dev/null
+++ b/icons/ui_light/design/add.svg
@@ -0,0 +1,145 @@
+
+
+
+
diff --git a/icons/ui_light/design/delete.svg b/icons/ui_light/design/delete.svg
new file mode 100644
index 00000000..e56c7d69
--- /dev/null
+++ b/icons/ui_light/design/delete.svg
@@ -0,0 +1,153 @@
+
+
+
+
diff --git a/icons/ui_light/design/duplicate.svg b/icons/ui_light/design/duplicate.svg
new file mode 100644
index 00000000..19b420b8
--- /dev/null
+++ b/icons/ui_light/design/duplicate.svg
@@ -0,0 +1,166 @@
+
+
+
+
diff --git a/icons/ui_light/design/edit.svg b/icons/ui_light/design/edit.svg
new file mode 100644
index 00000000..8da1cf51
--- /dev/null
+++ b/icons/ui_light/design/edit.svg
@@ -0,0 +1,213 @@
+
+
+
+
diff --git a/icons/ui_light/design/import.svg b/icons/ui_light/design/import.svg
new file mode 100644
index 00000000..49228e6a
--- /dev/null
+++ b/icons/ui_light/design/import.svg
@@ -0,0 +1,150 @@
+
+
+
+
diff --git a/icons/ui_light/design/json.svg b/icons/ui_light/design/json.svg
new file mode 100644
index 00000000..40f87b22
--- /dev/null
+++ b/icons/ui_light/design/json.svg
@@ -0,0 +1,168 @@
+
+
+
+
diff --git a/icons/ui_light/design/netspeed_arrow.svg b/icons/ui_light/design/netspeed_arrow.svg
new file mode 100644
index 00000000..67f15913
--- /dev/null
+++ b/icons/ui_light/design/netspeed_arrow.svg
@@ -0,0 +1,162 @@
+
+
+
+
diff --git a/icons/ui_light/design/ping_gauge.svg b/icons/ui_light/design/ping_gauge.svg
new file mode 100644
index 00000000..66c608cd
--- /dev/null
+++ b/icons/ui_light/design/ping_gauge.svg
@@ -0,0 +1,180 @@
+
+
+
+
diff --git a/icons/ui_light/design/share.svg b/icons/ui_light/design/share.svg
new file mode 100644
index 00000000..1bbbec0c
--- /dev/null
+++ b/icons/ui_light/design/share.svg
@@ -0,0 +1,160 @@
+
+
+
+
diff --git a/icons/ui_light/design/tray.svg b/icons/ui_light/design/tray.svg
new file mode 100644
index 00000000..3126b9ac
--- /dev/null
+++ b/icons/ui_light/design/tray.svg
@@ -0,0 +1,344 @@
+
+
+
+
diff --git a/icons/ui_light/duplicate.png b/icons/ui_light/duplicate.png
new file mode 100644
index 00000000..41dce418
Binary files /dev/null and b/icons/ui_light/duplicate.png differ
diff --git a/icons/ui_light/edit.png b/icons/ui_light/edit.png
new file mode 100644
index 00000000..c1a49da0
Binary files /dev/null and b/icons/ui_light/edit.png differ
diff --git a/icons/ui_light/import.png b/icons/ui_light/import.png
new file mode 100644
index 00000000..f66ab848
Binary files /dev/null and b/icons/ui_light/import.png differ
diff --git a/icons/ui_light/json.png b/icons/ui_light/json.png
new file mode 100644
index 00000000..264c3d4d
Binary files /dev/null and b/icons/ui_light/json.png differ
diff --git a/icons/ui_light/netspeed_arrow.png b/icons/ui_light/netspeed_arrow.png
new file mode 100644
index 00000000..0913db08
Binary files /dev/null and b/icons/ui_light/netspeed_arrow.png differ
diff --git a/icons/ui_light/ping_gauge.png b/icons/ui_light/ping_gauge.png
new file mode 100644
index 00000000..f380662d
Binary files /dev/null and b/icons/ui_light/ping_gauge.png differ
diff --git a/icons/ui_light/share.png b/icons/ui_light/share.png
new file mode 100644
index 00000000..dfa6a4f9
Binary files /dev/null and b/icons/ui_light/share.png differ
diff --git a/icons/ui_light/tray.png b/icons/ui_light/tray.png
new file mode 100644
index 00000000..dbcc105d
Binary files /dev/null and b/icons/ui_light/tray.png differ
diff --git a/resources.qrc b/resources.qrc
index 357ea761..4b17395d 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -1,10 +1,27 @@
+ icons/qv2ray.icns
+ icons/qv2ray.png
icons/qv2ray.ico
- icons/add_connection_btn.png
- icons/import_connection_btn.png
- icons/remove_connection_btn.png
- icons/edit_connection_btn.png
- icons/netspeed-arrows.svg
+ icons/ui_dark/add.png
+ icons/ui_dark/delete.png
+ icons/ui_dark/duplicate.png
+ icons/ui_dark/edit.png
+ icons/ui_dark/import.png
+ icons/ui_dark/json.png
+ icons/ui_dark/netspeed_arrow.png
+ icons/ui_dark/ping_gauge.png
+ icons/ui_dark/share.png
+ icons/ui_light/add.png
+ icons/ui_light/delete.png
+ icons/ui_light/duplicate.png
+ icons/ui_light/edit.png
+ icons/ui_light/import.png
+ icons/ui_light/json.png
+ icons/ui_light/netspeed_arrow.png
+ icons/ui_light/ping_gauge.png
+ icons/ui_light/share.png
+ icons/ui_light/tray.png
+ icons/ui_dark/tray.png
diff --git a/src/Qv2rayBase.hpp b/src/Qv2rayBase.hpp
index 2281e718..9a80ef71 100644
--- a/src/Qv2rayBase.hpp
+++ b/src/Qv2rayBase.hpp
@@ -1,14 +1,22 @@
#ifndef QV2RAYBASE_H
#define QV2RAYBASE_H
#include
+#include
#include
+#include
#include "QvTinyLog.hpp"
#include "QvCoreConfigObjects.hpp"
-#include "QvNetSpeedPlugin.hpp"
#include "QObjectMessageProxy.hpp"
#define QV2RAY_CONFIG_VERSION 9
+
+// Linux DEs should handle the ui schemes themselves.
+// --> Or.. should we change this into a modifyable setting?
+#ifdef Q_OS_LINUX
+#define QV2RAY_USE_BUILTIN_DARKTHEME false
+#else
#define QV2RAY_USE_BUILTIN_DARKTHEME true
+#endif
// Base folder suffix.
#ifdef QT_DEBUG
@@ -39,19 +47,21 @@
#define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log"
// GUI TOOLS
+#define QV2RAY_IS_DARKTHEME (GetGlobalConfig().UISettings.useDarkTheme)
#define RED(obj) \
auto _temp = obj->palette(); \
_temp.setColor(QPalette::Text, Qt::red); \
obj->setPalette(_temp);
-// TODO: Dark mode support.
#define BLACK(obj) \
auto _temp = obj->palette(); \
- _temp.setColor(QPalette::Text, Qt::blue); \
+ _temp.setColor(QPalette::Text, QV2RAY_IS_DARKTHEME ? Qt::white : Qt::black); \
obj->setPalette(_temp);
-#define QSTRING(std_string) QString::fromStdString(std_string)
+#define QV2RAY_UI_RESOURCES_ROOT QSTRING(QV2RAY_IS_DARKTHEME ? ":/icons/ui_dark/" : ":/icons/ui_light/")
+#define QICON_R(file) QIcon(QV2RAY_UI_RESOURCES_ROOT + file)
+#define QSTRING(std_string) QString::fromStdString(std_string)
#define NEWLINE "\r\n"
#ifndef MAX
@@ -60,6 +70,44 @@
namespace Qv2ray
{
+ // Extra header for QvConfigUpgrade.cpp
+ QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root);
+
+
+ struct QvBarLine {
+ std::string Family;
+ bool Bold;
+ bool Italic;
+ int ColorA;
+ int ColorR;
+ int ColorG;
+ int ColorB;
+ int ContentType;
+ double Size;
+ std::string Message;
+ QvBarLine()
+ : Family("Consolas")
+ , Bold(true)
+ , Italic(false)
+ , ColorA(255), ColorR(255), ColorG(255), ColorB(255)
+ , ContentType(0)
+ , Size(9),
+ Message() { }
+ XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
+ };
+
+ struct QvBarPage {
+ int OffsetYpx;
+ vector Lines;
+ XTOSTRUCT(O(OffsetYpx, Lines))
+ QvBarPage() : OffsetYpx(5) { }
+ };
+
+ struct QvNetSpeedBarConfig {
+ std::vector Pages;
+ XTOSTRUCT(O(Pages))
+ };
+
namespace QvConfigModels
{
struct Qv2rayCoreInboundsConfig {
@@ -90,7 +138,8 @@ namespace Qv2ray
string theme;
string language;
bool useDarkTheme;
- XTOSTRUCT(O(theme, language, useDarkTheme))
+ bool useDarkTrayIcon;
+ XTOSTRUCT(O(theme, language, useDarkTheme, useDarkTrayIcon))
};
struct Qv2rayConfig {
@@ -182,8 +231,6 @@ namespace Qv2ray
speedBarConfig))
};
- // Extra header for QvConfigUpgrade.cpp
- QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root);
}
}
diff --git a/src/QvConfigUpgrade.cpp b/src/QvConfigUpgrade.cpp
index f3a8984d..81eee249 100644
--- a/src/QvConfigUpgrade.cpp
+++ b/src/QvConfigUpgrade.cpp
@@ -9,110 +9,106 @@
namespace Qv2ray
{
- namespace QvConfigModels
+ // Private member
+ QJsonObject UpgradeConfig_Inc(int fromVersion, QJsonObject root)
{
- // Private member
- QJsonObject UpgradeConfig_Inc(int fromVersion, QJsonObject root)
- {
- switch (fromVersion) {
- case 1: {
- auto v1_oldConfigVersion = root["config_version"].toString();
- // From 1 to 2, we changed the config_version from 'string' to 'int'
- root.remove("config_version");
- root["config_version"] = 2;
- UPDATELOG("Upgrading config_version from old value " + v1_oldConfigVersion.toStdString() + " to 2")
- break;
- }
+ switch (fromVersion) {
+ case 1: {
+ auto v1_oldConfigVersion = root["config_version"].toString();
+ // From 1 to 2, we changed the config_version from 'string' to 'int'
+ root.remove("config_version");
+ root["config_version"] = 2;
+ UPDATELOG("Upgrading config_version from old value " + v1_oldConfigVersion.toStdString() + " to 2")
+ break;
+ }
- case 2 : {
- // We copied those files.
- auto vCoreFilePath = root["v2CorePath"].toString();
- auto vCoreDestPath = QV2RAY_DEFAULT_VCORE_PATH;
- // We also need v2ctl
- auto v2CtlFilePath = QFileInfo(vCoreFilePath).dir().path() + "/v2ctl";
- auto v2CtlDestPath = QFileInfo(vCoreDestPath).dir().path() + "/v2ctl";
+ case 2 : {
+ // We copied those files.
+ auto vCoreFilePath = root["v2CorePath"].toString();
+ auto vCoreDestPath = QV2RAY_DEFAULT_VCORE_PATH;
+ // We also need v2ctl
+ auto v2CtlFilePath = QFileInfo(vCoreFilePath).dir().path() + "/v2ctl";
+ auto v2CtlDestPath = QFileInfo(vCoreDestPath).dir().path() + "/v2ctl";
#ifdef Q_OS_WIN
- v2CtlFilePath = v2CtlFilePath.append(".exe");
- v2CtlDestPath = v2CtlDestPath.append(".exe");
+ v2CtlFilePath = v2CtlFilePath.append(".exe");
+ v2CtlDestPath = v2CtlDestPath.append(".exe");
#endif
- QFile::copy(vCoreFilePath, vCoreDestPath);
- QFile::copy(v2CtlFilePath, v2CtlDestPath);
- root.remove("v2CorePath");
- UPDATELOG("v2CorePath value from: " + vCoreFilePath.toStdString() + " to " + vCoreDestPath.toStdString())
- UPDATELOG("v2CtlFilePath value from: " + v2CtlFilePath.toStdString() + " to " + v2CtlDestPath.toStdString())
- break;
- }
-
- case 3 : {
- // We changed a key name in the config file.
- //proxyDefault
- auto oldProxyDefault = root["proxyDefault"].toBool();
- root.remove("proxyDefault");
- root["enableProxy"] = oldProxyDefault;
- //enableProxy
- UPDATELOG("key: proxyDefault->enableProxy, value from: " + to_string(oldProxyDefault) + " to " + to_string(oldProxyDefault))
- break;
- }
-
- // --------------------------------------------------------------------------------------
- // Below is for version 2
- case 4: {
- // From 2 to 3, we changed the "proxyCN" to "bypassCN" as it's easier to understand....
- auto v2_oldProxyCN = root["proxyCN"].toBool();
- root.remove("proxyCN");
- root.insert("bypassCN", !v2_oldProxyCN);
- UPDATELOG("Upgrading proxyCN to bypassCN and changed the value to " + to_string(!v2_oldProxyCN))
- break;
- }
-
- case 5: {
- auto v3_oldrunAsRoot = root["runAsRoot"].toBool();
- // From 3 to 4, we changed 'runAsRoot' to 'tProxySupport'
- root.remove("runAsRoot");
- root.insert("tProxySupport", v3_oldrunAsRoot);
- UPDATELOG("Upgrading runAsRoot to tProxySupport, the value is not changed: " + to_string(v3_oldrunAsRoot))
- break;
- }
-
- case 6: {
- root["enableStats"] = true;
- UPDATELOG("Default statistics enabled.")
- break;
- }
-
- case 7: {
- QString path;
- path = QV2RAY_DEFAULT_VCORE_PATH;
- root["v2CorePath"] = path;
- UPDATELOG("Added v2CorePath to the config file.")
- break;
- }
-
- case 8: {
- auto lang = root["language"].toString();
- QJsonObject uiSettings;
- uiSettings["language"] = lang;
- root["UISettings"] = uiSettings;
- UPDATELOG("Reconstructing config file.")
- break;
- }
+ QFile::copy(vCoreFilePath, vCoreDestPath);
+ QFile::copy(v2CtlFilePath, v2CtlDestPath);
+ root.remove("v2CorePath");
+ UPDATELOG("v2CorePath value from: " + vCoreFilePath.toStdString() + " to " + vCoreDestPath.toStdString())
+ UPDATELOG("v2CtlFilePath value from: " + v2CtlFilePath.toStdString() + " to " + v2CtlDestPath.toStdString())
+ break;
}
- root["config_version"] = root["config_version"].toInt() + 1;
- return root;
- }
-
- // Exported function
- QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root)
- {
- LOG(MODULE_CONFIG, "Migrating config from version " + to_string(fromVersion) + " to " + to_string(toVersion))
-
- for (int i = fromVersion; i < toVersion; i++) {
- root = UpgradeConfig_Inc(i, root);
+ case 3 : {
+ // We changed a key name in the config file.
+ //proxyDefault
+ auto oldProxyDefault = root["proxyDefault"].toBool();
+ root.remove("proxyDefault");
+ root["enableProxy"] = oldProxyDefault;
+ //enableProxy
+ UPDATELOG("key: proxyDefault->enableProxy, value from: " + to_string(oldProxyDefault) + " to " + to_string(oldProxyDefault))
+ break;
}
- return root;
+ // --------------------------------------------------------------------------------------
+ // Below is for version 2
+ case 4: {
+ // From 2 to 3, we changed the "proxyCN" to "bypassCN" as it's easier to understand....
+ auto v2_oldProxyCN = root["proxyCN"].toBool();
+ root.remove("proxyCN");
+ root.insert("bypassCN", !v2_oldProxyCN);
+ UPDATELOG("Upgrading proxyCN to bypassCN and changed the value to " + to_string(!v2_oldProxyCN))
+ break;
+ }
+
+ case 5: {
+ auto v3_oldrunAsRoot = root["runAsRoot"].toBool();
+ // From 3 to 4, we changed 'runAsRoot' to 'tProxySupport'
+ root.remove("runAsRoot");
+ root.insert("tProxySupport", v3_oldrunAsRoot);
+ UPDATELOG("Upgrading runAsRoot to tProxySupport, the value is not changed: " + to_string(v3_oldrunAsRoot))
+ break;
+ }
+
+ case 6: {
+ root["enableStats"] = true;
+ UPDATELOG("Default statistics enabled.")
+ break;
+ }
+
+ case 7: {
+ QString path;
+ path = QV2RAY_DEFAULT_VCORE_PATH;
+ root["v2CorePath"] = path;
+ UPDATELOG("Added v2CorePath to the config file.")
+ break;
+ }
+
+ case 8: {
+ auto lang = root["language"].toString();
+ QJsonObject uiSettings;
+ uiSettings["language"] = lang;
+ root["UISettings"] = uiSettings;
+ UPDATELOG("Reconstructing config file.")
+ break;
+ }
}
+ root["config_version"] = root["config_version"].toInt() + 1;
+ return root;
+ }
+
+ // Exported function
+ QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root)
+ {
+ LOG(MODULE_CONFIG, "Migrating config from version " + to_string(fromVersion) + " to " + to_string(toVersion))
+
+ for (int i = fromVersion; i < toVersion; i++) {
+ root = UpgradeConfig_Inc(i, root);
+ }
+
+ return root;
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 3dd9ce1f..08bed569 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,6 +2,7 @@
#include
#include
#include
+#include
#include
#include "QvUtils.hpp"
@@ -136,32 +137,40 @@ int main(int argc, char *argv[])
{
// This line must be called before any other ones.
QApplication _qApp(argc, argv);
+ //
+ // Install a default translater. From the OS/DE
+ auto _lang = QLocale::system().name().replace("_", "-");
+ bool _result_ = qApp->installTranslator(getTranslator(_lang));
+ LOG(MODULE_UI, "Installing a tranlator from OS: " + _lang.toStdString() + " -- " + (_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 NEWLINE
- "Libraries that are used in Qv2ray and their authors are listed below:" NEWLINE
- "QJsonModel: Copyright (c) 2011 SCHUTZ Sacha" NEWLINE
- "Qv2ray Current Developer Copyright (C) 2019 Leroy.H.Y (@lhy0403)" NEWLINE
- "Hv2ray Initial Designs & gRPC implementation Copyright (C) 2019 Hork (@aliyuchang33)" NEWLINE
- "Hv2ray/Qv2ray HTTP Request Helper (partial) Copyright 2019 (C) SOneWinstone (@SoneWinstone)" NEWLINE
+ "under certain conditions." NEWLINE NEWLINE
+ "Copyright (C) 2019 Leroy.H.Y (@lhy0403): Qv2ray Current Developer" NEWLINE
+ "Copyright (C) 2019 Hork (@aliyuchang33): Hv2ray Initial Designs & gRPC implementation " NEWLINE
+ "Copyright (C) 2019 SOneWinstone (@SoneWinstone): Hv2ray/Qv2ray HTTP Request Helper" NEWLINE
"Qv2ray ArtWork Done By ArielAxionL (@axionl)" NEWLINE
- "Qv2ray Russian Translations By TheBadGateway (@thebadgateway)" NEWLINE
- "Qv2ray patch 8a8c1a By Riko (@rikakomoe)" NEWLINE
+ "TheBadGateway (@thebadgateway): Qv2ray Russian Translations" NEWLINE
+ "Riko (@rikakomoe): Qv2ray patch 8a8c1a/PR115"
+ NEWLINE NEWLINE
+ "Libraries that have been used in Qv2ray are listed below (Sorted by date added):" NEWLINE
+ "Copyright (c) 2019 dridk (@dridk): X2Struct (Apache)" NEWLINE
+ "Copyright (c) 2011 SCHUTZ Sacha (@dridk): QJsonModel (MIT)" NEWLINE
+ "Copyright (c) 2019 Nikolaos Ftylitakis (@ftylitak): QZXing (Apache2)" NEWLINE
+ "Copyright (c) 2016 Singein (@Singein): ScreenShot (MIT)" NEWLINE
NEWLINE
"Qv2ray " QV2RAY_VERSION_STRING " running on " +
- (QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture()).toStdString() +
- NEWLINE)
+ (QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture()).toStdString() + NEWLINE)
//
LOG(MODULE_INIT, "Qv2ray Start Time: " + QString::number(QTime::currentTime().msecsSinceStartOfDay()).toStdString())
- DEBUG("DEBUG", "============================== This is a debug build, many features are not stable enough. ==============================")
+ DEBUG("DEBUG", "WARNING: ============================== This is a debug build, many features are not stable enough. ==============================")
//
// Initialise the language list.
auto langs = GetFileList(QDir(":/translations"));
if (langs.empty()) {
LOG(MODULE_INIT, "FAILED to find any translations. THIS IS A BUILD ERROR.")
- QvMessageBox(nullptr, "Cannot load languages", "Qv2ray will continue running, but you cannot change the UI language.");
+ QvMessageBox(nullptr, QObject::tr("Cannot load languages"), QObject::tr("Qv2ray will continue running, but you cannot change the UI language."));
} else {
for (auto lang : langs) {
LOG(MODULE_INIT, "Found Translator: " + lang.toStdString())
@@ -201,7 +210,7 @@ int main(int argc, char *argv[])
QObject::tr("Qv2ray will now exit."));
return -3;
} else if (confVersion != newVersion) {
- conf = UpgradeConfig(confVersion.toInt(), QV2RAY_CONFIG_VERSION, conf);
+ conf = Qv2ray::UpgradeConfig(confVersion.toInt(), QV2RAY_CONFIG_VERSION, conf);
}
auto confObject = StructFromJsonString(JsonToString(conf));
@@ -291,6 +300,7 @@ int main(int argc, char *argv[])
MainWindow w;
return _qApp.exec();
} catch (std::exception *ex) {
+ QvMessageBox(nullptr, "ERROR", QSTRING(ex->what()));
LOG(MODULE_INIT, ex->what())
return -9;
}
diff --git a/src/ui/w_ExportConfig.ui b/src/ui/w_ExportConfig.ui
index 5eae2daf..13b27563 100644
--- a/src/ui/w_ExportConfig.ui
+++ b/src/ui/w_ExportConfig.ui
@@ -6,8 +6,8 @@
0
0
- 549
- 493
+ 532
+ 666
@@ -23,7 +23,7 @@
- :/icons/qv2ray.ico
+ :/icons/qv2ray.png
false
diff --git a/src/ui/w_ImportConfig.cpp b/src/ui/w_ImportConfig.cpp
index 257be1f3..b90df9f1 100644
--- a/src/ui/w_ImportConfig.cpp
+++ b/src/ui/w_ImportConfig.cpp
@@ -39,7 +39,7 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
{
// QRubberBand
QThread::msleep(static_cast(doubleSpinBox->value() * 1000));
- bool hasVmessDetected = false;
+ //bool hasVmessDetected = false;
//for (auto screen : qApp->screens()) {
// if (!screen) {
// LOG(MODULE_UI, "Cannot even find a screen. RARE")
@@ -54,8 +54,9 @@ void ImportConfigWindow::on_qrFromScreenBtn_clicked()
if (w.result() == QDialog::Accepted) {
auto str = QZXing().decodeImage(pix);
- if (str.isEmpty()) {
+ if (str.trimmed().isEmpty()) {
LOG(MODULE_UI, "Cannot decode QR Code from an image, size: h=" + to_string(pix.width()) + ", v=" + to_string(pix.height()))
+ QvMessageBox(this, tr("Capture QRCode"), tr("Cannot find a valid QRCode from this region."));
// continue;
} else {
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
@@ -240,3 +241,31 @@ void ImportConfigWindow::on_editFileBtn_clicked()
LOG(MODULE_FILE, "Canceled saving a file.")
}
}
+
+void ImportConfigWindow::on_connectionEditBtn_clicked()
+{
+ OutboundEditor *w = new OutboundEditor(this);
+ auto outboundEntry = w->OpenEditor();
+ bool isChanged = w->result() == QDialog::Accepted;
+ QString alias = w->GetFriendlyName();
+ delete w;
+
+ if (isChanged) {
+ QJsonArray outboundsList;
+ outboundsList.push_back(outboundEntry);
+ QJsonObject root;
+ root.insert("outbounds", outboundsList);
+ //
+ // WARN This one will change the connection name, because of some duplicates.
+ SaveConnectionConfig(root, &alias, false);
+ //
+ auto conf = GetGlobalConfig();
+ auto connectionList = conf.configs;
+ connectionList.push_back(alias.toStdString());
+ conf.configs = connectionList;
+ SetGlobalConfig(conf);
+ close();
+ } else {
+ return;
+ }
+}
diff --git a/src/ui/w_ImportConfig.hpp b/src/ui/w_ImportConfig.hpp
index 0be46d33..315ddffc 100644
--- a/src/ui/w_ImportConfig.hpp
+++ b/src/ui/w_ImportConfig.hpp
@@ -25,6 +25,8 @@ class ImportConfigWindow : public QDialog, private Ui::ImportConfigWindow
void on_editFileBtn_clicked();
+ void on_connectionEditBtn_clicked();
+
private:
QMap vmessErrors;
};
diff --git a/src/ui/w_ImportConfig.ui b/src/ui/w_ImportConfig.ui
index 5cecb7d3..34f9071b 100644
--- a/src/ui/w_ImportConfig.ui
+++ b/src/ui/w_ImportConfig.ui
@@ -68,6 +68,11 @@
Subscription Link
+ -
+
+ Manually Input
+
+
@@ -154,7 +159,7 @@
-
- From QRCode
+ From QRCode File
@@ -278,14 +283,14 @@
-
- TextLabel
+ Error List
-
- TextLabel
+ VMess
@@ -325,6 +330,31 @@
+
+
+ -
+
+
+ Connection Editor
+
+
+
+ -
+
+
+ Open Connection Editor
+
+
+
+ -
+
+
+ Maunally input connection details
+
+
+
+
+
diff --git a/src/ui/w_MainWindow.cpp b/src/ui/w_MainWindow.cpp
index 3fd7a05d..a066bc70 100644
--- a/src/ui/w_MainWindow.cpp
+++ b/src/ui/w_MainWindow.cpp
@@ -37,8 +37,20 @@ MainWindow::MainWindow(QWidget *parent)
auto conf = GetGlobalConfig();
vinstance = new Qv2Instance(this);
setupUi(this);
- this->setWindowIcon(QIcon(":/icons/qv2ray.ico"));
- hTray->setIcon(this->windowIcon());
+ //
+ this->setWindowIcon(QIcon(":/icons/qv2ray.png"));
+ hTray->setIcon(QIcon(conf.UISettings.useDarkTrayIcon ? ":/icons/ui_dark/tray.png" : ":/icons/ui_light/tray.png"));
+ importConfigButton->setIcon(QICON_R("import.png"));
+ duplicateBtn->setIcon(QICON_R("duplicate.png"));
+ removeConfigButton->setIcon(QICON_R("delete.png"));
+ editConfigButton->setIcon(QICON_R("edit.png"));
+ editJsonBtn->setIcon(QICON_R("json.png"));
+ //
+ pingTestBtn->setIcon(QICON_R("ping_gauge.png"));
+ shareBtn->setIcon(QICON_R("share.png"));
+ updownImageBox->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
+ updownImageBox_2->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
+ //
hTray->setToolTip(TRAY_TOOLTIP_PREFIX);
//
QAction *action_Tray_ShowHide = new QAction(this->windowIcon(), tr("Hide"), this);
@@ -49,8 +61,8 @@ MainWindow::MainWindow(QWidget *parent)
//
QAction *action_RCM_RenameConnection = new QAction(tr("Rename"), this);
QAction *action_RCM_StartThis = new QAction(tr("Connect to this"), this);
- QAction *action_RCM_EditJson = new QAction(tr("Edit as Json"), this);
- QAction *action_RCM_ShareQR = new QAction(tr("Share as QRCode/vmess Uri"), this);
+ QAction *action_RCM_EditJson = new QAction(QICON_R("json.png"), tr("Edit as Json"), this);
+ QAction *action_RCM_ShareQR = new QAction(QICON_R("share.png"), tr("Share as QRCode/VMess URL"), this);
//
action_Tray_Start->setEnabled(true);
action_Tray_Stop->setEnabled(false);
@@ -91,7 +103,7 @@ MainWindow::MainWindow(QWidget *parent)
LoadConnections();
QObject::connect(&HTTPRequestHelper, &QvHttpRequestHelper::httpRequestFinished, this, &MainWindow::VersionUpdate);
HTTPRequestHelper.get("https://api.github.com/repos/lhy0403/Qv2ray/releases/latest");
- bool hasAutoStart = false;
+ bool hasAutoStart = false;
//
// For charts
uploadSerie = new QSplineSeries(this);
@@ -571,40 +583,11 @@ void MainWindow::on_removeConfigButton_clicked()
void MainWindow::on_importConfigButton_clicked()
{
- // TODO
ImportConfigWindow *w = new ImportConfigWindow(this);
w->exec();
OnConfigListChanged(false);
}
-void MainWindow::on_addConfigButton_clicked()
-{
- OutboundEditor *w = new OutboundEditor(this);
- connect(w, &OutboundEditor::s_reload_config, this, &MainWindow::OnConfigListChanged);
- auto outboundEntry = w->OpenEditor();
- bool isChanged = w->result() == QDialog::Accepted;
- QString alias = w->GetFriendlyName();
- delete w;
-
- if (isChanged) {
- QJsonArray outboundsList;
- outboundsList.push_back(outboundEntry);
- QJsonObject root;
- root.insert("outbounds", outboundsList);
- //
- // WARN This one will change the connection name, because of some duplicates.
- SaveConnectionConfig(root, &alias, false);
- //
- auto conf = GetGlobalConfig();
- auto connectionList = conf.configs;
- connectionList.push_back(alias.toStdString());
- conf.configs = connectionList;
- SetGlobalConfig(conf);
- OnConfigListChanged(false);
- ShowAndSetConnection(CurrentConnectionName, false, false);
- }
-}
-
void MainWindow::on_editConfigButton_clicked()
{
// Check if we have a connection selected...
@@ -705,7 +688,7 @@ void MainWindow::on_shareBtn_clicked()
}
}
-void MainWindow::on_action_RCM_ShareQR_triggered()
+void MainWindow::on_action_RCM_ShareQR_triggered(bool checked)
{
on_shareBtn_clicked();
}
diff --git a/src/ui/w_MainWindow.hpp b/src/ui/w_MainWindow.hpp
index 6c46429d..aca8a00b 100644
--- a/src/ui/w_MainWindow.hpp
+++ b/src/ui/w_MainWindow.hpp
@@ -27,7 +27,7 @@ class MainWindow : public QMainWindow, Ui::MainWindow
void UpdateLog();
void OnConfigListChanged(bool need_restart);
private slots:
- void on_action_RCM_ShareQR_triggered();
+ void on_action_RCM_ShareQR_triggered(bool checked = false);
void on_startButton_clicked();
void on_stopButton_clicked();
void on_reconnectButton_clicked();
@@ -56,8 +56,6 @@ class MainWindow : public QMainWindow, Ui::MainWindow
void on_importConfigButton_clicked();
- void on_addConfigButton_clicked();
-
void on_editConfigButton_clicked();
void on_editJsonBtn_clicked();
diff --git a/src/ui/w_MainWindow.ui b/src/ui/w_MainWindow.ui
index 88b7d54b..b6be494f 100644
--- a/src/ui/w_MainWindow.ui
+++ b/src/ui/w_MainWindow.ui
@@ -9,8 +9,8 @@
0
0
- 680
- 585
+ 740
+ 590
@@ -21,8 +21,8 @@
- 680
- 585
+ 740
+ 590
@@ -41,7 +41,7 @@
530
-
+
-
@@ -175,27 +175,7 @@
-
-
-
-
- 0
- 0
-
-
-
- Add new connection manually
-
-
- A
-
-
-
- :/icons/add_connection_btn.png:/icons/add_connection_btn.png
-
-
-
- -
-
+
0
@@ -206,26 +186,34 @@
Import connection
- I
+ Add
-
-
- :/icons/import_connection_btn.png:/icons/import_connection_btn.png
+
+
+ 22
+ 22
+
-
-
+
Duplicate connection
- D
+ Duplicate
+
+
+
+ 22
+ 22
+
-
-
+
0
@@ -236,35 +224,29 @@
Delete a connection
- R
+ Delete
-
-
- :/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
+
+
+ 22
+ 22
+
-
-
+
Edit connection
- ...
+ Edit
-
-
- :/icons/edit_connection_btn.png:/icons/edit_connection_btn.png
-
-
-
- -
-
-
- Edit connection as JSON
-
-
- { }
+
+
+ 22
+ 22
+
@@ -290,7 +272,7 @@
Config Details
-
+
-
-
@@ -365,6 +347,13 @@
+ -
+
+
+ Actions
+
+
+
-
-
@@ -381,17 +370,45 @@
-
-
+
+
+ Edit connection as JSON
+
- Ping
+ Edit JSON
+
+
+
+ 22
+ 22
+
-
-
+
+
+ Ping Test
+
+
+
+ 22
+ 22
+
+
+
+
+ -
+
Share
+
+
+ 22
+ 22
+
+
-
@@ -462,134 +479,124 @@
-
-
+
-
-
-
- Speed
-
-
-
- -
-
-
-
- 32
- 32
-
-
-
-
- 25
- 25
-
-
-
- border-image: url(:/icons/netspeed-arrows.svg) 0 0 0 0 stretch stretch;background-repeat: no-repeat;
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- -
-
-
-
- 8
-
-
-
- 0.00 B/s
+
+
-
+
+
+ Speed
+
+
+
+ -
+
+
+
+ 32
+ 32
+
+
+
+
+ 25
+ 25
+
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ 0.00 B/s
0.00 B/s
-
-
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
- Data
-
-
-
- -
-
-
-
- 32
- 32
-
-
-
-
- 25
- 25
-
-
-
- border-image: url(:/icons/netspeed-arrows.svg) 0 0 0 0 stretch stretch;background-repeat: no-repeat;
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
-
- -
-
-
-
- 8
-
-
-
- 0.00 B
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Data
+
+
+
+ -
+
+
+
+ 32
+ 32
+
+
+
+
+ 25
+ 25
+
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ 0.00 B
0.00 B
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
@@ -637,8 +644,6 @@
stopButton
clearlogButton
-
-
-
+
diff --git a/src/ui/w_PrefrencesWindow.cpp b/src/ui/w_PrefrencesWindow.cpp
index 745dd3f8..f7f81e22 100644
--- a/src/ui/w_PrefrencesWindow.cpp
+++ b/src/ui/w_PrefrencesWindow.cpp
@@ -5,8 +5,9 @@
#include "QvUtils.hpp"
#include "QvCoreInteractions.hpp"
-#include "w_PrefrencesWindow.hpp"
+#include "QvNetSpeedPlugin.hpp"
+#include "w_PrefrencesWindow.hpp"
#define LOADINGCHECK if(!finishedLoading) return;
#define NEEDRESTART if(finishedLoading) IsConnectionPropertyChanged = true;
@@ -29,13 +30,16 @@ PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
themeCombo->addItems(QStyleFactory::keys());
//
qvVersion->setText(QV2RAY_VERSION_STRING);
+ qvBuildTime->setText(__DATE__ " " __TIME__);
CurrentConfig = GetGlobalConfig();
//
themeCombo->setCurrentText(QSTRING(CurrentConfig.UISettings.theme));
- darkChartThemeCB->setChecked(CurrentConfig.UISettings.useDarkTheme);
+ darkThemeCB->setChecked(CurrentConfig.UISettings.useDarkTheme);
+ darkTrayCB->setChecked(CurrentConfig.UISettings.useDarkTrayIcon);
#if QV2RAY_USE_BUILTIN_DARKTHEME
// If we use built in theme, it should always be fusion.
themeCombo->setEnabled(!CurrentConfig.UISettings.useDarkTheme);
+ darkThemeLabel->setText(tr("Use Dark Theme"));
#endif
languageComboBox->setCurrentText(QSTRING(CurrentConfig.UISettings.language));
logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel);
@@ -339,7 +343,7 @@ void PrefrencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
auto v2ctlPath = QFileInfo(QSTRING(CurrentConfig.v2CorePath)).path() + "/v2ctl";
auto newPath = QFileInfo(QV2RAY_DEFAULT_VCORE_PATH).path();
//
- LOG(MODULE_FILE, " --> Origin v2ray core file is at: " + v2ctlPath.toStdString() + "/v2ctl")
+ LOG(MODULE_FILE, " --> Origin v2ctl file is at: " + v2ctlPath.toStdString())
LOG(MODULE_FILE, " --> New v2ray files will be placed in: " << newPath.toStdString())
//
LOG(MODULE_FILE, " --> Copying files....")
@@ -712,10 +716,11 @@ void PrefrencesWindow::on_themeCombo_currentTextChanged(const QString &arg1)
CurrentConfig.UISettings.theme = arg1.toStdString();
}
-void PrefrencesWindow::on_darkChartThemeCB_stateChanged(int arg1)
+void PrefrencesWindow::on_darkThemeCB_stateChanged(int arg1)
{
LOADINGCHECK
CurrentConfig.UISettings.useDarkTheme = arg1 == Qt::Checked;
+ QvMessageBox(this, tr("Dark Mode"), tr("Please restart Qv2ray to fully apply this feature."));
#if QV2RAY_USE_BUILTIN_DARKTHEME
themeCombo->setEnabled(arg1 != Qt::Checked);
@@ -726,3 +731,8 @@ void PrefrencesWindow::on_darkChartThemeCB_stateChanged(int arg1)
#endif
}
+
+void PrefrencesWindow::on_darkTrayCB_stateChanged(int arg1)
+{
+ CurrentConfig.UISettings.useDarkTrayIcon = arg1 == Qt::Checked;
+}
diff --git a/src/ui/w_PrefrencesWindow.hpp b/src/ui/w_PrefrencesWindow.hpp
index 5e13fd81..bb0b2e4b 100644
--- a/src/ui/w_PrefrencesWindow.hpp
+++ b/src/ui/w_PrefrencesWindow.hpp
@@ -116,7 +116,9 @@ class PrefrencesWindow : public QDialog, private Ui::PrefrencesWindow
void on_themeCombo_currentTextChanged(const QString &arg1);
- void on_darkChartThemeCB_stateChanged(int arg1);
+ void on_darkThemeCB_stateChanged(int arg1);
+
+ void on_darkTrayCB_stateChanged(int arg1);
private:
// Set ui parameters for a line;
diff --git a/src/ui/w_PrefrencesWindow.ui b/src/ui/w_PrefrencesWindow.ui
index 30e5e916..6ef68607 100644
--- a/src/ui/w_PrefrencesWindow.ui
+++ b/src/ui/w_PrefrencesWindow.ui
@@ -6,20 +6,14 @@
0
0
- 789
- 500
+ 797
+ 560
-
-
- 0
- 0
-
-
780
- 500
+ 560
@@ -70,27 +64,27 @@
-
-
+
- Use Dark Theme
+ Dark Theme Support
-
-
+
Enabled
- -
+
-
Language
- -
+
-
@@ -116,14 +110,14 @@
- -
+
-
Log Level
- -
+
-
@@ -164,14 +158,14 @@
- -
+
-
Automatically Connect To
- -
+
-
@@ -186,28 +180,28 @@
- -
+
-
Transparent Proxy Support
- -
+
-
Enabled
- -
+
-
v2ray Core Path
- -
+
-
-
@@ -221,14 +215,14 @@
- -
+
-
v2ray Assets Path
- -
+
-
-
@@ -242,6 +236,27 @@
+ -
+
+
+ Dark Tray Icon
+
+
+
+ -
+
+
+ Enabled
+
+
+
+ -
+
+
+ CheckBox
+
+
+
@@ -757,23 +772,39 @@
-
-
- ...
+
+
+ 0
+ 0
+
-
-
- :/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
+
+
+ 26
+ 26
+
+
+
+ -
-
-
- ...
+
+
+ 0
+ 0
+
-
-
- :/icons/add_connection_btn.png:/icons/add_connection_btn.png
+
+
+ 26
+ 26
+
+
+
+ +
@@ -820,23 +851,39 @@
-
-
- ...
+
+
+ 0
+ 0
+
-
-
- :/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
+
+
+ 26
+ 26
+
+
+
+ -
-
-
- ...
+
+
+ 0
+ 0
+
-
-
- :/icons/add_connection_btn.png:/icons/add_connection_btn.png
+
+
+ 26
+ 26
+
+
+
+ +
@@ -1051,31 +1098,42 @@
About
-
+
-
-
-
-
- 0
- 0
-
-
-
-
- 256
- 256
-
-
-
- background-image: url(:/icons/qv2ray.ico);background-repeat: no-repeat;
-
-
- QFrame::StyledPanel
-
-
- QFrame::Raised
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 256
+ 256
+
+
+
+ image: url(:/icons/qv2ray.ico);
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
-
@@ -1084,7 +1142,7 @@
- 17
+ 24
@@ -1096,6 +1154,11 @@
-
+
+
+ 15
+
+
Version:
@@ -1105,7 +1168,7 @@
- 10
+ 15
@@ -1126,51 +1189,29 @@
-
-
-
-
+
+
-
+
+
+
+
+
+
+ -
Built Time
- -
-
-
-
- 10
-
-
-
- TIME
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
-
+
-
- Official Repo:
+ Official Repo
- -
+
-
@@ -1178,11 +1219,6 @@
0
-
-
- 10
-
-
<html><head/><body><p><a href="https://github.com/lhy0403/Qv2ray"><span style=" text-decoration: underline; color:#2980b9;">https://github.com/lhy0403/Qv2ray</span></a></p></body></html>
@@ -1197,21 +1233,21 @@
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
-
-
@@ -1264,24 +1300,41 @@
-
-
-
- Qt::Vertical
+
+
+ QTextEdit::NoWrap
-
-
- 20
- 40
-
+
+ true
-
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Noto Sans'; color:#d69545;">This</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">program</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">comes</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">with</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">ABSOLUTELY</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">NO</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">WARRANTY.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">This</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">is</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">free</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">software,</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">and</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">you</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">are</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">welcome</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">to</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">redistribute</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">it under</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">certain</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">conditions.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(C)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Leroy.H.Y</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@lhy0403):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Current</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Developer</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(C)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Hork</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@aliyuchang33):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Hv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Initial</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Designs</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">&</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">gRPC</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">implementation</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(C)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">SOneWinstone</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@SoneWinstone):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Hv2ray/Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">HTTP</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Request</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Helper</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">ArtWork</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Done</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">By</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">ArielAxionL</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@axionl)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">TheBadGateway</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@thebadgateway):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Russian</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Translations</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Riko</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@rikakomoe):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">patch</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">8a8c1a/PR115</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Libraries</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">that</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">have</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">been</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">used</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">in</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">are</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">listed</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">below</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(Sorted</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">by</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">date</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">added):</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">dridk</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@dridk):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">X2Struct</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(Apache)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2011</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">SCHUTZ</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Sacha</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@dridk):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">QJsonModel</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(MIT)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Nikolaos</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Ftylitakis</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@ftylitak):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">QZXing</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(Apache2)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2016</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Singein</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@Singein):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">ScreenShot</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(MIT)</span></p></body></html>
+
+
-
-
- Ingore Next Version
+ Ignore Next Version
@@ -1336,9 +1389,7 @@
-
-
-
+
buttonBox
diff --git a/src/ui/w_RoutesEditor.cpp b/src/ui/w_RoutesEditor.cpp
index c9eefb5a..8498967c 100644
--- a/src/ui/w_RoutesEditor.cpp
+++ b/src/ui/w_RoutesEditor.cpp
@@ -12,8 +12,13 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) :
root(connection),
original(connection)
{
- // TODO Balancer will not be removed if an rule has been removed.
setupUi(this);
+ addInboundBtn->setIcon(QICON_R("add.png"));
+ addOutboundBtn->setIcon(QICON_R("add.png"));
+ editInboundBtn->setIcon(QICON_R("edit.png"));
+ editOutboundBtn->setIcon(QICON_R("edit.png"));
+ delInboundBtn->setIcon(QICON_R("delete.png"));
+ delOutboundBtn->setIcon(QICON_R("delete.png"));
//
inbounds = root["inbounds"].toArray();
outbounds = root["outbounds"].toArray();
diff --git a/src/ui/w_RoutesEditor.ui b/src/ui/w_RoutesEditor.ui
index e1facff9..bee3c8ed 100644
--- a/src/ui/w_RoutesEditor.ui
+++ b/src/ui/w_RoutesEditor.ui
@@ -67,33 +67,21 @@
-
- ...
-
-
-
- :/icons/add_connection_btn.png:/icons/add_connection_btn.png
+ A
-
- ...
-
-
-
- :/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
+ D
-
-
-
-
-
- :/icons/edit_connection_btn.png:/icons/edit_connection_btn.png
+ E
@@ -218,33 +206,21 @@
-
- ...
-
-
-
- :/icons/add_connection_btn.png:/icons/add_connection_btn.png
+ A
-
- ...
-
-
-
- :/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
+ D
-
-
-
-
-
- :/icons/edit_connection_btn.png:/icons/edit_connection_btn.png
+ E
@@ -441,7 +417,7 @@
...
-
+
:/icons/add_connection_btn.png:/icons/add_connection_btn.png
@@ -452,7 +428,7 @@
...
-
+
:/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
@@ -669,7 +645,7 @@
...
-
+
:/icons/remove_connection_btn.png:/icons/remove_connection_btn.png
@@ -693,7 +669,7 @@
...
-
+
:/icons/add_connection_btn.png:/icons/add_connection_btn.png
@@ -726,9 +702,7 @@
-
-
-
+
buttonBox
diff --git a/src/ui/w_ScreenShot_Core.cpp b/src/ui/w_ScreenShot_Core.cpp
index 6786d935..56380921 100644
--- a/src/ui/w_ScreenShot_Core.cpp
+++ b/src/ui/w_ScreenShot_Core.cpp
@@ -2,19 +2,45 @@
#include "QvUtils.hpp"
#include
#include
+#include
+
+#define QV2RAY_SCREENSHOT_DIM_RATIO 0.6f
ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubberBand::Rectangle, this))
{
setupUi(this);
+ // Fusion prevents the KDE Plasma Breeze's "Move window when dragging in the empty area" issue
+ this->setStyle(QStyleFactory::create("Fusion"));
+ //
+ LOG(MODULE_IMPORT, "We currently only support the primary screen.")
QRect deskRect = qApp->screens().first()->geometry();
- width = deskRect.width();
- height = deskRect.height();
//
setMouseTracking(true);
- resize(width, height);
- setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowType::Dialog);
+ resize(deskRect.size());
+ setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+ //
+ desktopImage = QGuiApplication::primaryScreen()->grabWindow(0);
+ int w = desktopImage.width();
+ int h = desktopImage.height();
+ QImage bg_grey(w, h, QImage::Format_RGB32);
+ //
+ int r, g, b;
+ auto _xdesktopImg = desktopImage.toImage();
+
+ for (int i = 0; i < w; i++) {
+ for (int j = 0; j < h; j++) {
+ r = static_cast(qRed(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
+ g = static_cast(qGreen(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
+ b = static_cast(qBlue(_xdesktopImg.pixel(i, j)) * QV2RAY_SCREENSHOT_DIM_RATIO);
+ bg_grey.setPixel(i, j, qRgb(r, g, b));
+ }
+ }
+
+ this->showFullScreen();
+ auto p = this->palette();
+ p.setBrush(QPalette::Background, bg_grey);
+ setPalette(p);
//
- setBackground(width, height, 0.6f);
label->setAttribute(Qt::WA_TranslucentBackground);
startBtn->setAttribute(Qt::WA_TranslucentBackground);
//
@@ -23,8 +49,8 @@ ScreenShotWindow::ScreenShotWindow() : QDialog(), rubber(new QRubberBand(QRubber
label->setPalette(pal);
startBtn->setPalette(pal);
//
- label->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
- startBtn->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+ label->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
+ startBtn->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
//
label->hide();
startBtn->hide();
@@ -37,55 +63,61 @@ QImage ScreenShotWindow::DoScreenShot()
return resultImage;
}
-void ScreenShotWindow::pSize() //获取截图位置坐标
+void ScreenShotWindow::pSize()
{
- pw = abs(end.x() - origin.x());
- ph = abs(end.y() - origin.y());
- px = origin.x() < end.x() ? origin.x() : end.x();
- py = origin.y() < end.y() ? origin.y() : end.y();
+ imgW = abs(end.x() - origin.x());
+ imgH = abs(end.y() - origin.y());
+ imgX = origin.x() < end.x() ? origin.x() : end.x();
+ imgY = origin.y() < end.y() ? origin.y() : end.y();
+ DEBUG("Capture Mouse Position", to_string(imgW) + " " + to_string(imgH) + " " + to_string(imgX) + " " + to_string(imgY))
+ fg->setPixmap(desktopImage.copy(imgX, imgY, imgW, imgH));
+ fg->setGeometry(imgX, imgY, imgW, imgH);
+ rubber->setGeometry(imgX, imgY, imgW, imgH);
}
void ScreenShotWindow::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Escape) {
- this->close();
+ reject();
+ } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
+ on_startBtn_clicked();
}
}
-void ScreenShotWindow::mousePressEvent(QMouseEvent *e) //鼠标按下
+void ScreenShotWindow::mousePressEvent(QMouseEvent *e)
{
origin = e->pos();
LOG(MODULE_UI, "Start capturing mouse")
rubber->setGeometry(origin.x(), origin.y(), 0, 0);
rubber->show();
- label->show();
- startBtn->show();
+ rubber->raise();
+ label->hide();
+ startBtn->hide();
}
-void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e) //鼠标移动
+void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e)
{
if (e->buttons() & Qt::LeftButton) {
end = e->pos();
pSize();
- rubber->setGeometry(px, py, pw, ph);
//
- QString size = QString("%1x%2").arg(pw).arg(ph);
- label->setText(size);
+ label->setText(QString("%1x%2").arg(imgW).arg(imgH));
+ //
//
QRect labelRect(label->contentsRect());
QRect btnRect(startBtn->contentsRect());
- if (py > labelRect.height()) {
- label->move(QPoint(px, py - labelRect.height()));
+ if (imgY > labelRect.height()) {
+ label->move(QPoint(imgX, imgY - labelRect.height()));
} else {
- label->move(QPoint(px, py));
+ label->move(QPoint(imgX, imgY));
}
- if (height - py - ph > btnRect.height()) {
- startBtn->move(QPoint(px + pw - btnRect.width(), py + ph));
- } else {
- startBtn->move(QPoint(px + pw - btnRect.width(), py + ph - btnRect.height()));
+ if (height() - imgY - imgH > btnRect.height()) {
+ startBtn->move(QPoint(imgX + imgW - btnRect.width(), imgY + imgH));
+ } else {
+ startBtn->move(QPoint(imgX + imgW - btnRect.width(), imgY + imgH - btnRect.height()));
}
label->show();
@@ -94,41 +126,17 @@ void ScreenShotWindow::mouseMoveEvent(QMouseEvent *e) //鼠标移动
}
-void ScreenShotWindow::mouseReleaseEvent(QMouseEvent *e) //鼠标松开
+void ScreenShotWindow::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() == Qt::RightButton) {
- close();
+ reject();
}
}
-void ScreenShotWindow::setBackground(int w, int h, float n) //定格当前屏幕
-{
- QScreen *screen = QGuiApplication::primaryScreen();
- bg = screen->grabWindow(0).toImage();
- QImage bg_grey(w, h, QImage::Format_RGB32);
- //
- int r, g, b;
-
- for (int i = 0; i < w; i++) {
- for (int j = 0; j < h; j++) {
- //
- r = static_cast(qRed(bg.pixel(i, j)) * n);
- g = static_cast(qGreen(bg.pixel(i, j)) * n);
- b = static_cast(qBlue(bg.pixel(i, j)) * n);
- //
- bg_grey.setPixel(i, j, qRgb(r, g, b));
- }
- }
-
- QPalette palette;
- palette.setBrush(this->backgroundRole(), QBrush(bg_grey));
- this->setPalette(palette);
- this->showFullScreen();
-}
void ScreenShotWindow::on_startBtn_clicked()
{
- resultImage = bg.copy(px, py, pw, ph);
+ resultImage = desktopImage.copy(imgX, imgY, imgW, imgH).toImage();
rubber->hide();
- close();
+ accept();
}
diff --git a/src/ui/w_ScreenShot_Core.hpp b/src/ui/w_ScreenShot_Core.hpp
index 3e8f0c0b..921409fe 100644
--- a/src/ui/w_ScreenShot_Core.hpp
+++ b/src/ui/w_ScreenShot_Core.hpp
@@ -25,23 +25,21 @@ class ScreenShotWindow : public QDialog, private Ui::ScreenShot
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
- void setBackground(int w, int h, float n);
private slots:
void on_startBtn_clicked();
private:
+ QRubberBand *rubber;
+ // Desktop Image
+ QPixmap desktopImage;
+ QImage windowBg;
QImage resultImage;
//
- QRubberBand *rubber;
- //
- QPoint origin;//鼠标起始位置
- QPoint end;//鼠标结束位置
- QImage bg;//存贮当前桌面截图
-
- int width, height;
- int pw, ph, px, py;
+ QPoint origin;
+ QPoint end;
+ int imgW, imgH, imgX, imgY;
void pSize();
};
diff --git a/src/ui/w_ScreenShot_Core.ui b/src/ui/w_ScreenShot_Core.ui
index 35905a04..8275875a 100644
--- a/src/ui/w_ScreenShot_Core.ui
+++ b/src/ui/w_ScreenShot_Core.ui
@@ -32,14 +32,14 @@
- TextLabel
+ Size
20
- 40
+ 60
80
26
@@ -48,6 +48,19 @@
Screen Shot
+
+
+
+ 30
+ 140
+ 58
+ 18
+
+
+
+ FG
+
+
diff --git a/src/utils/QvNetSpeedPlugin.hpp b/src/utils/QvNetSpeedPlugin.hpp
index cf4d7234..44a87915 100644
--- a/src/utils/QvNetSpeedPlugin.hpp
+++ b/src/utils/QvNetSpeedPlugin.hpp
@@ -1,8 +1,7 @@
#ifndef QVNETSPEEDBARJSON_H
#define QVNETSPEEDBARJSON_H
-#include "x2struct/x2struct.hpp"
-#include
+#include "Qv2rayBase.hpp"
//
// For Windows
#ifdef Q_OS_WIN
@@ -58,40 +57,6 @@ namespace Qv2ray
}
#endif
- struct QvBarLine {
- std::string Family;
- bool Bold;
- bool Italic;
- int ColorA;
- int ColorR;
- int ColorG;
- int ColorB;
- int ContentType;
- double Size;
- std::string Message;
- QvBarLine()
- : Family("Consolas")
- , Bold(true)
- , Italic(false)
- , ColorA(255), ColorR(255), ColorG(255), ColorB(255)
- , ContentType(0)
- , Size(9),
- Message() { }
- XTOSTRUCT(O(Bold, Italic, ColorA, ColorR, ColorG, ColorB, Size, Family, Message, ContentType))
- };
-
- struct QvBarPage {
- int OffsetYpx;
- std::vector Lines;
- XTOSTRUCT(O(OffsetYpx, Lines))
- QvBarPage() : OffsetYpx(5) { }
- };
-
- struct QvNetSpeedBarConfig {
- std::vector Pages;
- XTOSTRUCT(O(Pages))
- };
-
QString GetAnswerToRequest(const QString &pchRequest);
}
diff --git a/src/utils/QvTinyLog.hpp b/src/utils/QvTinyLog.hpp
index 40698d3d..7517fea9 100644
--- a/src/utils/QvTinyLog.hpp
+++ b/src/utils/QvTinyLog.hpp
@@ -11,7 +11,7 @@ using namespace std;
#define XLOG(module, level, msg) LOG(module, level << msg)
#ifdef QT_DEBUG
-#define DEBUG(module, msg) LOG(module, msg)
+#define DEBUG(module, msg) LOG("[DEBUG] - " module, msg)
#else
#define DEBUG(module, msg)
#endif
diff --git a/translations/en-US.ts b/translations/en-US.ts
index 8d83ae32..05d09eb1 100644
--- a/translations/en-US.ts
+++ b/translations/en-US.ts
@@ -13,26 +13,21 @@
ExportConfigWindow
- Dialog
+ Export Config
-
- Image
-
-
-
-
+
Text Message
-
+
Save
-
+
OK
@@ -46,7 +41,7 @@
- Name
+ Name/Prefix
@@ -54,12 +49,6 @@
Import Source
-
-
-
- Subscription Link
-
-
Existing File
@@ -70,9 +59,15 @@
VMess and QRCode
+
+
+
+ Subscription Link
+
+
-
+
Import
@@ -123,87 +118,119 @@
-
- Delay in secs
-
-
-
-
- Place your vmess:// here, one line for each.
-
-
-
-
- Cancel
-
-
-
-
- TO DO IN VERSION 2
-
-
-
-
- GroupBox
-
-
-
-
+
Go
-
+
+ After
+
+
+
+
+ second(s).
+
+
+
+
+ Place your vmess:// here, one line for each.
+
+
+
+
+ Error List
+
+
+
+
+ VMess
+
+
+
+
+ TO DO IN VERSION 2
+
+
+
+
+ GroupBox
+
+
+
+
+ Cancel
+
+
+
+
Select file to import
-
-
- QRCode Scanning Failed
-
-
-
-
- Cannot find a screen, it's rare.
-
-
-
-
- Cannot find a qrcode from the primary screen.
-
-
-
-
+
+
Import config file
-
+
+ Import from file failed, for more information, please check the log file.
+
+
+
+
Failed to check the validity of the config file.
-
-
- VMess String Check
+
+
+ Assertion Failed
-
- VMess string is not valid.
+
+ Assertion failed: ::SaveConnectionConfig should returns false.
-
- VMess config is not valid.
-
-
-
-
+
Select an image to import
+
+
+ QRCode scanning failed
+
+
+
+
+ Cannot find any QRCode from the image.
+
+
+
+
+
+
+ Edit file as JSON
+
+
+
+
+ Provided file not found:
+
+
+
+
+ The file you selected has json syntax error. Continue editing may make you lose data. Would you like to continue?
+
+
+
+
+ Failed to save file, please check if you have the required permissions
+
+
InboundEditor
@@ -484,6 +511,11 @@
Dialog
+
+
+ OK
+
+
Json Structure Preview
@@ -499,11 +531,6 @@
Json Editor
-
-
- OK
-
-
@@ -536,19 +563,19 @@
-
+
Connect
-
+
Disconnect
-
+
Reconnect
@@ -577,292 +604,302 @@
Add new connection manually
-
-
- Import connection
-
-
-
-
- Duplicate connection
-
-
-
-
- D
-
-
-
-
- Delete a connection
-
-
-
-
- Edit connection
-
-
-
-
- Edit connection as JSON
-
-
-
-
- { }
-
-
-
-
- Config Details
-
-
-
-
- Ping
-
-
A
-
- Share
+
+ Import connection
-
- #ImportConnection
+
+ Imp
-
- I
+
+ Duplicate connection
-
- ...
+
+ Dup
-
- R
+
+ Delete a connection
-
+
+ D
+
+
+
+
+ Edit connection
+
+
+
+
+ E
+
+
+
+
+ Config Details
+
+
+
+
Config Type
-
+
Protocol
-
+
Address
-
+
Port Number
-
+
Mux
-
+
+ Edit connection as JSON
+
+
+
+
+ J
+
+
+
+
+ P
+
+
+
+
+ S
+
+
+
+
Log
-
+
Speed Graph
-
+
Speed
-
+
0.00 B/s
0.00 B/s
-
+
Data
-
+
0.00 B
0.00 B
-
+
#ManuallyCreateConnection
-
+
+ #ImportConnection
+
+
+
+
#Exit
-
+
#Preferences
-
+
#Start
-
+
#Stop
-
+
#Restart
-
-
+
+
Hide
-
+
Quit
-
+
Rename
-
+
Connect to this
-
+
Edit as Json
-
- Share as QRCode/vmess Uri
+
+ Share as QRCode/VMess URL
-
-
-
+
+
+
Show
-
- Update
-
-
-
-
- Found a new version:
-
-
-
-
- Download Link:
-
-
-
-
-
+
+
No connection selected!
-
-
+
+
Please select a config from the list.
-
-
-
+
+ Update
+
+
+
+
+ Found a new version:
+
+
+
+
+ Download Link:
+
+
+
+
+
+
Connected To Server:
-
+
+ Connected
+
+
+
+
Disconnected
-
-
+
+
Rename a Connection
-
+
The name cannot be empty
-
+
+ The name has been used already, Please choose another.
+
+
+
+
Removing this Connection
+ Are you sure to remove this connection?
+
+
+
+
Failed to delete connection file, please delete manually.
-
-
+
+
No Config Selected
-
-
+
+
Please Select a Config
-
- The name has been used already, Please choose another.
+
+ Share Connection
-
- Connected
-
-
-
-
- Are you sure to remove this connection?
+
+ There're no support of sharing configs other than vmess
@@ -1107,565 +1144,554 @@
PrefrencesWindow
-
-
-
-
-
+
+
+
+
+
Prefrences
-
+
General
-
+
UI Theme
-
- Dark Chart Theme
+
+ Dark Theme Support
-
- Language
-
-
-
-
- zh-CN
-
-
-
-
- en-US
-
-
-
-
- Log Level
-
-
-
-
- none
-
-
-
-
- debug
-
-
-
-
- info
-
-
-
-
- warning
-
-
-
-
- error
-
-
-
-
- Automatically Connect To
-
-
-
-
- Transparent Proxy Support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
Enabled
-
- v2ray Assets Path
+
+ Language
-
-
- Select
+
+ zh-CN
-
- Connection Settings
+
+ en-US
-
- General Connection Settings
+
+ Log Level
-
- Statistics
+
+ none
-
- API Port
+
+ debug
-
+
+ info
+
+
+
+
+ warning
+
+
+
+
+ error
+
+
+
+
+ Automatically Connect To
+
+
+
+
+ Transparent Proxy Support
+
+
+
+
v2ray Core Path
-
-
-
- Port
+
+
+ Select
-
-
-
- Authentication
+
+ v2ray Assets Path
-
-
-
- Username
-
-
-
-
-
-
- Password
-
-
-
-
- Listening Address
-
-
-
-
+
Inbound Settings
-
+
+ Listening Address
+
+
+
+
+ Enable PAC
+
+
+
+
+ LISTEN_ADDR
+
+
+
+
+ /pac.txt
+
+
+
+
+ Choose File
+
+
+
+
SOCKS Inbound Settings
-
+
+
+
+ Port
+
+
+
+
SOCKS UDP
-
+
Local IP
-
+
+
+
+ Authentication
+
+
+
+
+
+
+ Username
+
+
+
+
+
+
+ Password
+
+
+
+
HTTP Inbound Settings
-
+
+ Connection Settings
+
+
+
+
+ General Connection Settings
+
+
+
+
Enable Proxy
-
+
Bypass Chinese Mainland
-
+
+ Statistics
+
+
+
+
+ API Port
+
+
+
+
Use Local DNS
-
+
DNS List
-
- Items
-
-
-
-
-
-
-
-
- ...
-
-
-
-
- Page Y Offset
-
-
-
-
- Pages
-
-
-
-
- Lines
-
-
-
-
- Text Style
-
-
-
-
- Font
-
-
-
-
-
- Bold
-
-
-
-
-
- Italic
-
-
-
-
- Size
-
-
-
-
- Color
-
-
-
-
- A:
-
-
-
-
- R:
-
-
-
-
- G:
-
-
-
-
- B:
-
-
-
-
- Style
-
-
-
-
- Content
-
-
-
-
- Content Type
-
-
-
-
- Text/Tag
-
-
-
-
- You can config how the network speed toolbar looks like in this panel
-
-
-
-
- Apply Network Speed Bar UI Settings
-
-
-
-
- About
-
-
-
-
- Qv2ray
-
-
-
-
- Version:
-
-
-
-
- TIME
-
-
-
-
- Official Repo:
-
-
-
-
- <html><head/><body><p><a href="https://github.com/lhy0403/Qv2ray"><span style=" text-decoration: underline; color:#2980b9;">https://github.com/lhy0403/Qv2ray</span></a></p></body></html>
-
-
-
-
- License:
-
-
-
-
- <html><head/><body><p><a href="https://www.gnu.org/licenses/gpl-3.0.txt"><span style=" text-decoration: underline; color:#2980b9;">GPLv3 (https://www.gnu.org/licenses/gpl-3.0.txt)</span></a></p></body></html>
-
-
-
-
- About Qt
-
-
-
-
- Ingore Next Version
-
-
-
-
+
Forward Proxy
-
+
Status
-
+
Type
-
+
HTTP
-
+
Socks
-
+
Host Address
-
+
Network Toolbar Settings
-
- Cancel
+
+ Items
-
+
+
+ -
+
+
+
+
+
+ +
+
+
+
+
+ Page Y Offset
+
+
+
+
+ Pages
+
+
+
+
+ Lines
+
+
+
+
+ Text Style
+
+
+
+
+ Font
+
+
+
+
+
+ Bold
+
+
+
+
+
+ Italic
+
+
+
+
+ Size
+
+
+
+
+ Color
+
+
+
+
+ A:
+
+
+
+
+ R:
+
+
+
+
+ G:
+
+
+
+
+ B:
+
+
+
+
+ ...
+
+
+
+
+ Style
+
+
+
+
+ Content
+
+
+
+
+ Content Type
+
+
+
+
+ Text/Tag
+
+
+
+
+ You can config how the network speed toolbar looks like in this panel
+
+
+
+
+ Apply Network Speed Bar UI Settings
+
+
+
+
+ About
+
+
+
+
+ Qv2ray
+
+
+
+
+ Version:
+
+
+
+
Built Time
-
+
+ Official Repo:
+
+
+
+
+ <html><head/><body><p><a href="https://github.com/lhy0403/Qv2ray"><span style=" text-decoration: underline; color:#2980b9;">https://github.com/lhy0403/Qv2ray</span></a></p></body></html>
+
+
+
+
+ License:
+
+
+
+
+ <html><head/><body><p><a href="https://www.gnu.org/licenses/gpl-3.0.txt"><span style=" text-decoration: underline; color:#2980b9;">GPLv3 (https://www.gnu.org/licenses/gpl-3.0.txt)</span></a></p></body></html>
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Noto Sans'; color:#d69545;">This</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">program</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">comes</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">with</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">ABSOLUTELY</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">NO</span><span style=" font-family:'Noto Sans'; color:#bec0c2;"> </span><span style=" font-family:'Noto Sans'; color:#d69545;">WARRANTY.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">This</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">is</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">free</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">software,</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">and</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">you</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">are</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">welcome</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">to</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">redistribute</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">it under</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">certain</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">conditions.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(C)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Leroy.H.Y</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@lhy0403):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Current</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Developer</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(C)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Hork</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@aliyuchang33):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Hv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Initial</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Designs</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">&</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">gRPC</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">implementation</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(C)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">SOneWinstone</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@SoneWinstone):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Hv2ray/Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">HTTP</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Request</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Helper</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">ArtWork</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Done</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">By</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">ArielAxionL</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@axionl)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">TheBadGateway</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@thebadgateway):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Russian</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Translations</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Riko</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@rikakomoe):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">patch</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">8a8c1a/PR115"</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Hack';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Libraries</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">that</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">have</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">been</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">used</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">in</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Qv2ray</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">are</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">listed</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">below</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(Sorted</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">by</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">date</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">added):</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">dridk</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@dridk):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">X2Struct</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(Apache)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2011</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">SCHUTZ</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Sacha</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@dridk):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">QJsonModel</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(MIT)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2019</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Nikolaos</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Ftylitakis</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@ftylitak):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">QZXing</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(Apache2)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Hack'; color:#d69545;">Copyright</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(c)</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">2016</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">Singein</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(@Singein):</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">ScreenShot</span><span style=" font-family:'Hack'; color:#bec0c2;"> </span><span style=" font-family:'Hack'; color:#d69545;">(MIT)</span></p></body></html>
+
+
+
+
+ Ingore Next Version
+
+
+
+
+ Cancel
+
+
+
+
+ About Qt
+
+
+
+
+ Use Dark Theme
+
+
+
+
Page
-
+
Item(s)
-
+
Port numbers cannot be the same
+ Open v2ray assets folder
+
+
+
+
Open v2ray core file
-
-
+
+
Enable tProxy Support
-
+
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 refer to issue #57 or the link below:
-
+
Qv2ray cannot copy one or both v2ray files from:
-
+
to this path:
-
-
+
+
Failed to setcap onto v2ray executable. You may need to run `setcap` manually.
-
+
tProxy is not supported on macOS and Windows
-
-
- Open v2ray assets folder
-
-
QObject
-
- Qv2ray Cannot Continue
+
+ VMess string should start with 'vmess://'
-
- You are running a lower version of Qv2ray compared to the current config file.
+
+ VMess string should be a valid base64 string
-
- Please report if you think this is an error.
-
-
-
-
-
- Qv2ray will now exit.
-
-
-
-
- Cannot Start Qv2ray
-
-
-
-
- Cannot find a place to store config files.
-
-
-
-
- Qv2ray has searched these paths below:
-
-
-
-
- DependencyMissing
-
-
-
-
- Cannot find openssl libs
-
-
-
-
- This could be caused by a missing of `openssl` package in your system. Or an AppImage issue.
-
-
-
-
- If you are using AppImage, please report a bug.
-
-
-
-
- Please refer to Github Issue #65 to check for solutions.
-
-
-
-
- Github Issue Link:
-
-
-
-
- Technical Details
-
-
-
-
- Another instance of Qv2ray is already running.
+
+ JSON should not be empty
@@ -1693,6 +1719,92 @@
Or put v2ray core file in the location above.
+
+
+ Cannot Start Qv2ray
+
+
+
+
+ Cannot find a place to store config files.
+
+
+
+
+ Qv2ray has searched these paths below:
+
+
+
+
+
+ Qv2ray will now exit.
+
+
+
+
+ Cannot load languages
+
+
+
+
+ Qv2ray will continue running, but you cannot change the UI language.
+
+
+
+
+ Another instance of Qv2ray is already running.
+
+
+
+
+ Qv2ray Cannot Continue
+
+
+
+
+ You are running a lower version of Qv2ray compared to the current config file.
+
+
+
+
+ Please report if you think this is an error.
+
+
+
+
+ DependencyMissing
+
+
+
+
+ Cannot find openssl libs
+
+
+
+
+ This could be caused by a missing of `openssl` package in your system. Or an AppImage issue.
+
+
+
+
+ If you are using AppImage, please report a bug.
+
+
+
+
+ Please refer to Github Issue #65 to check for solutions.
+
+
+
+
+ Github Issue Link:
+
+
+
+
+ Technical Details
+
+
Stats is not enabled
@@ -1714,367 +1826,395 @@
-
+
Custom Text
-
+
Current Time
-
+
Current Date
-
+
Current Qv2ray Version
-
+
Current Connection Name
-
+
Current Connection Status
-
+
Total Upload Speed
-
+
Total Download Speed
-
+
Upload Speed for Specific Tag
-
+
Download Speed for Specific Tag
-
+
Total Uploaded Data
-
+
Total Downloaded Data
-
+
Uploaded Data for Specific Tag
-
+
Downloaded Data for Specific Tag
RouteEditor
-
-
-
-
- Enabled
-
-
-
-
- InBounds
-
-
-
-
- Outbound
-
-
-
-
- Source IP Matching List
-
-
-
-
- Target Domain List
-
-
-
-
- Protocol
-
-
-
-
- HTTP
-
-
-
-
- TLS
-
-
-
-
- BitTorrent
-
-
-
-
- e.g. 80, 443, 8000-8080
-
-
-
-
- Enable Balancers
-
-
-
-
- Balancers
-
-
-
-
- Outbound Tag
-
-
-
-
- Users List
-
-
-
-
- Network
-
-
-
-
- TCP
-
-
-
-
- UDP
-
-
-
-
- Both
-
-
-
-
-
-
-
-
-
-
-
- ...
-
-
-
-
- Inbound List
-
-
-
-
- Inbound Information
-
-
-
-
-
- Tag
-
-
-
-
-
- Type
-
-
-
-
-
- Address
-
-
-
-
-
-
- Port
-
-
-
+
Route Editor
-
-
- D
-
-
-
-
- F
-
-
-
-
- B
-
-
-
-
- Routes
-
-
-
-
- Domain/IP
-
-
-
-
- Route Details
-
-
-
-
- Target IP List
-
-
-
-
- Outbound List
-
-
-
-
- Outbound Information
-
-
Status
-
-
-
-
+
+ Inbound List
+
+
+
+
+
+ A
+
+
+
+
+
+
+ D
+
+
+
+
+
+ E
+
+
+
+
+ Inbound Information
+
+
+
+
+
+ Type
+
+
+
+
+
+
+ Port
+
+
+
+
+
+ Address
+
+
+
+
+
+ Tag
+
+
+
+
+ Outbound List
+
+
+
+
+ F
+
+
+
+
+ B
+
+
+
+
+ Outbound Information
+
+
+
+
+ Routes
+
+
+
+
+
+
+ Enabled
+
+
+
+
+ InBounds
+
+
+
+
+ Domain/IP
+
+
+
+
+ Outbound
+
+
+
+
+
+
+
+ ...
+
+
+
+
+ Route Details
+
+
+
+
+ Target IP List
+
+
+
+
+ Source IP Matching List
+
+
+
+
+ Target Domain List
+
+
+
+
+ Network
+
+
+
+
+ TCP
+
+
+
+
+ UDP
+
+
+
+
+ Both
+
+
+
+
+ Protocol
+
+
+
+
+ HTTP
+
+
+
+
+ TLS
+
+
+
+
+ BitTorrent
+
+
+
+
+ e.g. 80, 443, 8000-8080
+
+
+
+
+ Enable Balancers
+
+
+
+
+ Balancers
+
+
+
+
+ Outbound Tag
+
+
+
+
+ Users List
+
+
+
+
+
+
+
No Tag
-
-
+
+
Any
-
-
+
+
Items
-
+
Cannot find an inbound by tag:
-
+
Index Out Of Range
-
-
+
+
Cannot Edit
-
+
This outbound entry is not supported by the GUI editor.
-
+
+
+ We will launch Json Editor instead.
+
+
+
+
Currently, this type of outbound is not supported by the editor.
-
-
-
-
+
+
+
+
Changing route inbound/outbound
-
+
You didn't select an outbound.
-
+
Banlancer will be used.
-
-
+
+
One or more inbound config(s) have no tag configured, do you still want to continue?
-
+
Are you sure to change the inbound/outbound of currently selected route?
-
+
Current inbound/outbound combinations:
-
+
Inbounds:
-
+
Outbound:
+
+
+ ScreenShot
-
-
- We will launch Json Editor instead.
+
+ ScreenShot
+
+
+
+
+ TextLabel
+
+
+
+
+ Screen Shot