Merge pull request #760 from Qv2ray/version-v2

Version v2.6.1
This commit is contained in:
QxQ 2020-07-14 00:56:42 +08:00 committed by GitHub
commit e4920e76be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 2857 additions and 7488 deletions

View File

@ -112,14 +112,13 @@ jobs:
- uses: actions/setup-node@v1
if: matrix.platform == 'macos-latest'
with:
node-version: '10.x'
node-version: '12.x'
- run: npm install -g appdmg
if: matrix.platform == 'macos-latest'
- name: macOS - ${{ matrix.qt_version }} - Generate Dependencies and Build
shell: bash
if: matrix.platform == 'macos-latest'
run: |
sudo xcode-select -s "/Applications/Xcode_10.3.app"
mkdir build
cd build
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DDS_STORE_SCRIPT=ON

5
.gitmodules vendored
View File

@ -12,10 +12,7 @@
url = https://github.com/nu-book/zxing-cpp
[submodule "src/plugin-interface"]
path = src/plugin-interface
url = https://github.com/Qv2ray/QvPlugin-Interface/
url = https://github.com/Qv2ray/QvPlugin-Interface
[submodule "libs/QJsonStruct"]
path = libs/QJsonStruct
url = https://github.com/Qv2ray/QJsonStruct
[submodule "3rdparty/uistyles"]
path = 3rdparty/uistyles
url = https://github.com/Qv2ray/QvUIStyles

@ -1 +1 @@
Subproject commit bae7c331ca7203a242e4533ba859c0c6016521ba
Subproject commit e93c12ab69a25fcaa963416f0e348d3269263190

1
3rdparty/uistyles vendored

@ -1 +0,0 @@
Subproject commit ccbc5a7ec83229e18804bf6b650b181f5279ca74

2
3rdparty/zxing-cpp vendored

@ -1 +1 @@
Subproject commit 6d40262e7293666909f7325075d452637f2fca75
Subproject commit 5351b67eac63c7e544274abf5b15b55c7716a6cf

View File

@ -108,6 +108,7 @@ set(QV2RAY_DISABLE_AUTO_UPDATE OFF CACHE BOOL "Disable update checker")
set(BUILD_TESTING OFF CACHE BOOL "Build test")
set(EMBED_TRANSLATIONS OFF CACHE BOOL "Embed translations")
set(QV2RAY_AUTO_DEPLOY ON CACHE BOOL "Automatically run deploy command after build")
set(QV2RAY_HAS_BUILT_IN_THEMES ON CACHE BOOL "Build with built-in themes")
if(QV2RAY_DEFAULT_VASSETS_PATH AND NOT QV2RAY_DEFAULT_VASSETS_PATH STREQUAL "unset")
add_definitions(-DQV2RAY_DEFAULT_VASSETS_PATH="${QV2RAY_DEFAULT_VASSETS_PATH}")
@ -191,7 +192,10 @@ include(src/plugin-interface/QvPluginInterface.cmake)
# ==================================================================================
include(cmake/components/qv2ray-lib.cmake)
include(cmake/components/qv2ray-ui.cmake)
include(3rdparty/uistyles/uistyles.cmake)
if (QV2RAY_HAS_BUILT_IN_THEMES)
include(libs/uistyles/uistyles.cmake)
endif()
set(QRC_RESOURCES
${UISTYLE_QRCS}

View File

@ -19,7 +19,6 @@ steps:
inputs:
versionSpec: '12.x'
- script: |
sudo xcode-select -s /Applications/Xcode_10.3.app
brew install protobuf grpc ninja qt5 pkg-config
npm install -g appdmg
displayName: Prepare dependencies
@ -47,4 +46,4 @@ steps:
action: edit
tag: '$(Build.SourceBranchName)'
isPreRelease: true
addChangeLog: false
addChangeLog: false

View File

@ -98,8 +98,8 @@ set(QV2RAY_LIB_SOURCES
${CMAKE_SOURCE_DIR}/src/core/kernel/PluginKernelInteractions.hpp
${CMAKE_SOURCE_DIR}/src/core/kernel/QvKernelABIChecker.cpp
${CMAKE_SOURCE_DIR}/src/core/kernel/QvKernelABIChecker.hpp
${CMAKE_SOURCE_DIR}/src/core/kernel/V2rayKernelInteractions.cpp
${CMAKE_SOURCE_DIR}/src/core/kernel/V2rayKernelInteractions.hpp
${CMAKE_SOURCE_DIR}/src/core/kernel/V2RayKernelInteractions.cpp
${CMAKE_SOURCE_DIR}/src/core/kernel/V2RayKernelInteractions.hpp
#
${CMAKE_SOURCE_DIR}/src/core/settings/SettingsBackend.cpp
${CMAKE_SOURCE_DIR}/src/core/settings/SettingsBackend.hpp

9
debian/changelog vendored
View File

@ -1,3 +1,12 @@
qv2ray (2.6.1-1) unstable; urgency=medium
* fix: should not edit GroupManager tablewidget
* fix: fixed connection import/export with unwanted content (Closes #771)
* fix: fixed V2RAY_LOCATION_ASSET env name (Closes #768)
* fix: QR code file cannot be imported
-- Guobang Bi <ymshenyu@gmail.com> Mon, 13 Jul 2020 09:37:27 +0800
qv2ray (2.6.0-1) unstable; urgency=medium
* New Release 2.6.0

@ -1 +1 @@
Subproject commit bd4f9335bb89e7b1199282c685d49dd5ae4ce1fa
Subproject commit 39d0644bd3d9348f8482d3f5375a9196a54a4348

121
libs/uistyles/LICENSE.mulan Normal file
View File

@ -0,0 +1,121 @@
木兰宽松许可证, 第1版
木兰宽松许可证, 第1版
2019年8月 http://license.coscl.org.cn/MulanPSL
您对“软件”的复制、使用、修改及分发受木兰宽松许可证第1版“本许可证”的如下条款的约束
0. 定义
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体”是指提交贡献的机构及其“关联实体”。
“关联实体”是指对“本许可证”下的一方而言控制、受控制或与其共同受控制的机构此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括仅因您或他人修改“贡献”或其他结合而将必然会侵犯到的专利权利要求。如您或您的“关联实体”直接或间接地(包括通过代理、专利被许可人或受让人),就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
条款结束。
如何将木兰宽松许可证第1版应用到您的软件
如果您希望将木兰宽松许可证第1版应用到您的新软件为了方便接收者查阅建议您完成如下三步
1 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2 请您在软件包的一级目录下创建以“LICENSE”为名的文件将整个许可证文本放入该文件中
3 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) [2019] [name of copyright holder]
[Software Name] is licensed under the Mulan PSL v1.
You can use this software according to the terms and conditions of the Mulan PSL v1.
You may obtain a copy of Mulan PSL v1 at:
http://license.coscl.org.cn/MulanPSL
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
PURPOSE.
See the Mulan PSL v1 for more details.
Mulan Permissive Software LicenseVersion 1
Mulan Permissive Software LicenseVersion 1 (Mulan PSL v1)
August 2019 http://license.coscl.org.cn/MulanPSL
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v1 (this License) with following terms and conditions:
0. Definition
Software means the program and related documents which are comprised of those Contribution and licensed under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, or are controlled by, or are under common control with a party to this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
Contribution means the copyrightable work licensed by a particular Contributor under this License.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed, excluding of any patent claims solely be infringed by your or others modification or other combinations. If you or your Affiliates directly or indirectly (including through an agent, patent licensee or assignee, institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
The Software and Contribution in it are provided without warranties of any kind, either express or implied. In no event shall any Contributor or copyright holder be liable to you for any damages, including, but not limited to any direct, or indirect, special or consequential damages arising from your use or inability to use the Software or the Contribution in it, no matter how its caused or based on which legal theory, even if advised of the possibility of such damages.
End of the Terms and Conditions
How to apply the Mulan Permissive Software LicenseVersion 1 (Mulan PSL v1) to your software
To apply the Mulan PSL v1 to your work, for easy identification by recipients, you are suggested to complete following three steps:
i. Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
ii. Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
iii. Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) [2019] [name of copyright holder]
[Software Name] is licensed under the Mulan PSL v1.
You can use this software according to the terms and conditions of the Mulan PSL v1.
You may obtain a copy of Mulan PSL v1 at:
http://license.coscl.org.cn/MulanPSL
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
PURPOSE.
See the Mulan PSL v1 for more details.

View File

@ -0,0 +1,846 @@
QPalette,
QWidget {
background: #FFFFFF;
}
* {
outline: 0px;
color: #57595B;
}
QWidget[form="true"],
QLabel[frameShape="1"] {
border: 1px solid #B6B6B6;
border-radius: 0px;
}
QWidget[form="bottom"] {
background: #E4E4E4;
}
QWidget[form="bottom"] .QFrame {
border: 1px solid #57595B;
}
QWidget[form="bottom"] QLabel,
QWidget[form="title"] QLabel {
border-radius: 0px;
color: #57595B;
background: none;
border-style: none;
}
QWidget[form="title"],
QWidget[nav="left"],
QWidget[nav="top"] QAbstractButton {
border-style: none;
border-radius: 0px;
padding: 5px;
color: #57595B;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
QWidget[nav="top"] QAbstractButton:hover,
QWidget[nav="top"] QAbstractButton:pressed,
QWidget[nav="top"] QAbstractButton:checked {
border-style: solid;
border-width: 0px 0px 2px 0px;
padding: 4px 4px 2px 4px;
border-color: #00BB9E;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
QWidget[nav="left"] QAbstractButton {
border-radius: 0px;
color: #57595B;
background: none;
border-style: none;
}
QWidget[nav="left"] QAbstractButton:hover {
color: #FFFFFF;
background-color: #00BB9E;
}
QWidget[nav="left"] QAbstractButton:checked,
QWidget[nav="left"] QAbstractButton:pressed {
color: #57595B;
border-style: solid;
border-width: 0px 0px 0px 2px;
padding: 4px 4px 4px 2px;
border-color: #00BB9E;
background-color: #FFFFFF;
}
QWidget[video="true"] QLabel {
color: #57595B;
border: 1px solid #B6B6B6;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
QWidget[video="true"] QLabel:focus {
border: 1px solid #00BB9E;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
QLineEdit,
QTextEdit,
QPlainTextEdit,
QSpinBox,
QDoubleSpinBox,
QComboBox,
QDateEdit,
QTimeEdit,
QDateTimeEdit {
border: 1px solid #B6B6B6;
border-radius: 3px;
padding: 2px;
background: none;
selection-background-color: #00BB9E;
selection-color: #FFFFFF;
}
QLineEdit:focus,
QTextEdit:focus,
QPlainTextEdit:focus,
QSpinBox:focus,
QDoubleSpinBox:focus,
QComboBox:focus,
QDateEdit:focus,
QTimeEdit:focus,
QDateTimeEdit:focus,
QLineEdit:hover,
QTextEdit:hover,
QPlainTextEdit:hover,
QSpinBox:hover,
QDoubleSpinBox:hover,
QComboBox:hover,
QDateEdit:hover,
QTimeEdit:hover,
QDateTimeEdit:hover {
border: 1px solid #B6B6B6;
}
QLineEdit[echoMode="2"] {
lineedit-password-character: 9679;
}
.QFrame {
border: 1px solid #B6B6B6;
border-radius: 3px;
}
.QGroupBox {
border: 1px solid #B6B6B6;
border-radius: 5px;
margin-top: 3ex;
}
.QGroupBox::title {
subcontrol-origin: margin;
position: relative;
left: 10px;
}
.QPushButton,
.QToolButton {
border-style: none;
border: 1px solid #B6B6B6;
color: #57595B;
padding: 5px;
min-height: 15px;
border-radius: 5px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
.QPushButton:hover,
.QToolButton:hover {
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
.QPushButton:pressed,
.QToolButton:pressed {
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
.QToolButton::menu-indicator {
image: None;
}
QToolButton#btnMenu,
QPushButton#btnMenu_Min,
QPushButton#btnMenu_Max,
QPushButton#btnMenu_Close {
border-radius: 3px;
color: #57595B;
padding: 3px;
margin: 0px;
background: none;
border-style: none;
}
QToolButton#btnMenu:hover,
QPushButton#btnMenu_Min:hover,
QPushButton#btnMenu_Max:hover {
color: #FFFFFF;
margin: 1px 1px 2px 1px;
background-color: rgba(51, 127, 209, 230);
}
QPushButton#btnMenu_Close:hover {
color: #FFFFFF;
margin: 1px 1px 2px 1px;
background-color: rgba(238, 0, 0, 128);
}
QRadioButton::indicator {
width: 15px;
height: 15px;
}
QRadioButton::indicator::unchecked {
image: url(:/uistyles/flatwhite/radiobutton_unchecked.png);
}
QRadioButton::indicator::unchecked:disabled {
image: url(:/uistyles/flatwhite/radiobutton_unchecked_disable.png);
}
QRadioButton::indicator::checked {
image: url(:/uistyles/flatwhite/radiobutton_checked.png);
}
QRadioButton::indicator::checked:disabled {
image: url(:/uistyles/flatwhite/radiobutton_checked_disable.png);
}
QGroupBox::indicator,
QTreeWidget::indicator,
QListWidget::indicator {
padding: 0px -3px 0px 0px;
}
QCheckBox::indicator,
QGroupBox::indicator,
QTreeWidget::indicator,
QListWidget::indicator {
width: 13px;
height: 13px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked,
QTreeWidget::indicator:unchecked,
QListWidget::indicator:unchecked {
image: url(:/uistyles/flatwhite/checkbox_unchecked.png);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled,
QTreeWidget::indicator:unchecked:disabled,
QListWidget::indicator:disabled {
image: url(:/uistyles/flatwhite/checkbox_unchecked_disable.png);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked,
QTreeWidget::indicator:checked,
QListWidget::indicator:checked {
image: url(:/uistyles/flatwhite/checkbox_checked.png);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled,
QTreeWidget::indicator:checked:disabled,
QListWidget::indicator:checked:disabled {
image: url(:/uistyles/flatwhite/checkbox_checked_disable.png);
}
QCheckBox::indicator:indeterminate,
QGroupBox::indicator:indeterminate,
QTreeWidget::indicator:indeterminate,
QListWidget::indicator:indeterminate {
image: url(:/uistyles/flatwhite/checkbox_parcial.png);
}
QCheckBox::indicator:indeterminate:disabled,
QGroupBox::indicator:indeterminate:disabled,
QTreeWidget::indicator:indeterminate:disabled,
QListWidget::indicator:indeterminate:disabled {
image: url(:/uistyles/flatwhite/checkbox_parcial_disable.png);
}
QTimeEdit::up-button,
QDateEdit::up-button,
QDateTimeEdit::up-button,
QDoubleSpinBox::up-button,
QSpinBox::up-button {
image: url(:/uistyles/flatwhite/add_top.png);
width: 10px;
height: 10px;
padding: 2px 5px 0px 0px;
}
QTimeEdit::down-button,
QDateEdit::down-button,
QDateTimeEdit::down-button,
QDoubleSpinBox::down-button,
QSpinBox::down-button {
image: url(:/uistyles/flatwhite/add_bottom.png);
width: 10px;
height: 10px;
padding: 0px 5px 2px 0px;
}
QTimeEdit::up-button:pressed,
QDateEdit::up-button:pressed,
QDateTimeEdit::up-button:pressed,
QDoubleSpinBox::up-button:pressed,
QSpinBox::up-button:pressed {
top: -2px;
}
QTimeEdit::down-button:pressed,
QDateEdit::down-button:pressed,
QDateTimeEdit::down-button:pressed,
QDoubleSpinBox::down-button:pressed,
QSpinBox::down-button:pressed,
QSpinBox::down-button:pressed {
bottom: -2px;
}
QComboBox::down-arrow,
QDateEdit[calendarPopup="true"]::down-arrow,
QTimeEdit[calendarPopup="true"]::down-arrow,
QDateTimeEdit[calendarPopup="true"]::down-arrow {
image: url(:/uistyles/flatwhite/add_bottom.png);
width: 10px;
height: 10px;
right: 2px;
}
QComboBox::drop-down,
QDateEdit::drop-down,
QTimeEdit::drop-down,
QDateTimeEdit::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border-left-width: 0px;
border-left-style: solid;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-left-color: #B6B6B6;
}
QComboBox::drop-down:on {
top: 1px;
}
QMenuBar::item {
color: #57595B;
background-color: #E4E4E4;
margin: 0px;
padding: 3px 10px;
}
QMenu,
QMenuBar,
QMenu:disabled,
QMenuBar:disabled {
color: #57595B;
background-color: #E4E4E4;
border: 1px solid #B6B6B6;
margin: 0px;
}
QMenu::icon{
left: 5px;
}
QMenu::item {
padding: 3px 50px 3px 15px;
}
QMenu::indicator {
width: 13px;
height: 13px;
}
QMenu::item:selected,
QMenuBar::item:selected {
color: #57595B;
border: 0px solid #B6B6B6;
background: #F6F6F6;
}
QMenu::separator {
height: 1px;
background: #B6B6B6;
}
QProgressBar {
min-height: 10px;
background: #E4E4E4;
border-radius: 5px;
text-align: center;
border: 1px solid #E4E4E4;
}
QProgressBar:chunk {
border-radius: 5px;
background-color: #B6B6B6;
}
QSlider::groove:horizontal {
background: #E4E4E4;
height: 8px;
border-radius: 4px;
}
QSlider::add-page:horizontal {
background: #E4E4E4;
height: 8px;
border-radius: 4px;
}
QSlider::sub-page:horizontal {
background: #B6B6B6;
height: 8px;
border-radius: 4px;
}
QSlider::handle:horizontal {
width: 13px;
margin-top: -3px;
margin-bottom: -3px;
border-radius: 6px;
background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #FFFFFF, stop: 0.8 #B6B6B6);
}
QSlider::groove:vertical {
width: 8px;
border-radius: 4px;
background: #E4E4E4;
}
QSlider::add-page:vertical {
width: 8px;
border-radius: 4px;
background: #E4E4E4;
}
QSlider::sub-page:vertical {
width: 8px;
border-radius: 4px;
background: #B6B6B6;
}
QSlider::handle:vertical {
height: 14px;
margin-left: -3px;
margin-right: -3px;
border-radius: 6px;
background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #FFFFFF, stop: 0.8 #B6B6B6);
}
QScrollBar:horizontal {
background: #E4E4E4;
padding: 0px;
border-radius: 6px;
max-height: 8px;
}
QScrollBar::handle:horizontal {
background: #B6B6B6;
min-width: 50px;
border-radius: 2px;
}
QScrollBar::handle:horizontal:hover {
background: #00BB9E;
}
QScrollBar::handle:horizontal:pressed {
background: #00BB9E;
}
QScrollBar::add-page:horizontal {
background: none;
}
QScrollBar::sub-page:horizontal {
background: none;
}
QScrollBar::add-line:horizontal {
background: none;
}
QScrollBar::sub-line:horizontal {
background: none;
}
QScrollBar:vertical {
background: #E4E4E4;
padding: 0px;
border-radius: 6px;
max-width: 8px;
}
QScrollBar::handle:vertical {
background: #B6B6B6;
min-height: 50px;
border-radius: 2px;
}
QScrollBar::handle:vertical:hover {
background: #00BB9E;
}
QScrollBar::handle:vertical:pressed {
background: #00BB9E;
}
QScrollBar::add-page:vertical {
background: none;
}
QScrollBar::sub-page:vertical {
background: none;
}
QScrollBar::add-line:vertical {
background: none;
}
QScrollBar::sub-line:vertical {
background: none;
}
QScrollArea {
border: 0px;
}
QTreeView,
QListView,
QTableView,
QTabWidget::pane {
border: 1px solid #B6B6B6;
selection-background-color: #F6F6F6;
selection-color: #57595B;
alternate-background-color: #F6F6F6;
gridline-color: #B6B6B6;
}
QTreeView::branch:closed:has-children {
margin: 4px;
border-image: url(:/uistyles/flatwhite/branch_open.png);
}
QTreeView::branch:open:has-children {
margin: 4px;
border-image: url(:/uistyles/flatwhite/branch_close.png);
}
QTreeView,
QListView,
QTableView,
QSplitter::handle,
QTreeView::branch {
background: #FFFFFF;
}
QTableView::item:selected,
QListView::item:selected,
QTreeView::item:selected {
color: #57595B;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
QTableView::item:hover,
QListView::item:hover,
QTreeView::item:hover,
QHeaderView {
color: #57595B;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
QTableView::item,
QListView::item,
QTreeView::item {
padding: 1px;
margin: 0px;
}
QHeaderView::section,
QTableCornerButton:section {
padding: 3px;
margin: 0px;
color: #57595B;
border: 1px solid #B6B6B6;
border-left-width: 0px;
border-right-width: 1px;
border-top-width: 0px;
border-bottom-width: 1px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
QTabBar::tab {
border: 1px solid #B6B6B6;
color: #57595B;
margin: 0px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
QTabBar::tab:selected,
QTabBar::tab:hover {
border-style: solid;
border-color: #00BB9E;
background: #FFFFFF;
}
QTabBar::tab:top,
QTabBar::tab:bottom {
padding: 3px 8px 3px 8px;
}
QTabBar::tab:left,
QTabBar::tab:right {
padding: 8px 3px 8px 3px;
}
QTabBar::tab:top:selected,
QTabBar::tab:top:hover {
border-width: 2px 0px 0px 0px;
}
QTabBar::tab:right:selected,
QTabBar::tab:right:hover {
border-width: 0px 0px 0px 2px;
}
QTabBar::tab:bottom:selected,
QTabBar::tab:bottom:hover {
border-width: 0px 0px 2px 0px;
}
QTabBar::tab:left:selected,
QTabBar::tab:left:hover {
border-width: 0px 2px 0px 0px;
}
QTabBar::tab:first:top:selected,
QTabBar::tab:first:top:hover,
QTabBar::tab:first:bottom:selected,
QTabBar::tab:first:bottom:hover {
border-left-width: 1px;
border-left-color: #B6B6B6;
}
QTabBar::tab:first:left:selected,
QTabBar::tab:first:left:hover,
QTabBar::tab:first:right:selected,
QTabBar::tab:first:right:hover {
border-top-width: 1px;
border-top-color: #B6B6B6;
}
QTabBar::tab:last:top:selected,
QTabBar::tab:last:top:hover,
QTabBar::tab:last:bottom:selected,
QTabBar::tab:last:bottom:hover {
border-right-width: 1px;
border-right-color: #B6B6B6;
}
QTabBar::tab:last:left:selected,
QTabBar::tab:last:left:hover,
QTabBar::tab:last:right:selected,
QTabBar::tab:last:right:hover {
border-bottom-width: 1px;
border-bottom-color: #B6B6B6;
}
QStatusBar::item {
border: 0px solid #E4E4E4;
border-radius: 3px;
}
QToolBox::tab,
QGroupBox#gboxDevicePanel,
QGroupBox#gboxDeviceTitle,
QFrame#gboxDevicePanel,
QFrame#gboxDeviceTitle {
padding: 3px;
border-radius: 5px;
color: #57595B;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
QToolTip {
border: 0px solid #57595B;
padding: 1px;
color: #57595B;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
QToolBox::tab:selected {
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F6F6F6, stop: 1 #F6F6F6);
}
QPrintPreviewDialog QToolButton {
border: 0px solid #57595B;
border-radius: 0px;
margin: 0px;
padding: 3px;
background: none;
}
QColorDialog QPushButton,
QFileDialog QPushButton {
min-width: 80px;
}
QToolButton#qt_calendar_prevmonth {
icon-size: 0px;
min-width: 20px;
image: url(:/uistyles/flatwhite/calendar_prevmonth.png);
}
QToolButton#qt_calendar_nextmonth {
icon-size: 0px;
min-width: 20px;
image: url(:/uistyles/flatwhite/calendar_nextmonth.png);
}
QToolButton#qt_calendar_prevmonth,
QToolButton#qt_calendar_nextmonth,
QToolButton#qt_calendar_monthbutton,
QToolButton#qt_calendar_yearbutton {
border: 0px solid #57595B;
border-radius: 3px;
margin: 3px 3px 3px 3px;
padding: 3px;
background: none;
}
QToolButton#qt_calendar_prevmonth:hover,
QToolButton#qt_calendar_nextmonth:hover,
QToolButton#qt_calendar_monthbutton:hover,
QToolButton#qt_calendar_yearbutton:hover,
QToolButton#qt_calendar_prevmonth:pressed,
QToolButton#qt_calendar_nextmonth:pressed,
QToolButton#qt_calendar_monthbutton:pressed,
QToolButton#qt_calendar_yearbutton:pressed {
border: 1px solid #B6B6B6;
}
QCalendarWidget QSpinBox#qt_calendar_yearedit {
margin: 2px;
}
QCalendarWidget QToolButton::menu-indicator {
image: None;
}
QCalendarWidget QTableView {
border-width: 0px;
}
QCalendarWidget QWidget#qt_calendar_navigationbar {
border: 1px solid #B6B6B6;
border-width: 1px 1px 0px 1px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E4E4E4, stop: 1 #E4E4E4);
}
QComboBox QAbstractItemView::item {
min-height: 20px;
min-width: 10px;
}
QTableView[model="true"]::item {
padding: 0px;
margin: 0px;
}
QTableView QLineEdit,
QTableView QComboBox,
QTableView QSpinBox,
QTableView QDoubleSpinBox,
QTableView QDateEdit,
QTableView QTimeEdit,
QTableView QDateTimeEdit {
border-width: 0px;
border-radius: 0px;
}
QTableView QLineEdit:focus,
QTableView QComboBox:focus,
QTableView QSpinBox:focus,
QTableView QDoubleSpinBox:focus,
QTableView QDateEdit:focus,
QTableView QTimeEdit:focus,
QTableView QDateTimeEdit:focus {
border-width: 0px;
border-radius: 0px;
}
QLineEdit,
QTextEdit,
QPlainTextEdit,
QSpinBox,
QDoubleSpinBox,
QComboBox,
QDateEdit,
QTimeEdit,
QDateTimeEdit {
background: #FFFFFF;
}
QTabWidget::pane:top {
top: -1px;
}
QTabWidget::pane:bottom {
bottom: -1px;
}
QTabWidget::pane:left {
right: -1px;
}
QTabWidget::pane:right {
left: -1px;
}
*:disabled {
background: #FFFFFF;
border-color: #E4E4E4;
color: #B6B6B6;
}
/*TextColor:#57595B*/
/*PanelColor:#FFFFFF*/
/*BorderColor:#B6B6B6*/
/*NormalColorStart:#E4E4E4*/
/*NormalColorEnd:#E4E4E4*/
/*DarkColorStart:#F6F6F6*/
/*DarkColorEnd:#F6F6F6*/
/*HighColor:#00BB9E*/

View File

@ -0,0 +1,23 @@
<RCC>
<qresource prefix="/uistyles">
<file>flatwhite.css</file>
<file>flatwhite/add_bottom.png</file>
<file>flatwhite/add_left.png</file>
<file>flatwhite/add_right.png</file>
<file>flatwhite/add_top.png</file>
<file>flatwhite/branch_close.png</file>
<file>flatwhite/branch_open.png</file>
<file>flatwhite/calendar_nextmonth.png</file>
<file>flatwhite/calendar_prevmonth.png</file>
<file>flatwhite/checkbox_checked.png</file>
<file>flatwhite/checkbox_checked_disable.png</file>
<file>flatwhite/checkbox_parcial.png</file>
<file>flatwhite/checkbox_parcial_disable.png</file>
<file>flatwhite/checkbox_unchecked.png</file>
<file>flatwhite/checkbox_unchecked_disable.png</file>
<file>flatwhite/radiobutton_checked.png</file>
<file>flatwhite/radiobutton_checked_disable.png</file>
<file>flatwhite/radiobutton_unchecked.png</file>
<file>flatwhite/radiobutton_unchecked_disable.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

View File

@ -0,0 +1,845 @@
QPalette,
QWidget {
background: #444444;
}
* {
outline: 0px;
color: #DCDCDC;
}
QWidget[form="true"],
QLabel[frameShape="1"] {
border: 1px solid #242424;
border-radius: 0px;
}
QWidget[form="bottom"] {
background: #484848;
}
QWidget[form="bottom"] .QFrame {
border: 1px solid #DCDCDC;
}
QWidget[form="bottom"] QLabel,
QWidget[form="title"] QLabel {
border-radius: 0px;
color: #DCDCDC;
background: none;
border-style: none;
}
QWidget[form="title"],
QWidget[nav="left"],
QWidget[nav="top"] QAbstractButton {
border-style: none;
border-radius: 0px;
padding: 5px;
color: #DCDCDC;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
QWidget[nav="top"] QAbstractButton:hover,
QWidget[nav="top"] QAbstractButton:pressed,
QWidget[nav="top"] QAbstractButton:checked {
border-style: solid;
border-width: 0px 0px 2px 0px;
padding: 4px 4px 2px 4px;
border-color: #00BB9E;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
QWidget[nav="left"] QAbstractButton {
border-radius: 0px;
color: #DCDCDC;
background: none;
border-style: none;
}
QWidget[nav="left"] QAbstractButton:hover {
color: #FFFFFF;
background-color: #00BB9E;
}
QWidget[nav="left"] QAbstractButton:checked,
QWidget[nav="left"] QAbstractButton:pressed {
color: #DCDCDC;
border-style: solid;
border-width: 0px 0px 0px 2px;
padding: 4px 4px 4px 2px;
border-color: #00BB9E;
background-color: #444444;
}
QWidget[video="true"] QLabel {
color: #DCDCDC;
border: 1px solid #242424;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
QWidget[video="true"] QLabel:focus {
border: 1px solid #00BB9E;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
QLineEdit,
QTextEdit,
QPlainTextEdit,
QSpinBox,
QDoubleSpinBox,
QComboBox,
QDateEdit,
QTimeEdit,
QDateTimeEdit {
border: 1px solid #242424;
border-radius: 3px;
padding: 2px;
background: none;
selection-background-color: #484848;
selection-color: #DCDCDC;
}
QLineEdit:focus,
QTextEdit:focus,
QPlainTextEdit:focus,
QSpinBox:focus,
QDoubleSpinBox:focus,
QComboBox:focus,
QDateEdit:focus,
QTimeEdit:focus,
QDateTimeEdit:focus,
QLineEdit:hover,
QTextEdit:hover,
QPlainTextEdit:hover,
QSpinBox:hover,
QDoubleSpinBox:hover,
QComboBox:hover,
QDateEdit:hover,
QTimeEdit:hover,
QDateTimeEdit:hover {
border: 1px solid #242424;
}
QLineEdit[echoMode="2"] {
lineedit-password-character: 9679;
}
.QFrame {
border: 1px solid #242424;
border-radius: 3px;
}
.QGroupBox {
border: 1px solid #242424;
border-radius: 5px;
margin-top: 3ex;
}
.QGroupBox::title {
subcontrol-origin: margin;
position: relative;
left: 10px;
}
.QPushButton,
.QToolButton {
border-style: none;
border: 1px solid #242424;
color: #DCDCDC;
padding: 5px;
min-height: 15px;
border-radius: 5px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
.QPushButton:hover,
.QToolButton:hover {
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
.QPushButton:pressed,
.QToolButton:pressed {
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
.QToolButton::menu-indicator {
image: None;
}
QToolButton#btnMenu,
QPushButton#btnMenu_Min,
QPushButton#btnMenu_Max,
QPushButton#btnMenu_Close {
border-radius: 3px;
color: #DCDCDC;
padding: 3px;
margin: 0px;
background: none;
border-style: none;
}
QToolButton#btnMenu:hover,
QPushButton#btnMenu_Min:hover,
QPushButton#btnMenu_Max:hover {
color: #FFFFFF;
margin: 1px 1px 2px 1px;
background-color: rgba(51, 127, 209, 230);
}
QPushButton#btnMenu_Close:hover {
color: #FFFFFF;
margin: 1px 1px 2px 1px;
background-color: rgba(238, 0, 0, 128);
}
QRadioButton::indicator {
width: 15px;
height: 15px;
}
QRadioButton::indicator::unchecked {
image: url(:/uistyles/psblack/radiobutton_unchecked.png);
}
QRadioButton::indicator::unchecked:disabled {
image: url(:/uistyles/psblack/radiobutton_unchecked_disable.png);
}
QRadioButton::indicator::checked {
image: url(:/uistyles/psblack/radiobutton_checked.png);
}
QRadioButton::indicator::checked:disabled {
image: url(:/uistyles/psblack/radiobutton_checked_disable.png);
}
QGroupBox::indicator,
QTreeWidget::indicator,
QListWidget::indicator {
padding: 0px -3px 0px 0px;
}
QCheckBox::indicator,
QGroupBox::indicator,
QTreeWidget::indicator,
QListWidget::indicator {
width: 13px;
height: 13px;
}
QCheckBox::indicator:unchecked,
QGroupBox::indicator:unchecked,
QTreeWidget::indicator:unchecked,
QListWidget::indicator:unchecked {
image: url(:/uistyles/psblack/checkbox_unchecked.png);
}
QCheckBox::indicator:unchecked:disabled,
QGroupBox::indicator:unchecked:disabled,
QTreeWidget::indicator:unchecked:disabled,
QListWidget::indicator:disabled {
image: url(:/uistyles/psblack/checkbox_unchecked_disable.png);
}
QCheckBox::indicator:checked,
QGroupBox::indicator:checked,
QTreeWidget::indicator:checked,
QListWidget::indicator:checked {
image: url(:/uistyles/psblack/checkbox_checked.png);
}
QCheckBox::indicator:checked:disabled,
QGroupBox::indicator:checked:disabled,
QTreeWidget::indicator:checked:disabled,
QListWidget::indicator:checked:disabled {
image: url(:/uistyles/psblack/checkbox_checked_disable.png);
}
QCheckBox::indicator:indeterminate,
QGroupBox::indicator:indeterminate,
QTreeWidget::indicator:indeterminate,
QListWidget::indicator:indeterminate {
image: url(:/uistyles/psblack/checkbox_parcial.png);
}
QCheckBox::indicator:indeterminate:disabled,
QGroupBox::indicator:indeterminate:disabled,
QTreeWidget::indicator:indeterminate:disabled,
QListWidget::indicator:indeterminate:disabled {
image: url(:/uistyles/psblack/checkbox_parcial_disable.png);
}
QTimeEdit::up-button,
QDateEdit::up-button,
QDateTimeEdit::up-button,
QDoubleSpinBox::up-button,
QSpinBox::up-button {
image: url(:/uistyles/psblack/add_top.png);
width: 10px;
height: 10px;
padding: 2px 5px 0px 0px;
}
QTimeEdit::down-button,
QDateEdit::down-button,
QDateTimeEdit::down-button,
QDoubleSpinBox::down-button,
QSpinBox::down-button {
image: url(:/uistyles/psblack/add_bottom.png);
width: 10px;
height: 10px;
padding: 0px 5px 2px 0px;
}
QTimeEdit::up-button:pressed,
QDateEdit::up-button:pressed,
QDateTimeEdit::up-button:pressed,
QDoubleSpinBox::up-button:pressed,
QSpinBox::up-button:pressed {
top: -2px;
}
QTimeEdit::down-button:pressed,
QDateEdit::down-button:pressed,
QDateTimeEdit::down-button:pressed,
QDoubleSpinBox::down-button:pressed,
QSpinBox::down-button:pressed,
QSpinBox::down-button:pressed {
bottom: -2px;
}
QComboBox::down-arrow,
QDateEdit[calendarPopup="true"]::down-arrow,
QTimeEdit[calendarPopup="true"]::down-arrow,
QDateTimeEdit[calendarPopup="true"]::down-arrow {
image: url(:/uistyles/psblack/add_bottom.png);
width: 10px;
height: 10px;
right: 2px;
}
QComboBox::drop-down,
QDateEdit::drop-down,
QTimeEdit::drop-down,
QDateTimeEdit::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border-left-width: 0px;
border-left-style: solid;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-left-color: #242424;
}
QComboBox::drop-down:on {
top: 1px;
}
QMenuBar::item {
color: #DCDCDC;
background-color: #484848;
margin: 0px;
padding: 3px 10px;
}
QMenu,
QMenuBar,
QMenu:disabled,
QMenuBar:disabled {
color: #DCDCDC;
background-color: #484848;
border: 1px solid #242424;
margin: 0px;
}
QMenu::icon{
left: 5px;
}
QMenu::item {
padding: 3px 50px 3px 15px;
}
QMenu::indicator {
width: 13px;
height: 13px;
}
QMenu::item:selected,
QMenuBar::item:selected {
color: #DCDCDC;
border: 0px solid #242424;
background: #646464;
}
QMenu::separator {
height: 1px;
background: #242424;
}
QProgressBar {
min-height: 10px;
background: #484848;
border-radius: 5px;
text-align: center;
border: 1px solid #484848;
}
QProgressBar:chunk {
border-radius: 5px;
background-color: #242424;
}
QSlider::groove:horizontal {
background: #484848;
height: 8px;
border-radius: 4px;
}
QSlider::add-page:horizontal {
background: #484848;
height: 8px;
border-radius: 4px;
}
QSlider::sub-page:horizontal {
background: #242424;
height: 8px;
border-radius: 4px;
}
QSlider::handle:horizontal {
width: 13px;
margin-top: -3px;
margin-bottom: -3px;
border-radius: 6px;
background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #444444, stop: 0.8 #242424);
}
QSlider::groove:vertical {
width: 8px;
border-radius: 4px;
background: #484848;
}
QSlider::add-page:vertical {
width: 8px;
border-radius: 4px;
background: #484848;
}
QSlider::sub-page:vertical {
width: 8px;
border-radius: 4px;
background: #242424;
}
QSlider::handle:vertical {
height: 14px;
margin-left: -3px;
margin-right: -3px;
border-radius: 6px;
background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #444444, stop: 0.8 #242424);
}
QScrollBar:horizontal {
background: #484848;
padding: 0px;
border-radius: 6px;
max-height: 12px;
}
QScrollBar::handle:horizontal {
background: #242424;
min-width: 50px;
border-radius: 6px;
}
QScrollBar::handle:horizontal:hover {
background: #00BB9E;
}
QScrollBar::handle:horizontal:pressed {
background: #00BB9E;
}
QScrollBar::add-page:horizontal {
background: none;
}
QScrollBar::sub-page:horizontal {
background: none;
}
QScrollBar::add-line:horizontal {
background: none;
}
QScrollBar::sub-line:horizontal {
background: none;
}
QScrollBar:vertical {
background: #484848;
padding: 0px;
border-radius: 6px;
max-width: 12px;
}
QScrollBar::handle:vertical {
background: #242424;
min-height: 50px;
border-radius: 6px;
}
QScrollBar::handle:vertical:hover {
background: #00BB9E;
}
QScrollBar::handle:vertical:pressed {
background: #00BB9E;
}
QScrollBar::add-page:vertical {
background: none;
}
QScrollBar::sub-page:vertical {
background: none;
}
QScrollBar::add-line:vertical {
background: none;
}
QScrollBar::sub-line:vertical {
background: none;
}
QScrollArea {
border: 0px;
}
QTreeView,
QListView,
QTableView,
QTabWidget::pane {
border: 1px solid #242424;
selection-background-color: #646464;
selection-color: #DCDCDC;
alternate-background-color: #525252;
gridline-color: #242424;
}
QTreeView::branch:closed:has-children {
margin: 4px;
border-image: url(:/uistyles/psblack/branch_open.png);
}
QTreeView::branch:open:has-children {
margin: 4px;
border-image: url(:/uistyles/psblack/branch_close.png);
}
QTreeView,
QListView,
QTableView,
QSplitter::handle,
QTreeView::branch {
background: #444444;
}
QTableView::item:selected,
QListView::item:selected,
QTreeView::item:selected {
color: #DCDCDC;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
QTableView::item:hover,
QListView::item:hover,
QTreeView::item:hover,
QHeaderView {
color: #DCDCDC;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
QTableView::item,
QListView::item,
QTreeView::item {
padding: 1px;
margin: 0px;
}
QHeaderView::section,
QTableCornerButton:section {
padding: 3px;
margin: 0px;
color: #DCDCDC;
border: 1px solid #242424;
border-left-width: 0px;
border-right-width: 1px;
border-top-width: 0px;
border-bottom-width: 1px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
QTabBar::tab {
border: 1px solid #242424;
color: #DCDCDC;
margin: 0px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
QTabBar::tab:selected,
QTabBar::tab:hover {
border-style: solid;
border-color: #00BB9E;
background: #444444;
}
QTabBar::tab:top,
QTabBar::tab:bottom {
padding: 3px 8px 3px 8px;
}
QTabBar::tab:left,
QTabBar::tab:right {
padding: 8px 3px 8px 3px;
}
QTabBar::tab:top:selected,
QTabBar::tab:top:hover {
border-width: 2px 0px 0px 0px;
}
QTabBar::tab:right:selected,
QTabBar::tab:right:hover {
border-width: 0px 0px 0px 2px;
}
QTabBar::tab:bottom:selected,
QTabBar::tab:bottom:hover {
border-width: 0px 0px 2px 0px;
}
QTabBar::tab:left:selected,
QTabBar::tab:left:hover {
border-width: 0px 2px 0px 0px;
}
QTabBar::tab:first:top:selected,
QTabBar::tab:first:top:hover,
QTabBar::tab:first:bottom:selected,
QTabBar::tab:first:bottom:hover {
border-left-width: 1px;
border-left-color: #242424;
}
QTabBar::tab:first:left:selected,
QTabBar::tab:first:left:hover,
QTabBar::tab:first:right:selected,
QTabBar::tab:first:right:hover {
border-top-width: 1px;
border-top-color: #242424;
}
QTabBar::tab:last:top:selected,
QTabBar::tab:last:top:hover,
QTabBar::tab:last:bottom:selected,
QTabBar::tab:last:bottom:hover {
border-right-width: 1px;
border-right-color: #242424;
}
QTabBar::tab:last:left:selected,
QTabBar::tab:last:left:hover,
QTabBar::tab:last:right:selected,
QTabBar::tab:last:right:hover {
border-bottom-width: 1px;
border-bottom-color: #242424;
}
QStatusBar::item {
border: 0px solid #484848;
border-radius: 3px;
}
QToolBox::tab,
QGroupBox#gboxDevicePanel,
QGroupBox#gboxDeviceTitle,
QFrame#gboxDevicePanel,
QFrame#gboxDeviceTitle {
padding: 3px;
border-radius: 5px;
color: #DCDCDC;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
QToolTip {
border: 0px solid #DCDCDC;
padding: 1px;
color: #DCDCDC;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
QToolBox::tab:selected {
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1 #525252);
}
QPrintPreviewDialog QToolButton {
border: 0px solid #DCDCDC;
border-radius: 0px;
margin: 0px;
padding: 3px;
background: none;
}
QColorDialog QPushButton,
QFileDialog QPushButton {
min-width: 80px;
}
QToolButton#qt_calendar_prevmonth {
icon-size: 0px;
min-width: 20px;
image: url(:/uistyles/psblack/calendar_prevmonth.png);
}
QToolButton#qt_calendar_nextmonth {
icon-size: 0px;
min-width: 20px;
image: url(:/uistyles/psblack/calendar_nextmonth.png);
}
QToolButton#qt_calendar_prevmonth,
QToolButton#qt_calendar_nextmonth,
QToolButton#qt_calendar_monthbutton,
QToolButton#qt_calendar_yearbutton {
border: 0px solid #DCDCDC;
border-radius: 3px;
margin: 3px 3px 3px 3px;
padding: 3px;
background: none;
}
QToolButton#qt_calendar_prevmonth:hover,
QToolButton#qt_calendar_nextmonth:hover,
QToolButton#qt_calendar_monthbutton:hover,
QToolButton#qt_calendar_yearbutton:hover,
QToolButton#qt_calendar_prevmonth:pressed,
QToolButton#qt_calendar_nextmonth:pressed,
QToolButton#qt_calendar_monthbutton:pressed,
QToolButton#qt_calendar_yearbutton:pressed {
border: 1px solid #242424;
}
QCalendarWidget QSpinBox#qt_calendar_yearedit {
margin: 2px;
}
QCalendarWidget QToolButton::menu-indicator {
image: None;
}
QCalendarWidget QTableView {
border-width: 0px;
}
QCalendarWidget QWidget#qt_calendar_navigationbar {
border: 1px solid #242424;
border-width: 1px 1px 0px 1px;
background: qlineargradient(spread: pad, x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484848, stop: 1 #383838);
}
QComboBox QAbstractItemView::item {
min-height: 20px;
min-width: 10px;
}
QTableView[model="true"]::item {
padding: 0px;
margin: 0px;
}
QTableView QLineEdit,
QTableView QComboBox,
QTableView QSpinBox,
QTableView QDoubleSpinBox,
QTableView QDateEdit,
QTableView QTimeEdit,
QTableView QDateTimeEdit {
border-width: 0px;
border-radius: 0px;
}
QTableView QLineEdit:focus,
QTableView QComboBox:focus,
QTableView QSpinBox:focus,
QTableView QDoubleSpinBox:focus,
QTableView QDateEdit:focus,
QTableView QTimeEdit:focus,
QTableView QDateTimeEdit:focus {
border-width: 0px;
border-radius: 0px;
}
QLineEdit,
QTextEdit,
QPlainTextEdit,
QSpinBox,
QDoubleSpinBox,
QComboBox,
QDateEdit,
QTimeEdit,
QDateTimeEdit {
background: #444444;
}
QTabWidget::pane:top {
top: -1px;
}
QTabWidget::pane:bottom {
bottom: -1px;
}
QTabWidget::pane:left {
right: -1px;
}
QTabWidget::pane:right {
left: -1px;
}
*:disabled {
background: #444444;
border-color: #484848;
color: #242424;
}
/*TextColor:#DCDCDC*/
/*PanelColor:#444444*/
/*BorderColor:#242424*/
/*NormalColorStart:#484848*/
/*NormalColorEnd:#383838*/
/*DarkColorStart:#646464*/
/*DarkColorEnd:#525252*/
/*HighColor:#00BB9E*/

View File

@ -0,0 +1,23 @@
<RCC>
<qresource prefix="/uistyles">
<file>psblack.css</file>
<file>psblack/add_bottom.png</file>
<file>psblack/add_left.png</file>
<file>psblack/add_right.png</file>
<file>psblack/add_top.png</file>
<file>psblack/branch_close.png</file>
<file>psblack/branch_open.png</file>
<file>psblack/calendar_nextmonth.png</file>
<file>psblack/calendar_prevmonth.png</file>
<file>psblack/checkbox_checked.png</file>
<file>psblack/checkbox_checked_disable.png</file>
<file>psblack/checkbox_parcial.png</file>
<file>psblack/checkbox_parcial_disable.png</file>
<file>psblack/checkbox_unchecked.png</file>
<file>psblack/checkbox_unchecked_disable.png</file>
<file>psblack/radiobutton_checked.png</file>
<file>psblack/radiobutton_checked_disable.png</file>
<file>psblack/radiobutton_unchecked.png</file>
<file>psblack/radiobutton_unchecked_disable.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

View File

@ -0,0 +1,4 @@
set(UISTYLE_QRCS
${CMAKE_SOURCE_DIR}/libs/uistyles/flatwhite/flatwhite.qrc
${CMAKE_SOURCE_DIR}/libs/uistyles/psblack/psblack.qrc
)

View File

@ -1 +1 @@
5756
5779

View File

@ -1 +1 @@
2.6.0
2.6.1

View File

@ -348,7 +348,7 @@ namespace Qv2ray
if (!QDir(QV2RAY_GENERATED_DIR).exists())
{
// The dir used to generate final config file, for V2ray interaction.
// The dir used to generate final config file, for V2Ray interaction.
QDir().mkdir(QV2RAY_GENERATED_DIR);
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
}
@ -463,8 +463,17 @@ namespace Qv2ray
return true;
}
Qv2rayApplication::commandline_status Qv2rayApplication::ParseCommandLine(QString *errorMessage, const QStringList &args)
Qv2rayApplication::commandline_status Qv2rayApplication::ParseCommandLine(QString *errorMessage, const QStringList &_argx_)
{
QStringList filteredArgs;
for (const auto &arg : _argx_)
{
#ifdef Q_OS_MACOS
if (arg.contains("-psn"))
continue;
#endif
filteredArgs << arg;
}
QCommandLineParser parser;
//
QCommandLineOption noAPIOption("noAPI", tr("Disable gRPC API subsystem"));
@ -476,7 +485,7 @@ namespace Qv2ray
QCommandLineOption reconnectOption("reconnect", tr("Reconnect last connection"));
QCommandLineOption exitOption("exit", tr("Exit Qv2ray"));
//
parser.setApplicationDescription(tr("Qv2ray - A cross-platform Qt frontend for V2ray."));
parser.setApplicationDescription(tr("Qv2ray - A cross-platform Qt frontend for V2Ray."));
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
//
parser.addOption(noAPIOption);
@ -491,7 +500,7 @@ namespace Qv2ray
auto helpOption = parser.addHelpOption();
auto versionOption = parser.addVersionOption();
if (!parser.parse(args))
if (!parser.parse(filteredArgs))
{
*errorMessage = parser.errorText();
return QV2RAY_ERROR;

View File

@ -181,6 +181,12 @@ namespace Qv2ray::base
JSONSTRUCT_REGISTER(ConnectionStatsEntryObject, F(upLinkData, downLinkData))
};
enum ConnectionImportSource
{
IMPORT_SOURCE_SUBSCRIPTION,
IMPORT_SOURCE_MANUAL
};
struct ConnectionStatsObject
{
ConnectionStatsEntryObject &operator[](StatisticsType i)
@ -195,15 +201,6 @@ namespace Qv2ray::base
{
return JsonStructHelper::___json_struct_store_data(entries);
}
auto toMap() const
{
std::map<StatisticsType, QvStatsData> result;
for (auto i = 0; i < entries.count(); i++)
{
result[StatisticsType(i)] = { entries[i].upLinkData, entries[i].downLinkData };
}
return result;
}
void loadJson(const QJsonValue &d)
{
entries.clear();
@ -222,12 +219,19 @@ namespace Qv2ray::base
{
qint64 lastConnected;
qint64 latency;
ConnectionImportSource importSource;
ConnectionStatsObject stats;
//
int __qvConnectionRefCount;
//
ConnectionObject() : lastConnected(), latency(LATENCY_TEST_VALUE_NODATA), stats(), __qvConnectionRefCount(0){};
JSONSTRUCT_REGISTER(ConnectionObject, F(lastConnected, latency, stats), B(__Qv2rayConfigObjectBase))
ConnectionObject()
: lastConnected(), //
latency(LATENCY_TEST_VALUE_NODATA), //
importSource(IMPORT_SOURCE_MANUAL), //
stats(), //
__qvConnectionRefCount(0) //
{};
JSONSTRUCT_REGISTER(ConnectionObject, F(lastConnected, latency, importSource, stats), B(__Qv2rayConfigObjectBase))
};
template<typename T>

View File

@ -188,7 +188,7 @@ namespace Qv2ray::components::autolaunch
ts.setCodec("UTF-8");
ts << QLatin1String("[Desktop Entry]") << NEWLINE //
<< QLatin1String("Name=") << QCoreApplication::applicationName() + QCoreApplication::arguments().join(" ") << NEWLINE //
<< QLatin1String("GenericName=") << QLatin1String("V2ray Frontend") << NEWLINE //
<< QLatin1String("GenericName=") << QLatin1String("V2Ray Frontend") << NEWLINE //
<< QLatin1String("Exec=") << binPath << NEWLINE //
<< QLatin1String("Terminal=") << "false" << NEWLINE //
<< QLatin1String("Icon=") << "qv2ray" << NEWLINE //

View File

@ -109,8 +109,15 @@ namespace Qv2ray::components::latency::icmping
memset(&targetAddress, 0, sizeof(targetAddress));
targetAddress.sin_family = resolvedAddress->h_addrtype;
targetAddress.sin_port = 0;
memcpy(&targetAddress.sin_addr, resolvedAddress->h_addr, resolvedAddress->h_length);
auto src = resolvedAddress->h_addr;
if (src == nullptr)
{
// Buggy GCC detected
return { 0, "GCC: COMPILER BUG. Cannot even dereference a char**" };
}
memcpy(&targetAddress.sin_addr, src, resolvedAddress->h_length);
// prepare echo request packet
icmp _icmp_request;
memset(&_icmp_request, 0, sizeof(_icmp_request));

View File

@ -172,9 +172,9 @@ namespace Qv2ray::core
{
const auto &inbound = inboundVal.toObject();
inboundPorts[inbound["tag"].toString()] = {
inbound["protocol"].toString(), //
inbound["listen"].toString(), //
inbound["port"].toInt() //
inbound["protocol"].toString(), //
inbound["listen"].toString(), //
inbound["port"].toVariant().toInt() //
};
}
return inboundPorts;

View File

@ -13,12 +13,12 @@ namespace Qv2ray::core::connection::connectionIO
{
root.remove("inbounds");
root.remove("routing");
root.remove("dns");
}
root.remove("log");
root.remove("api");
root.remove("stats");
root.remove("dns");
return root;
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "base/Qv2rayBase.hpp"
static const inline QStringList V2rayLogLevel = { "none", "debug", "info", "warning", "error" };
static const inline QStringList V2RayLogLevel = { "none", "debug", "info", "warning", "error" };
namespace Qv2ray::core::connection::generation
{

View File

@ -75,8 +75,8 @@ namespace Qv2ray::core::handler
tcpingHelper = new LatencyTestHost(5, this);
connect(tcpingHelper, &LatencyTestHost::OnLatencyTestCompleted, this, &QvConfigHandler::OnLatencyDataArrived_p);
//
// Save per 1 minutes.
saveTimerId = startTimer(1 * 60 * 1000);
// Save per 1 hour.
saveTimerId = startTimer(1 * 60 * 60 * 1000);
// Do not ping all...
pingConnectionTimerId = startTimer(60 * 1000);
}
@ -616,7 +616,8 @@ namespace Qv2ray::core::handler
filteredConnections.count() > 5 ||
QvMessageBoxAsk(nullptr, tr("Update Subscription"),
tr("%1 out of %n entrie(s) have been filtered out, do you want to continue?", "", _newConnections.count())
.arg(filteredConnections.count())) == QMessageBox::Yes;
.arg(filteredConnections.count()) +
NEWLINE + GetDisplayName(id)) == QMessageBox::Yes;
for (const auto &config : useFilteredConnections ? filteredConnections : _newConnections)
{
@ -659,16 +660,27 @@ namespace Qv2ray::core::handler
}
// Check if anything left behind (not being updated or changed significantly)
LOG(MODULE_CORE_HANDLER, "Removed old connections not have been matched.")
for (const auto &conn : originalConnectionIdList)
if (!originalConnectionIdList.isEmpty())
{
LOG(MODULE_CORE_HANDLER, "Removing connections not in the new subscription: " + conn.toString())
RemoveConnectionFromGroup(conn, id);
bool needContinue =
QvMessageBoxAsk(nullptr, //
tr("Update Subscription"),
tr("There're %n connection(s) in the group that do not belong the current subscription (any more).", "",
originalConnectionIdList.count()) +
NEWLINE + GetDisplayName(id) + NEWLINE + tr("Would you like to remove them?")) == QMessageBox::Yes;
if (needContinue)
{
LOG(MODULE_CORE_HANDLER, "Removed old connections not have been matched.")
for (const auto &conn : originalConnectionIdList)
{
LOG(MODULE_CORE_HANDLER, "Removing connections not in the new subscription: " + conn.toString())
RemoveConnectionFromGroup(conn, id);
}
}
}
// Update the time
groups[id].lastUpdatedDate = system_clock::to_time_t(system_clock::now());
return hasErrorOccured;
}

View File

@ -10,10 +10,10 @@ namespace Qv2ray::core::handler
KernelInstanceHandler::KernelInstanceHandler(QObject *parent) : QObject(parent)
{
KernelInstance = this;
vCoreInstance = new V2rayKernelInstance(this);
connect(vCoreInstance, &V2rayKernelInstance::OnNewStatsDataArrived, this, &KernelInstanceHandler::OnV2rayStatsDataRcvd_p);
connect(vCoreInstance, &V2rayKernelInstance::OnProcessOutputReadyRead, this, &KernelInstanceHandler::OnKernelLog_p);
connect(vCoreInstance, &V2rayKernelInstance::OnProcessErrored, this, &KernelInstanceHandler::OnKernelCrashed_p);
vCoreInstance = new V2RayKernelInstance(this);
connect(vCoreInstance, &V2RayKernelInstance::OnNewStatsDataArrived, this, &KernelInstanceHandler::OnV2RayStatsDataRcvd_p);
connect(vCoreInstance, &V2RayKernelInstance::OnProcessOutputReadyRead, this, &KernelInstanceHandler::OnKernelLog_p);
connect(vCoreInstance, &V2RayKernelInstance::OnProcessErrored, this, &KernelInstanceHandler::OnKernelCrashed_p);
//
auto kernelList = PluginHost->GetPluginKernels();
for (const auto &internalName : kernelList.keys())
@ -119,7 +119,7 @@ namespace Qv2ray::core::handler
//
QMap<QvPluginKernel::KernelSetting, QVariant> _inboundSettings;
LOG(MODULE_VCORE, "V2rayIntegration: " + QSTRN(pluginPort) + " = " + outProtocol)
LOG(MODULE_VCORE, "V2RayIntegration: " + QSTRN(pluginPort) + " = " + outProtocol)
_inboundSettings[_k::KERNEL_HTTP_ENABLED] = false;
_inboundSettings[_k::KERNEL_SOCKS_ENABLED] = true;
_inboundSettings[_k::KERNEL_SOCKS_PORT] = pluginPort;
@ -157,7 +157,7 @@ namespace Qv2ray::core::handler
const auto firstOutboundProtocol = firstOutbound["protocol"].toString();
if (GlobalConfig.pluginConfig.v2rayIntegration)
{
LOG(MODULE_VCORE, "Starting kernels with V2rayIntegration.")
LOG(MODULE_VCORE, "Starting kernels with V2RayIntegration.")
bool hasAllKernelStarted = true;
for (auto &[outboundProtocol, kernelObject] : activeKernels)
{
@ -181,7 +181,7 @@ namespace Qv2ray::core::handler
}
currentId = id;
//
// Also start V2ray-core.
// Also start V2Ray-core.
auto result = vCoreInstance->StartConnection(fullConfig);
//
if (result.has_value())
@ -198,8 +198,8 @@ namespace Qv2ray::core::handler
}
else if (outboundKernelMap.contains(firstOutboundProtocol))
{
// Connections without V2ray Integration will have and ONLY have ONE kernel.
LOG(MODULE_CONNECTION, "Starting kernel " + firstOutboundProtocol + " without V2ray Integration")
// Connections without V2Ray Integration will have and ONLY have ONE kernel.
LOG(MODULE_CONNECTION, "Starting kernel " + firstOutboundProtocol + " without V2Ray Integration")
{
auto kernel = PluginHost->CreatePluginKernel(outboundKernelMap[firstOutbound["protocol"].toString()]);
activeKernels.push_back({ firstOutboundProtocol, std::move(kernel) });
@ -243,7 +243,7 @@ namespace Qv2ray::core::handler
}
else
{
LOG(MODULE_CONNECTION, "Starting V2ray without plugin.")
LOG(MODULE_CONNECTION, "Starting V2Ray without plugin.")
currentId = id;
auto result = vCoreInstance->StartConnection(fullConfig);
if (result.has_value())
@ -300,7 +300,7 @@ namespace Qv2ray::core::handler
activeKernels.clear();
}
void KernelInstanceHandler::OnV2rayStatsDataRcvd_p(const QMap<StatisticsType, QvStatsSpeed> &data)
void KernelInstanceHandler::OnV2RayStatsDataRcvd_p(const QMap<StatisticsType, QvStatsSpeed> &data)
{
if (isConnected)
{
@ -310,6 +310,6 @@ namespace Qv2ray::core::handler
void KernelInstanceHandler::OnPluginStatsDataRcvd_p(const long uploadSpeed, const long downloadSpeed)
{
OnV2rayStatsDataRcvd_p({ { API_OUTBOUND_PROXY, { uploadSpeed, downloadSpeed } } });
OnV2RayStatsDataRcvd_p({ { API_OUTBOUND_PROXY, { uploadSpeed, downloadSpeed } } });
}
} // namespace Qv2ray::core::handler

View File

@ -1,7 +1,7 @@
#pragma once
#include "components/plugins/QvPluginHost.hpp"
#include "core/CoreUtils.hpp"
#include "core/kernel/V2rayKernelInteractions.hpp"
#include "core/kernel/V2RayKernelInteractions.hpp"
#include <QObject>
#include <optional>
@ -40,7 +40,7 @@ namespace Qv2ray::core::handler
private slots:
void OnKernelCrashed_p(const QString &msg);
void OnKernelLog_p(const QString &log);
void OnV2rayStatsDataRcvd_p(const QMap<StatisticsType, QvStatsSpeed> &data);
void OnV2RayStatsDataRcvd_p(const QMap<StatisticsType, QvStatsSpeed> &data);
void OnPluginStatsDataRcvd_p(const long uploadSpeed, const long downloadSpeed);
private:
@ -70,7 +70,7 @@ namespace Qv2ray::core::handler
// Since QMap does not support std::unique_ptr, we use std::map<>
std::list<std::pair<QString, std::unique_ptr<QvPluginKernel>>> activeKernels;
QMap<QString, InboundInfoObject> inboundInfo;
V2rayKernelInstance *vCoreInstance = nullptr;
V2RayKernelInstance *vCoreInstance = nullptr;
ConnectionGroupPair currentId = {};
};
inline const KernelInstanceHandler *KernelInstance;

View File

@ -111,11 +111,11 @@ namespace Qv2ray::core::handler
//
// BEGIN RUNTIME CONFIG GENERATION
// We need copy construct here
CONFIGROOT RouteHandler::GenerateFinalConfig(const ConnectionGroupPair &pair) const
CONFIGROOT RouteHandler::GenerateFinalConfig(const ConnectionGroupPair &p, bool api) const
{
return GenerateFinalConfig(ConnectionManager->GetConnectionRoot(pair.connectionId), ConnectionManager->GetGroupRoutingId(pair.groupId));
return GenerateFinalConfig(ConnectionManager->GetConnectionRoot(p.connectionId), ConnectionManager->GetGroupRoutingId(p.groupId), api);
}
CONFIGROOT RouteHandler::GenerateFinalConfig(CONFIGROOT root, const GroupRoutingId &routingId) const
CONFIGROOT RouteHandler::GenerateFinalConfig(CONFIGROOT root, const GroupRoutingId &routingId, bool hasAPI) const
{
const auto &config = configs.contains(routingId) ? configs[routingId] : GlobalConfig.defaultRouteConfig;
//
@ -134,7 +134,7 @@ namespace Qv2ray::core::handler
//
// logObject.insert("access", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ACCESS_LOG_FILENAME);
// logObject.insert("error", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME);
QJsonIO::SetValue(root, V2rayLogLevel[GlobalConfig.logLevel], "log", "loglevel");
QJsonIO::SetValue(root, V2RayLogLevel[GlobalConfig.logLevel], "log", "loglevel");
//
// Since Qv2ray does not support settings DNS manually for now.
// These settings are being added for both complex config AND simple config.
@ -382,7 +382,7 @@ namespace Qv2ray::core::handler
}
// Let's process some api features.
if (GlobalConfig.kernelConfig.enableAPI)
if (hasAPI && GlobalConfig.kernelConfig.enableAPI)
{
//
// Stats

View File

@ -26,8 +26,8 @@ namespace Qv2ray::core::handler
bool SetAdvancedRouteSettings(const GroupRoutingId &id, bool overrideGlobal, const QvConfig_Route &dns);
//
// Final Config Generation
CONFIGROOT GenerateFinalConfig(const ConnectionGroupPair &pair) const;
CONFIGROOT GenerateFinalConfig(CONFIGROOT root, const GroupRoutingId &routingId) const;
CONFIGROOT GenerateFinalConfig(const ConnectionGroupPair &pair, bool hasAPI = true) const;
CONFIGROOT GenerateFinalConfig(CONFIGROOT root, const GroupRoutingId &routingId, bool hasAPI = true) const;
// Route Table Generation
ROUTING GenerateRoutes(bool enableProxy, bool bypassCN, const QString &outboundTag, const QvConfig_Route &routeConfig) const;

View File

@ -10,7 +10,7 @@ using grpc::Status;
namespace Qv2ray::core::kernel
{
constexpr auto QV2RAY_GRPC_ERROR_RETCODE = -1;
constexpr auto Qv2ray_GRPC_ERROR_RETCODE = -1;
static QvAPIDataTypeConfig DefaultInboundAPIConfig{ { API_INBOUND, { "dokodemo-door", "http", "socks" } } };
static QvAPIDataTypeConfig DefaultOutboundAPIConfig{ { API_OUTBOUND_PROXY, { "dns", "http", "mtproto", "shadowsocks", "socks", "vmess" } },
{ API_OUTBOUND_DIRECT, { "freedom" } },
@ -22,10 +22,10 @@ namespace Qv2ray::core::kernel
// It's been expected that you will take hours to fully understand the tricks and hacks lying deeply in this class.
//
// The API Worker runs as a daemon together with Qv2ray, on a single thread.
// They use a flag, running, to indicate if the API worker should go and fetch the statistics from V2ray Core.
// They use a flag, running, to indicate if the API worker should go and fetch the statistics from V2Ray Core.
//
// The flag, running, will be set to true, immediately after the V2ray core reported that it's been started.
// and will be set to false right before we stopping V2ray Core.
// The flag, running, will be set to true, immediately after the V2Ray core reported that it's been started.
// and will be set to false right before we stopping V2Ray Core.
//
APIWorker::APIWorker()
@ -101,13 +101,15 @@ namespace Qv2ray::core::kernel
if (apiFailCounter == QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD)
{
LOG(MODULE_VCORE, "API call failure threshold reached, cancelling further API aclls.")
emit OnAPIErrored(tr("Failed to get statistics data, please check if V2ray is running properly"));
emit OnAPIErrored(tr("Failed to get statistics data, please check if V2Ray is running properly"));
apiFailCounter++;
QThread::msleep(1000);
continue;
}
else if (apiFailCounter > QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD)
{
// Ignored future requests.
QThread::msleep(1000);
continue;
}
@ -118,7 +120,7 @@ namespace Qv2ray::core::kernel
const QString prefix = config.type == API_INBOUND ? "inbound" : "outbound";
const auto value_up = CallStatsAPIByName(prefix % ">>>" % tag % ">>>traffic>>>uplink");
const auto value_down = CallStatsAPIByName(prefix % ">>>" % tag % ">>>traffic>>>downlink");
hasError = hasError || value_up == QV2RAY_GRPC_ERROR_RETCODE || value_down == QV2RAY_GRPC_ERROR_RETCODE;
hasError = hasError || value_up == Qv2ray_GRPC_ERROR_RETCODE || value_down == Qv2ray_GRPC_ERROR_RETCODE;
statsResult[config.type].first += std::max(value_up, 0LL);
statsResult[config.type].second += std::max(value_down, 0LL);
}
@ -145,7 +147,7 @@ namespace Qv2ray::core::kernel
if (!status.ok())
{
LOG(MODULE_VCORE, "API call returns: " + QSTRN(status.error_code()) + " (" + QString::fromStdString(status.error_message()) + ")")
return QV2RAY_GRPC_ERROR_RETCODE;
return Qv2ray_GRPC_ERROR_RETCODE;
}
else
{

View File

@ -1,4 +1,4 @@
#include "V2rayKernelInteractions.hpp"
#include "V2RayKernelInteractions.hpp"
#include "APIBackend.hpp"
#include "common/QvHelpers.hpp"
@ -8,7 +8,7 @@
namespace Qv2ray::core::kernel
{
std::pair<bool, std::optional<QString>> V2rayKernelInstance::CheckAndSetCoreExecutableState(const QString &vCorePath)
std::pair<bool, std::optional<QString>> V2RayKernelInstance::CheckAndSetCoreExecutableState(const QString &vCorePath)
{
#ifdef Q_OS_UNIX
// For Linux/macOS users: if they cannot execute the core,
@ -73,23 +73,23 @@ namespace Qv2ray::core::kernel
return { true, tr("Check is skipped") };
}
bool V2rayKernelInstance::ValidateKernel(const QString &vCorePath, const QString &vAssetsPath, QString *message)
bool V2RayKernelInstance::ValidateKernel(const QString &vCorePath, const QString &vAssetsPath, QString *message)
{
QFile coreFile(vCorePath);
if (!coreFile.exists())
{
DEBUG(MODULE_VCORE, "V2ray core file cannot be found.")
*message = tr("V2ray core executable not found.");
DEBUG(MODULE_VCORE, "V2Ray core file cannot be found.")
*message = tr("V2Ray core executable not found.");
return false;
}
// Use open() here to prevent `executing` a folder, which may have the
// same name as the V2ray core.
// same name as the V2Ray core.
if (!coreFile.open(QFile::ReadOnly))
{
DEBUG(MODULE_VCORE, "V2ray core file cannot be opened, possibly be a folder?")
*message = tr("V2ray core file cannot be opened, please ensure there's a file instead of a folder.");
DEBUG(MODULE_VCORE, "V2Ray core file cannot be opened, possibly be a folder?")
*message = tr("V2Ray core file cannot be opened, please ensure there's a file instead of a folder.");
return false;
}
@ -150,8 +150,8 @@ namespace Qv2ray::core::kernel
if (!hasGeoIP && !hasGeoSite)
{
DEBUG(MODULE_VCORE, "V2ray assets path contains none of those two files.")
*message = tr("V2ray assets path is not valid.");
DEBUG(MODULE_VCORE, "V2Ray assets path contains none of those two files.")
*message = tr("V2Ray assets path is not valid.");
return false;
}
@ -169,7 +169,7 @@ namespace Qv2ray::core::kernel
return false;
}
// Check if V2ray core returns a version number correctly.
// Check if V2Ray core returns a version number correctly.
QProcess proc;
#ifdef Q_OS_WIN32
// nativeArguments are required for Windows platform, without a
@ -188,16 +188,16 @@ namespace Qv2ray::core::kernel
if (exitCode != 0)
{
DEBUG(MODULE_VCORE, "VCore failed with an exit code: " + QSTRN(exitCode))
*message = tr("V2ray core failed with an exit code: ") + QSTRN(exitCode);
*message = tr("V2Ray core failed with an exit code: ") + QSTRN(exitCode);
return false;
}
QString output = proc.readAllStandardOutput();
LOG(MODULE_VCORE, "V2ray output: " + SplitLines(output).join(";"))
LOG(MODULE_VCORE, "V2Ray output: " + SplitLines(output).join(";"))
if (SplitLines(output).isEmpty())
{
*message = tr("V2ray core returns empty string.");
*message = tr("V2Ray core returns empty string.");
return false;
}
@ -205,21 +205,21 @@ namespace Qv2ray::core::kernel
return true;
}
bool V2rayKernelInstance::ValidateConfig(const QString &path)
bool V2RayKernelInstance::ValidateConfig(const QString &path)
{
QString v2rayCheckResult;
QString V2RayCheckResult;
auto kernelPath = GlobalConfig.kernelConfig.KernelPath();
auto assetsPath = GlobalConfig.kernelConfig.AssetsPath();
if (ValidateKernel(kernelPath, assetsPath, &v2rayCheckResult))
if (ValidateKernel(kernelPath, assetsPath, &V2RayCheckResult))
{
DEBUG(MODULE_VCORE, "V2ray version: " + v2rayCheckResult)
DEBUG(MODULE_VCORE, "V2Ray version: " + V2RayCheckResult)
// Append assets location env.
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("V2RAY_LOCATION_ASSET", assetsPath);
//
QProcess process;
process.setProcessEnvironment(env);
DEBUG(MODULE_VCORE, "Starting V2ray core with test options")
DEBUG(MODULE_VCORE, "Starting V2Ray core with test options")
process.start(kernelPath, QStringList{ "-test", "-config", path }, QIODevice::ReadWrite | QIODevice::Text);
process.waitForFinished();
@ -237,42 +237,42 @@ namespace Qv2ray::core::kernel
}
else
{
QvMessageBoxWarn(nullptr, tr("Cannot start V2ray"), //
tr("V2ray core settings is incorrect.") + NEWLINE + NEWLINE + //
tr("The error is: ") + NEWLINE + v2rayCheckResult);
QvMessageBoxWarn(nullptr, tr("Cannot start V2Ray"), //
tr("V2Ray core settings is incorrect.") + NEWLINE + NEWLINE + //
tr("The error is: ") + NEWLINE + V2RayCheckResult);
return false;
}
}
V2rayKernelInstance::V2rayKernelInstance(QObject *parent) : QObject(parent)
V2RayKernelInstance::V2RayKernelInstance(QObject *parent) : QObject(parent)
{
vProcess = new QProcess();
connect(vProcess, &QProcess::readyReadStandardOutput, this,
[&]() { emit OnProcessOutputReadyRead(vProcess->readAllStandardOutput().trimmed()); });
connect(vProcess, &QProcess::stateChanged, [&](QProcess::ProcessState state) {
DEBUG(MODULE_VCORE, "V2ray kernel process status changed: " + QVariant::fromValue(state).toString())
DEBUG(MODULE_VCORE, "V2Ray kernel process status changed: " + QVariant::fromValue(state).toString())
// If V2ray crashed AFTER we start it.
// If V2Ray crashed AFTER we start it.
if (KernelStarted && state == QProcess::NotRunning)
{
LOG(MODULE_VCORE, "V2ray kernel crashed.")
LOG(MODULE_VCORE, "V2Ray kernel crashed.")
StopConnection();
emit OnProcessErrored("V2ray kernel crashed.");
emit OnProcessErrored("V2Ray kernel crashed.");
}
});
apiWorker = new APIWorker();
qRegisterMetaType<StatisticsType>();
qRegisterMetaType<QMap<StatisticsType, QvStatsSpeed>>();
connect(apiWorker, &APIWorker::onAPIDataReady, this, &V2rayKernelInstance::OnNewStatsDataArrived);
connect(apiWorker, &APIWorker::onAPIDataReady, this, &V2RayKernelInstance::OnNewStatsDataArrived);
KernelStarted = false;
}
std::optional<QString> V2rayKernelInstance::StartConnection(const CONFIGROOT &root)
std::optional<QString> V2RayKernelInstance::StartConnection(const CONFIGROOT &root)
{
if (KernelStarted)
{
LOG(MODULE_VCORE, "Status is invalid, expect STOPPED when calling StartConnection")
return tr("Invalid V2ray Instance Status.");
return tr("Invalid V2Ray Instance Status.");
}
// Write the final configuration to the disk.
@ -288,7 +288,7 @@ namespace Qv2ray::core::kernel
vProcess->setProcessEnvironment(env);
vProcess->start(GlobalConfig.kernelConfig.KernelPath(), { "-config", filePath }, QIODevice::ReadWrite | QIODevice::Text);
vProcess->waitForStarted();
DEBUG(MODULE_VCORE, "V2ray core started.")
DEBUG(MODULE_VCORE, "V2Ray core started.")
KernelStarted = true;
QMap<bool, QMap<QString, QString>> tagProtocolMap;
@ -333,11 +333,11 @@ namespace Qv2ray::core::kernel
else
{
KernelStarted = false;
return tr("V2ray kernel failed to start.");
return tr("V2Ray kernel failed to start.");
}
}
void V2rayKernelInstance::StopConnection()
void V2RayKernelInstance::StopConnection()
{
if (apiEnabled)
{
@ -349,12 +349,12 @@ namespace Qv2ray::core::kernel
// to capture the real kernel CRASH
KernelStarted = false;
vProcess->close();
// Block until V2ray core exits
// Block until V2Ray core exits
// Should we use -1 instead of waiting for 30secs?
vProcess->waitForFinished();
}
V2rayKernelInstance::~V2rayKernelInstance()
V2RayKernelInstance::~V2RayKernelInstance()
{
if (KernelStarted)
{

View File

@ -7,12 +7,12 @@ class QProcess;
namespace Qv2ray::core::kernel
{
class APIWorker;
class V2rayKernelInstance : public QObject
class V2RayKernelInstance : public QObject
{
Q_OBJECT
public:
explicit V2rayKernelInstance(QObject *parent = nullptr);
~V2rayKernelInstance() override;
explicit V2RayKernelInstance(QObject *parent = nullptr);
~V2RayKernelInstance() override;
//
std::optional<QString> StartConnection(const CONFIGROOT &root);
void StopConnection();

View File

@ -201,7 +201,7 @@ namespace Qv2ray
nullptr, QObject::tr("Deprecated"),
QObject::tr("PAC is now deprecated and is not encouraged to be used anymore.") + NEWLINE +
QObject::tr("It will be removed or be provided as a plugin in the future.") + NEWLINE + NEWLINE +
QObject::tr("PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible."));
QObject::tr("PAC will still work currently, but please switch to the V2Ray built-in routing as soon as possible."));
}
else
{

View File

@ -72,7 +72,7 @@ void signalHandler(int signum)
exit(-99);
}
Qv2rayExitCode RunQv2rayApplicationScoped(int argc, char *argv[])
QPair<Qv2rayExitCode, std::optional<QString>> RunQv2rayApplicationScoped(int argc, char *argv[])
{
Qv2rayApplication app(argc, argv);
@ -80,8 +80,8 @@ Qv2rayExitCode RunQv2rayApplicationScoped(int argc, char *argv[])
switch (setupStatus)
{
case Qv2rayApplication::NORMAL: break;
case Qv2rayApplication::SINGLE_APPLICATION: return QV2RAY_SECONDARY_INSTANCE;
case Qv2rayApplication::FAILED: return QV2RAY_EARLY_SETUP_FAIL;
case Qv2rayApplication::SINGLE_APPLICATION: return { QV2RAY_SECONDARY_INSTANCE, std::nullopt };
case Qv2rayApplication::FAILED: return { QV2RAY_EARLY_SETUP_FAIL, app.tr("Qv2ray early initialization failed.") };
}
LOG("LICENCE", NEWLINE //
@ -99,12 +99,12 @@ Qv2rayExitCode RunQv2rayApplicationScoped(int argc, char *argv[])
if (!app.FindAndCreateInitialConfiguration())
{
LOG(MODULE_INIT, "Cannot find or create initial configuration file.")
return QV2RAY_CONFIG_PATH_FAIL;
return { QV2RAY_CONFIG_PATH_FAIL, app.tr("Cannot create initial config file.") };
}
if (!app.LoadConfiguration())
{
LOG(MODULE_INIT, "Cannot load existing configuration file.")
return QV2RAY_CONFIG_FILE_FAIL;
return { QV2RAY_CONFIG_FILE_FAIL, "Configuration file currupted" };
}
// Check OpenSSL version for auto-update and subscriptions
@ -123,7 +123,7 @@ Qv2rayExitCode RunQv2rayApplicationScoped(int argc, char *argv[])
NEWLINE + QObject::tr("Technical Details") + NEWLINE + //
"OSsl.Rq.V=" + osslReqVersion + NEWLINE + //
"OSsl.Cr.V=" + osslCurVersion);
return QV2RAY_SSL_FAIL;
return { QV2RAY_SSL_FAIL, app.tr("Cannot start Qv2ray without OpenSSL") };
}
app.InitializeGlobalVariables();
@ -132,7 +132,7 @@ Qv2rayExitCode RunQv2rayApplicationScoped(int argc, char *argv[])
signal(SIGUSR1, [](int) { ConnectionManager->RestartConnection(); });
signal(SIGUSR2, [](int) { ConnectionManager->StopConnection(); });
#endif
return app.RunQv2ray();
return { app.RunQv2ray(), std::nullopt };
}
int main(int argc, char *argv[])
@ -161,12 +161,26 @@ int main(int argc, char *argv[])
//
// parse the command line before starting as a Qt application
if (!Qv2rayApplication::PreInitialize(argc, argv))
{
QApplication errorApplication{ argc, argv };
QvMessageBoxWarn(nullptr, "Cannot Start Qv2ray!", "Early initialization failed!");
return QV2RAY_PRE_INITIALIZE_FAIL;
const auto rcode = RunQv2rayApplicationScoped(argc, argv);
}
const auto &[rcode, str] = RunQv2rayApplicationScoped(argc, argv);
if (rcode == QV2RAY_NEW_VERSION)
{
LOG(MODULE_INIT, "Starting new version of Qv2ray: " + Qv2rayProcessArgument._qvNewVersionPath)
QProcess::startDetached(Qv2rayProcessArgument._qvNewVersionPath, {});
}
else if (str)
{
QApplication errorApplication{ argc, argv };
QvMessageBoxWarn(nullptr, errorApplication.tr("Cannot start Qv2ray"),
ACCESS_OPTIONAL_VALUE(str) + //
NEWLINE + //
NEWLINE + //
errorApplication.tr("Qv2ray will now exit!"));
}
return rcode;
}

View File

@ -30,13 +30,6 @@
</property>
<widget class="QWidget" name="layoutWidgetx">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Json Editor</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTextEdit" name="jsonEditor">
<property name="font">
@ -47,6 +40,9 @@
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
@ -63,6 +59,13 @@
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Json Editor</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">

View File

@ -4,6 +4,7 @@
#include "core/CoreUtils.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/connection/Generation.hpp"
#include "core/handler/ConfigHandler.hpp"
#include "ui/common/UIBase.hpp"
#include "ui/models/InboundNodeModel.hpp"
#include "ui/models/OutboundNodeModel.hpp"
@ -97,17 +98,17 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QvDialog(par
domainStrategyCombo->setCurrentText(domainStrategy);
// Show connections in the node graph
for (auto in : root["inbounds"].toArray())
for (const auto &in : root["inbounds"].toArray())
{
AddInbound(INBOUND(in.toObject()));
}
for (auto out : root["outbounds"].toArray())
for (const auto &out : root["outbounds"].toArray())
{
AddOutbound(OUTBOUND(out.toObject()));
}
for (auto item : root["routing"].toObject()["rules"].toArray())
for (const auto &item : root["routing"].toObject()["rules"].toArray())
{
AddRule(RuleObject::fromJson(item.toObject()));
}
@ -120,13 +121,17 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QvDialog(par
for (auto _balancer : root["routing"].toObject()["balancers"].toArray())
{
auto _balancerObject = _balancer.toObject();
if (!_balancerObject["tag"].toString().isEmpty())
{
balancers.insert(_balancerObject["tag"].toString(), _balancerObject["selector"].toVariant().toStringList());
}
}
for (const auto &group : ConnectionManager->AllGroups())
{
importGroupBtn->addItem(GetDisplayName(group), group.toString());
}
isLoading = false;
}
@ -1056,3 +1061,22 @@ void RouteEditor::on_defaultOutboundCombo_currentTextChanged(const QString &arg1
LOADINGCHECK
defaultOutbound = arg1;
}
void RouteEditor::on_importExistingBtn_clicked()
{
const auto connId = ConnectionId{ importConnBtn->currentData(Qt::UserRole).toString() };
const auto root = ConnectionManager->GetConnectionRoot(connId);
auto outbound = root["outbounds"].toArray()[0].toObject();
outbound["tag"] = GetDisplayName(connId);
AddOutbound(OUTBOUND{ outbound });
}
void RouteEditor::on_importGroupBtn_currentIndexChanged(int)
{
const auto group = GroupId{ importGroupBtn->currentData(Qt::UserRole).toString() };
importConnBtn->clear();
for (const auto &connId : ConnectionManager->Connections(group))
{
importConnBtn->addItem(GetDisplayName(connId), connId.toString());
}
}

View File

@ -96,6 +96,10 @@ class RouteEditor
void on_defaultOutboundCombo_currentTextChanged(const QString &arg1);
void on_importExistingBtn_clicked();
void on_importGroupBtn_currentIndexChanged(int index);
public slots:
void onNodeClicked(Node &n);
void onConnectionCreated(QtNodes::Connection const &c);

View File

@ -30,14 +30,14 @@
<property name="title">
<string>Inbound</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QPushButton" name="addInboundBtn">
<property name="toolTip">
<string>Add outbound</string>
</property>
<property name="text">
<string>Add an Inbound</string>
<string>Add Inbound</string>
</property>
</widget>
</item>
@ -47,7 +47,7 @@
<string>Add default inbound from global config</string>
</property>
<property name="text">
<string>Add From Global Settings</string>
<string>Add Global Settings</string>
</property>
</widget>
</item>
@ -59,36 +59,71 @@
<property name="title">
<string>Outbound</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QPushButton" name="addOutboundBtn">
<property name="toolTip">
<string>Add outbound</string>
</property>
<property name="text">
<string>Add an Outbound</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_20">
<property name="text">
<string>New Outbound</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addOutboundBtn">
<property name="toolTip">
<string>Add outbound</string>
</property>
<property name="text">
<string>Import</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="insertBlackBtn">
<property name="toolTip">
<string>Add blackhole outbound</string>
</property>
<property name="text">
<string>Blackhole</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="insertDirectBtn">
<property name="toolTip">
<string>Add Freedom outbound</string>
</property>
<property name="text">
<string>Direct / Freedom</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="insertBlackBtn">
<property name="toolTip">
<string>Add blackhole outbound</string>
</property>
<property name="text">
<string>Add Black Hole</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="insertDirectBtn">
<property name="toolTip">
<string>Add Freedom outbound</string>
</property>
<property name="text">
<string>Add Direct</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>Existing Outbound</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="importGroupBtn"/>
</item>
<item>
<widget class="QComboBox" name="importConnBtn"/>
</item>
<item>
<widget class="QToolButton" name="importExistingBtn">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -262,7 +297,7 @@
<item row="1" column="1">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="page_2">
<property name="geometry">
@ -270,7 +305,7 @@
<x>0</x>
<y>0</y>
<width>359</width>
<height>535</height>
<height>505</height>
</rect>
</property>
<attribute name="label">
@ -371,8 +406,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>345</width>
<height>615</height>
<width>347</width>
<height>704</height>
</rect>
</property>
<attribute name="label">
@ -673,11 +708,7 @@
</layout>
</widget>
<tabstops>
<tabstop>addInboundBtn</tabstop>
<tabstop>addDefaultBtn</tabstop>
<tabstop>addOutboundBtn</tabstop>
<tabstop>insertBlackBtn</tabstop>
<tabstop>insertDirectBtn</tabstop>
<tabstop>editBtn</tabstop>
<tabstop>addRouteBtn</tabstop>
<tabstop>delBtn</tabstop>

View File

@ -100,7 +100,7 @@ void ConnectionInfoWidget::ShowDetails(const ConnectionGroupPair &_identifier)
QStringList shareLinks;
for (const auto &connection : ConnectionManager->Connections(groupId))
{
shareLinks << ConvertConfigToString({ connection, groupId }, false);
shareLinks << ConvertConfigToString({ connection, groupId }, !GlobalConfig.uiConfig.useOldShareLinkFormat);
}
//
auto complexCount = shareLinks.removeAll(QV2RAY_SERIALIZATION_COMPLEX_CONFIG_PLACEHOLDER);

View File

@ -107,6 +107,7 @@ void ConnectionItemWidget::RecalculateConnectionsCount()
{
auto connectionCount = ConnectionManager->Connections(groupId).count();
latencyLabel->setText(QSTRN(connectionCount) + " " + (connectionCount < 2 ? tr("connection") : tr("connections")));
OnGroupItemRenamed(groupId, "", originalItemName);
}
void ConnectionItemWidget::OnConnected(const ConnectionGroupPair &id)
@ -114,7 +115,7 @@ void ConnectionItemWidget::OnConnected(const ConnectionGroupPair &id)
if (id == ConnectionGroupPair{ connectionId, groupId })
{
connNameLabel->setText("" + originalItemName);
LOG(MODULE_UI, "OnConnected signal received for: " + id.connectionId.toString())
DEBUG(MODULE_UI, "ConnectionItemWidgetOnConnected signal received for: " + id.connectionId.toString())
emit RequestWidgetFocus(this);
}
}

View File

@ -104,7 +104,7 @@ void GroupManager::onRCMExportConnectionTriggered()
auto filePath = d.getSaveFileName(this, GetDisplayName(id));
if (filePath.isEmpty())
return;
auto root = RouteManager->GenerateFinalConfig({ id, currentGroupId });
auto root = RouteManager->GenerateFinalConfig({ id, currentGroupId }, false);
//
// Apply export filter
ExportConnectionFilter(root);
@ -275,6 +275,16 @@ void GroupManager::on_addGroupButton_clicked()
void GroupManager::on_updateButton_clicked()
{
if (subAddrTxt->text().trimmed().isEmpty())
{
QvMessageBoxWarn(this, tr("Update Subscription"), tr("The subscription link is empty."));
return;
}
if (!QUrl{ subAddrTxt->text() }.isValid())
{
QvMessageBoxWarn(this, tr("Update Subscription"), tr("The subscription link is invalid."));
return;
}
if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like to update the subscription?")) == QMessageBox::Yes)
{
this->setEnabled(false);

View File

@ -174,6 +174,9 @@
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>

View File

@ -240,7 +240,7 @@ void ImportConfigWindow::on_beginImportBtn_clicked()
bool ImportAsComplex = keepImportedInboundCheckBox->isChecked();
QString path = fileLineTxt->text();
if (!V2rayKernelInstance::ValidateConfig(path))
if (!V2RayKernelInstance::ValidateConfig(path))
{
QvMessageBoxWarn(this, tr("Import config file"), tr("Failed to check the validity of the config file."));
return;
@ -276,7 +276,7 @@ void ImportConfigWindow::on_selectImageBtn_clicked()
}
else
{
vmessConnectionStringTxt->appendPlainText(str.trimmed() + NEWLINE);
qrCodeLinkTxt->setText(str.trimmed());
}
}
void ImportConfigWindow::on_errorsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)

View File

@ -7,7 +7,7 @@
#include "components/ntp/QvNTPClient.hpp"
#include "core/connection/ConnectionIO.hpp"
#include "core/handler/ConfigHandler.hpp"
#include "core/kernel/V2rayKernelInteractions.hpp"
#include "core/kernel/V2RayKernelInteractions.hpp"
#include "core/settings/SettingsBackend.hpp"
#include "src/plugin-interface/QvPluginInterface.hpp"
#include "ui/styles/StyleManager.hpp"
@ -144,11 +144,11 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QvDialog(parent), Curren
enableAPI->setChecked(CurrentConfig.kernelConfig.enableAPI);
statsPortBox->setValue(CurrentConfig.kernelConfig.statsPort);
//
v2rayOutboundStatsCB->setChecked(CurrentConfig.uiConfig.graphConfig.useOutboundStats);
V2RayOutboundStatsCB->setChecked(CurrentConfig.uiConfig.graphConfig.useOutboundStats);
hasDirectStatisticsCB->setEnabled(CurrentConfig.uiConfig.graphConfig.useOutboundStats);
hasDirectStatisticsCB->setChecked(CurrentConfig.uiConfig.graphConfig.hasDirectStats);
//
pluginKernelV2rayIntegrationCB->setChecked(CurrentConfig.pluginConfig.v2rayIntegration);
pluginKernelV2RayIntegrationCB->setChecked(CurrentConfig.pluginConfig.v2rayIntegration);
pluginKernelPortAllocateCB->setValue(CurrentConfig.pluginConfig.portAllocationStart);
pluginKernelPortAllocateCB->setEnabled(CurrentConfig.pluginConfig.v2rayIntegration);
}
@ -213,6 +213,11 @@ PreferencesWindow::PreferencesWindow(QWidget *parent) : QvDialog(parent), Curren
//
SET_AUTOSTART_UI_ENABLED(CurrentConfig.autoStartBehavior == AUTO_CONNECTION_FIXED);
//
if (CurrentConfig.autoStartId.isEmpty())
{
CurrentConfig.autoStartId.groupId = DefaultGroupId;
}
//
auto autoStartConnId = CurrentConfig.autoStartId.connectionId;
auto autoStartGroupId = CurrentConfig.autoStartId.groupId;
//
@ -455,7 +460,7 @@ void PreferencesWindow::on_localDNSCb_stateChanged(int arg1)
void PreferencesWindow::on_selectVAssetBtn_clicked()
{
NEEDRESTART
QString dir = QFileDialog::getExistingDirectory(this, tr("Open V2ray assets folder"), QDir::currentPath());
QString dir = QFileDialog::getExistingDirectory(this, tr("Open V2Ray assets folder"), QDir::currentPath());
if (!dir.isEmpty())
{
@ -466,7 +471,7 @@ void PreferencesWindow::on_selectVAssetBtn_clicked()
void PreferencesWindow::on_selectVCoreBtn_clicked()
{
QString core = QFileDialog::getOpenFileName(this, tr("Open V2ray core file"), QDir::currentPath());
QString core = QFileDialog::getOpenFileName(this, tr("Open V2Ray core file"), QDir::currentPath());
if (!core.isEmpty())
{
@ -498,17 +503,17 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
#ifdef Q_OS_LINUX
// Setting up tProxy for linux
// Steps:
// --> 1. Copy V2ray core files to the QV2RAY_TPROXY_VCORE_PATH and QV2RAY_TPROXY_VCTL_PATH dir.
// --> 1. Copy V2Ray core files to the QV2RAY_TPROXY_VCORE_PATH and QV2RAY_TPROXY_VCTL_PATH dir.
// --> 2. Change GlobalConfig.v2CorePath.
// --> 3. Call `pkexec setcap
// CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the V2ray core.
// CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the V2Ray core.
auto const kernelPath = CurrentConfig.kernelConfig.KernelPath();
if (arg1 == Qt::Checked)
{
// We enable it!
if (QvMessageBoxAsk(this, tr("Enable tProxy Support"),
tr("This will append capabilities to the V2ray executable.") + NEWLINE + NEWLINE +
tr("Qv2ray will copy your V2ray core to this path: ") + NEWLINE + QV2RAY_TPROXY_VCORE_PATH + NEWLINE + NEWLINE +
tr("This will append capabilities to the V2Ray executable.") + NEWLINE + NEWLINE +
tr("Qv2ray will copy your V2Ray core to this path: ") + NEWLINE + QV2RAY_TPROXY_VCORE_PATH + NEWLINE + NEWLINE +
tr("If anything goes wrong after enabling this, please check issue #57 or the link below:") + NEWLINE +
" https://github.com/Qv2ray/Qv2ray/wiki/FAQ ") != QMessageBox::Yes)
{
@ -519,14 +524,14 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
{
LOG(MODULE_VCORE, "ENABLING tProxy Support")
LOG(MODULE_FILEIO, " --> Origin V2ray core file is at: " + kernelPath)
LOG(MODULE_FILEIO, " --> Origin V2Ray core file is at: " + kernelPath)
auto v2ctlPath = QFileInfo(kernelPath).absolutePath() + "/v2ctl";
auto newPath = QFileInfo(QV2RAY_TPROXY_VCORE_PATH).absolutePath();
QString mkPathResult = QDir().mkpath(newPath) ? "OK" : "FAILED";
LOG(MODULE_FILEIO, " --> mkPath result: " + mkPathResult)
//
LOG(MODULE_FILEIO, " --> Origin v2ctl file is at: " + v2ctlPath)
LOG(MODULE_FILEIO, " --> New V2ray files will be placed in: " + newPath)
LOG(MODULE_FILEIO, " --> New V2Ray files will be placed in: " + newPath)
//
LOG(MODULE_FILEIO, " --> Copying files....")
@ -552,10 +557,10 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
}
QString vCoreresult = QFile(kernelPath).copy(QV2RAY_TPROXY_VCORE_PATH) ? "OK" : "FAILED";
LOG(MODULE_FILEIO, " --> V2ray Core: " + vCoreresult)
LOG(MODULE_FILEIO, " --> V2Ray Core: " + vCoreresult)
//
QString vCtlresult = QFile(v2ctlPath).copy(QV2RAY_TPROXY_VCTL_PATH) ? "OK" : "FAILED";
LOG(MODULE_FILEIO, " --> V2ray Ctl: " + vCtlresult)
LOG(MODULE_FILEIO, " --> V2Ray Ctl: " + vCtlresult)
//
if (vCoreresult == "OK" && vCtlresult == "OK")
@ -565,16 +570,16 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
}
else
{
LOG(MODULE_VCORE, "FAILED to copy V2ray files. Aborting.")
LOG(MODULE_VCORE, "FAILED to copy V2Ray files. Aborting.")
QvMessageBoxWarn(this, tr("Enable tProxy Support"),
tr("Qv2ray cannot copy one or both V2ray files from: ") + NEWLINE + NEWLINE + kernelPath + NEWLINE +
tr("Qv2ray cannot copy one or both V2Ray files from: ") + NEWLINE + NEWLINE + kernelPath + NEWLINE +
v2ctlPath + NEWLINE + NEWLINE + tr("to this path: ") + NEWLINE + newPath);
return;
}
}
else
{
LOG(MODULE_VCORE, "Skipped removing files since the current V2ray core is in the default path.")
LOG(MODULE_VCORE, "Skipped removing files since the current V2Ray core is in the default path.")
LOG(MODULE_VCORE, " --> Actually because we don't know where else to obtain the files.")
}
@ -583,7 +588,7 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
if (ret != 0)
{
LOG(MODULE_UI, "WARN: setcap exits with code: " + QSTRN(ret))
QvMessageBoxWarn(this, tr("Preferences"), tr("Failed to setcap onto V2ray executable. You may need to run `setcap` manually."));
QvMessageBoxWarn(this, tr("Preferences"), tr("Failed to setcap onto V2Ray executable. You may need to run `setcap` manually."));
}
CurrentConfig.tProxySupport = true;
@ -597,7 +602,7 @@ void PreferencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
if (ret != 0)
{
LOG(MODULE_UI, "WARN: setcap exits with code: " + QSTRN(ret))
QvMessageBoxWarn(this, tr("Preferences"), tr("Failed to setcap onto V2ray executable. You may need to run `setcap` manually."));
QvMessageBoxWarn(this, tr("Preferences"), tr("Failed to setcap onto V2Ray executable. You may need to run `setcap` manually."));
}
CurrentConfig.tProxySupport = false;
@ -698,7 +703,8 @@ void PreferencesWindow::on_setSysProxyCB_stateChanged(int arg1)
void PreferencesWindow::on_autoStartSubsCombo_currentIndexChanged(const QString &arg1)
{
LOADINGCHECK if (arg1.isEmpty())
LOADINGCHECK
if (arg1.isEmpty())
{
CurrentConfig.autoStartId.clear();
autoStartConnCombo->clear();
@ -841,14 +847,14 @@ void PreferencesWindow::on_checkVCoreSettings_clicked()
return;
}
if (!V2rayKernelInstance::ValidateKernel(vcorePath, vAssetsPath, &result))
if (!V2RayKernelInstance::ValidateKernel(vcorePath, vAssetsPath, &result))
{
QvMessageBoxWarn(this, tr("V2ray Core Settings"), result);
QvMessageBoxWarn(this, tr("V2Ray Core Settings"), result);
}
else
{
QvMessageBoxInfo(this, tr("V2ray Core Settings"),
tr("V2ray path configuration check passed.") + NEWLINE + NEWLINE + tr("Current version of V2ray is: ") + NEWLINE +
QvMessageBoxInfo(this, tr("V2Ray Core Settings"),
tr("V2Ray path configuration check passed.") + NEWLINE + NEWLINE + tr("Current version of V2Ray is: ") + NEWLINE +
result);
}
}
@ -903,7 +909,7 @@ void PreferencesWindow::on_updateChannelCombo_currentIndexChanged(int index)
CurrentConfig.updateConfig.ignoredVersion.clear();
}
void PreferencesWindow::on_pluginKernelV2rayIntegrationCB_stateChanged(int arg1)
void PreferencesWindow::on_pluginKernelV2RayIntegrationCB_stateChanged(int arg1)
{
LOADINGCHECK
if (KernelInstance->ActivePluginKernelsCount() > 0)
@ -963,7 +969,7 @@ void PreferencesWindow::on_setSessionResumptionCB_stateChanged(int arg1)
LOADINGCHECK
if (arg1 == Qt::Checked)
{
QvMessageBoxWarn(this, tr("Dangerous Operation"), tr("This will make your TLS fingerpring different from common golang programs."));
QvMessageBoxWarn(this, tr("Dangerous Operation"), tr("This will make your TLS fingerpring different from common Golang programs."));
}
CurrentConfig.advancedConfig.setSessionResumption = arg1 == Qt::Checked;
}
@ -1100,8 +1106,14 @@ void PreferencesWindow::on_pushButton_clicked()
{
const auto ntpTitle = tr("NTP Checker");
const auto ntpHint = tr("Check date and time from server:");
const static QStringList ntpServerList = { "cn.pool.ntp.org", //
"cn.ntp.org.cn", //
"edu.ntp.org.cn", //
"time.pool.aliyun.com", //
"time1.cloud.tencent.com", //
"ntp.neu.edu.cn" };
bool ok = false;
QString ntpServer = QInputDialog::getText(this, ntpTitle, ntpHint, QLineEdit::Normal, "202.118.1.46", &ok).trimmed();
QString ntpServer = QInputDialog::getItem(this, ntpTitle, ntpHint, ntpServerList, 0, true, &ok).trimmed();
if (!ok)
return;
@ -1189,7 +1201,7 @@ void PreferencesWindow::on_qvNetworkUATxt_editTextChanged(const QString &arg1)
CurrentConfig.networkConfig.userAgent = arg1;
}
void PreferencesWindow::on_v2rayOutboundStatsCB_stateChanged(int arg1)
void PreferencesWindow::on_V2RayOutboundStatsCB_stateChanged(int arg1)
{
hasDirectStatisticsCB->setEnabled(arg1 == Qt::Checked);
LOADINGCHECK

View File

@ -90,7 +90,7 @@ class PreferencesWindow
void on_enableAPI_stateChanged(int arg1);
void on_startWithLoginCB_stateChanged(int arg1);
void on_updateChannelCombo_currentIndexChanged(int index);
void on_pluginKernelV2rayIntegrationCB_stateChanged(int arg1);
void on_pluginKernelV2RayIntegrationCB_stateChanged(int arg1);
void on_pluginKernelPortAllocateCB_valueChanged(int arg1);
void on_qvProxyAddressTxt_textEdited(const QString &arg1);
void on_qvProxyTypeCombo_currentTextChanged(const QString &arg1);
@ -122,10 +122,8 @@ class PreferencesWindow
void on_latencyTCPingRB_clicked();
void on_latencyICMPingRB_clicked();
void on_qvNetworkUATxt_editTextChanged(const QString &arg1);
void on_v2rayOutboundStatsCB_stateChanged(int arg1);
void on_V2RayOutboundStatsCB_stateChanged(int arg1);
void on_hasDirectStatisticsCB_stateChanged(int arg1);
void on_useOldShareLinkFormatCB_stateChanged(int arg1);
private:

View File

@ -51,7 +51,7 @@
<item row="0" column="0">
<widget class="QLabel" name="darkThemeLabel">
<property name="text">
<string>Darkmode UI Icons</string>
<string>Adapt Dark Theme</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -68,7 +68,7 @@
<item row="1" column="0">
<widget class="QLabel" name="label_36">
<property name="text">
<string>Darkmode Tray Icon</string>
<string>Adapt Dark Tray Theme</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -664,7 +664,7 @@ But could damage your server if improperly used.</string>
<item>
<widget class="QGroupBox" name="vcoresettingsGroupBox">
<property name="title">
<string>V2ray Core Settings</string>
<string>V2Ray Core Settings</string>
</property>
<layout class="QFormLayout" name="formLayout_10">
<item row="0" column="0">
@ -721,7 +721,7 @@ But could damage your server if improperly used.</string>
<item row="1" column="0">
<widget class="QLabel" name="label_46">
<property name="text">
<string>V2ray Core Executable Path</string>
<string>V2Ray Core Executable Path</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -749,7 +749,7 @@ But could damage your server if improperly used.</string>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>V2ray Assets Directory</string>
<string>V2Ray Assets Directory</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -773,7 +773,7 @@ But could damage your server if improperly used.</string>
<item row="7" column="0" colspan="2">
<widget class="QPushButton" name="checkVCoreSettings">
<property name="text">
<string>Check V2ray Core Settings</string>
<string>Check V2Ray Core Settings</string>
</property>
</widget>
</item>
@ -787,7 +787,7 @@ But could damage your server if improperly used.</string>
<item row="3" column="0">
<widget class="QLabel" name="label_68">
<property name="text">
<string>V2ray API Subsystem</string>
<string>V2Ray API Subsystem</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -804,7 +804,7 @@ But could damage your server if improperly used.</string>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>V2ray API Port</string>
<string>V2Ray API Port</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -833,12 +833,12 @@ But could damage your server if improperly used.</string>
<item row="5" column="0">
<widget class="QLabel" name="label_37">
<property name="text">
<string>Outbound Statistics (V2ray Core v4.26+)</string>
<string>Outbound Statistics (V2Ray Core v4.26+)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="v2rayOutboundStatsCB">
<widget class="QCheckBox" name="V2RayOutboundStatsCB">
<property name="toolTip">
<string>Currently:
- vmess/shadowsocks/socks/http will be treated as PROXY.
@ -876,7 +876,7 @@ But could damage your server if improperly used.</string>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_62">
<property name="text">
<string>Enabling V2ray Integration will allow the kernel benefit from the V2ray routing engine.</string>
<string>Enabling V2Ray Integration will allow the kernel benefit from the V2Ray routing engine.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -886,7 +886,7 @@ But could damage your server if improperly used.</string>
<item row="2" column="0">
<widget class="QLabel" name="label_57">
<property name="text">
<string>V2ray Integration</string>
<string>V2Ray Integration</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -894,7 +894,7 @@ But could damage your server if improperly used.</string>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="pluginKernelV2rayIntegrationCB">
<widget class="QCheckBox" name="pluginKernelV2RayIntegrationCB">
<property name="toolTip">
<string>If not checked, these features will be disabled:
@ -944,7 +944,7 @@ Custom DNS Settings</string>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_64">
<property name="text">
<string>Only V2ray Core v4.21+ is supported.</string>
<string>Only V2Ray Core v4.21+ is supported.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@ -1537,7 +1537,7 @@ Custom DNS Settings</string>
<item row="3" column="0">
<widget class="QLabel" name="label_75">
<property name="text">
<string>Use V2ray DNS for Direct Connection</string>
<string>Use V2Ray DNS for Direct Connection</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>

View File

@ -292,6 +292,14 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>All connections will be moved to default group, do you want to continue?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>The subscription link is empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>The subscription link is invalid.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ImportConfigWindow</name>
@ -1210,18 +1218,10 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Appearance</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Darkmode UI Icons</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Darkmode Tray Icon</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>UI Theme</source>
<translation type="unfinished"></translation>
@ -1393,26 +1393,10 @@ Qv2ray will give a more accurate latency value if Enabled, but makes it easy to
<source>Select</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray Assets Directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Check V2ray Core Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Plugin Kernel Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enabling V2ray Integration will allow the kernel benefit from the V2ray routing engine.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray Integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>If not checked, these features will be disabled:
@ -1546,10 +1530,6 @@ Custom DNS Settings</source>
<source>Bypass Bittorrent Protocol</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use V2ray DNS for Direct Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use Local DNS</source>
<translation type="unfinished"></translation>
@ -1666,42 +1646,18 @@ Custom DNS Settings</source>
<source>Invalid tproxy listening ipv6 address.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open V2ray assets folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open V2ray core file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable tProxy Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will append capabilities to the V2ray executable.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Qv2ray will copy your V2ray core to this path: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>If anything goes wrong after enabling this, please check issue #57 or the link below:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Qv2ray cannot copy one or both V2ray files from: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>to this path: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to setcap onto V2ray executable. You may need to run `setcap` manually.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>tProxy is not supported on macOS and Windows</source>
<translation type="unfinished"></translation>
@ -1726,18 +1682,6 @@ Custom DNS Settings</source>
<source>Failed to set auto start option.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray Core Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray path configuration check passed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current version of V2ray is: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Disabling API Subsystem</source>
<translation type="unfinished"></translation>
@ -1758,10 +1702,6 @@ Custom DNS Settings</source>
<source>You will lose the advantage of TLS and make your connection under MITM attack.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will make your TLS fingerpring different from common golang programs.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will (probably) make it easy to fingerprint your connection.</source>
<translation type="unfinished"></translation>
@ -1841,32 +1781,10 @@ This won&apos;t trigger a fork bomb, however, since Qv2ray works in singleton mo
If your V2Ray core filename happened to be &apos;qv2ray&apos;-something, you are totally free to ignore this warning.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.<byte value="xd"/>
The filename of V2Ray core is usually &apos;v2ray&apos; or &apos;v2ray.exe&apos;. Make sure to choose it wisely.<byte value="xd"/>
If you insist to proceed, we&apos;re not providing with any support.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray Core Executable Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Check System Date and Time from the Internet</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray API Subsystem</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray API Port</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Outbound Statistics (V2ray Core v4.26+)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Currently:
- vmess/shadowsocks/socks/http will be treated as PROXY.
@ -1879,11 +1797,101 @@ If you insist to proceed, we&apos;re not providing with any support.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Only V2ray Core v4.21+ is supported.</source>
<source>Old Share Link Format</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Old Share Link Format</source>
<source>Adapt Dark Theme</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Adapt Dark Tray Theme</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray Core Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray Core Executable Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray Assets Directory</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Check V2Ray Core Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray API Subsystem</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray API Port</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Outbound Statistics (V2Ray Core v4.26+)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enabling V2Ray Integration will allow the kernel benefit from the V2Ray routing engine.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray Integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Only V2Ray Core v4.21+ is supported.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Use V2Ray DNS for Direct Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open V2Ray assets folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open V2Ray core file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will append capabilities to the V2Ray executable.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Qv2ray will copy your V2Ray core to this path: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Qv2ray cannot copy one or both V2Ray files from: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to setcap onto V2Ray executable. You may need to run `setcap` manually.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray path configuration check passed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Current version of V2Ray is: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.<byte value="xd"/>
The filename of V2Ray core is usually &apos;v2ray&apos; or &apos;v2ray.exe&apos;. Make sure to choose it wisely.<byte value="xd"/>
If you insist to proceed, we&apos;re not providing with any support.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>This will make your TLS fingerpring different from common Golang programs.</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -2145,10 +2153,6 @@ If you insist to proceed, we&apos;re not providing with any support.</source>
<source>It will be removed or be provided as a plugin in the future.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Configuration Upgrade Failed</source>
<translation type="unfinished"></translation>
@ -2181,6 +2185,10 @@ If you insist to proceed, we&apos;re not providing with any support.</source>
<source>Unknown state.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>PAC will still work currently, but please switch to the V2Ray built-in routing as soon as possible.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Qv2ray::Qv2rayApplication</name>
@ -2293,11 +2301,11 @@ If you insist to proceed, we&apos;re not providing with any support.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Qv2ray - A cross-platform Qt frontend for V2ray.</source>
<source>Do not automatically connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Do not automatically connect</source>
<source>Qv2ray - A cross-platform Qt frontend for V2Ray.</source>
<translation type="unfinished"></translation>
</message>
</context>
@ -2394,74 +2402,27 @@ If you insist to proceed, we&apos;re not providing with any support.</source>
<numerusform>%1 out of %n entries have been filtered out, do you want to continue?</numerusform>
</translation>
</message>
<message>
<source>Would you like to remove them?</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>There&apos;re %n connection(s) in the group that do not belong the current subscription (any more).</source>
<translation>
<numerusform>There is %n connection in the group that do not belong to the current subscription any more.</numerusform>
<numerusform>There are %n connections in the group that do not belong to the current subscription any more.</numerusform>
</translation>
</message>
</context>
<context>
<name>Qv2ray::core::kernel::APIWorker</name>
<message>
<source>Failed to get statistics data, please check if V2ray is running properly</source>
<source>Failed to get statistics data, please check if V2Ray is running properly</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Qv2ray::core::kernel::V2rayKernelInstance</name>
<message>
<source>V2ray core executable not found.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray core file cannot be opened, please ensure there&apos;s a file instead of a folder.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core is incompatible with your platform.<byte value="xd"/>
Expected core ABI is %1, but got actual %2.<byte value="xd"/>
Maybe you have downloaded the wrong core?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray assets path is not valid.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No geoip.dat in assets path.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No geosite.dat in assets path.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray core failed with an exit code: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray core returns empty string.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Configuration Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot start V2ray</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray core settings is incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>The error is: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Invalid V2ray Instance Status.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2ray kernel failed to start.</source>
<translation type="unfinished"></translation>
</message>
<name>Qv2ray::core::kernel::V2RayKernelInstance</name>
<message>
<source>Core file is lacking executable permission for the current user.</source>
<translation type="unfinished"></translation>
@ -2478,6 +2439,64 @@ Maybe you have downloaded the wrong core?</source>
<source>Check is skipped</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core executable not found.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core file cannot be opened, please ensure there&apos;s a file instead of a folder.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core is incompatible with your platform.<byte value="xd"/>
Expected core ABI is %1, but got actual %2.<byte value="xd"/>
Maybe you have downloaded the wrong core?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray assets path is not valid.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No geoip.dat in assets path.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No geosite.dat in assets path.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core failed with an exit code: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core returns empty string.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Configuration Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Cannot start V2Ray</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray core settings is incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>The error is: </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Invalid V2Ray Instance Status.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>V2Ray kernel failed to start.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
@ -2521,42 +2540,22 @@ Maybe you have downloaded the wrong core?</source>
<source>Add outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add an Inbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add default inbound from global config</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add From Global Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add an Outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add blackhole outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add Black Hole</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add Freedom outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add Direct</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Selected Inbound/Outbound Info</source>
<translation type="unfinished"></translation>
@ -2857,6 +2856,34 @@ Maybe you have downloaded the wrong core?</source>
<source>The new tag has been used, we appended a random string to the tag.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add Inbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Add Global Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New Outbound</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Import</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Blackhole</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Direct / Freedom</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Existing Outbound</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RouteSettingsMatrix</name>

File diff suppressed because it is too large Load Diff

View File

@ -293,6 +293,14 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Would you like to update the subscription?</source>
<translation></translation>
</message>
<message>
<source>The subscription link is empty.</source>
<translation></translation>
</message>
<message>
<source>The subscription link is invalid.</source>
<translation></translation>
</message>
</context>
<context>
<name>ImportConfigWindow</name>
@ -1209,14 +1217,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Enabled</source>
<translation></translation>
</message>
<message>
<source>Darkmode UI Icons</source>
<translation>UIアイコン</translation>
</message>
<message>
<source>Darkmode Tray Icon</source>
<translation></translation>
</message>
<message>
<source>Language</source>
<translation></translation>
@ -1361,14 +1361,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source> lines</source>
<translation> </translation>
</message>
<message>
<source>V2ray Assets Directory</source>
<translation>V2rayアセットフォルダー</translation>
</message>
<message>
<source>Check V2ray Core Settings</source>
<translation>V2ray Core設定を確認する</translation>
</message>
<message>
<source>UDP Local IP</source>
<translation>UDP IP</translation>
@ -1429,34 +1421,10 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Invalid inbound listening address.</source>
<translation></translation>
</message>
<message>
<source>Open V2ray assets folder</source>
<translation>V2rayアセットフォルダーを開く</translation>
</message>
<message>
<source>Open V2ray core file</source>
<translation>V2rayコアファイルを開く</translation>
</message>
<message>
<source>This will append capabilities to the V2ray executable.</source>
<translation>V2ray実行可能ファイルに機能が追加されます</translation>
</message>
<message>
<source>Qv2ray will copy your V2ray core to this path: </source>
<translation>Qv2rayはV2rayコアを次のパスにコピーします: </translation>
</message>
<message>
<source>If anything goes wrong after enabling this, please check issue #57 or the link below:</source>
<translation>#57:</translation>
</message>
<message>
<source>Qv2ray cannot copy one or both V2ray files from: </source>
<translation>Qv2rayはV2rayファイルの一つまたは二つを以下からコピーできません: </translation>
</message>
<message>
<source>Failed to setcap onto V2ray executable. You may need to run `setcap` manually.</source>
<translation>V2ray実行可能ファイルへのsetcapに失敗しました`setcap`</translation>
</message>
<message>
<source>tProxy is not supported on macOS and Windows</source>
<translation>tProxyはmacOSおよびWindowsではサポートされていません</translation>
@ -1469,10 +1437,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>You will lose the advantage of TLS and make your connection under MITM attack.</source>
<translation>TLSの保護を失いMITMの攻撃を受ける可能性が高くなります</translation>
</message>
<message>
<source>This will make your TLS fingerpring different from common golang programs.</source>
<translation>TLS Golang </translation>
</message>
<message>
<source>This will (probably) make it easy to fingerprint your connection.</source>
<translation>()</translation>
@ -1485,18 +1449,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Failed to set auto start option.</source>
<translation></translation>
</message>
<message>
<source>V2ray Core Settings</source>
<translation>V2ray Core設定</translation>
</message>
<message>
<source>V2ray path configuration check passed.</source>
<translation>V2rayパス構成チェックに通過しました</translation>
</message>
<message>
<source>Current version of V2ray is: </source>
<translation>V2rayの現在のバージョンは次のとおりです: </translation>
</message>
<message>
<source>Bypass CN Mainland</source>
<translation></translation>
@ -1565,14 +1517,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Plugin Kernel Settings</source>
<translation></translation>
</message>
<message>
<source>Enabling V2ray Integration will allow the kernel benefit from the V2ray routing engine.</source>
<translation>V2Ray統合を有効にするとV2Rayルーティングエンジンの恩恵を受けることができます</translation>
</message>
<message>
<source>V2ray Integration</source>
<translation>V2Rayの統合</translation>
</message>
<message>
<source>If not checked, these features will be disabled:
@ -1817,10 +1761,6 @@ For example, for updating subscriptions.</source>
<source>DNS Settings</source>
<translation>DNS設定</translation>
</message>
<message>
<source>Use V2ray DNS for Direct Connection</source>
<translation>V2Ray DNSを使用</translation>
</message>
<message>
<source>You can configure default DNS settings for all simple connection config here.</source>
<translation>DNS設定を行うことができます</translation>
@ -1851,34 +1791,10 @@ If your V2Ray core filename happened to be &apos;qv2ray&apos;-something, you are
Qv2rayはシングルトンモードで動作するため
V2Rayコアのファイル名が&apos;qv2ray&apos;</translation>
</message>
<message>
<source>You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.<byte value="xd"/>
The filename of V2Ray core is usually &apos;v2ray&apos; or &apos;v2ray.exe&apos;. Make sure to choose it wisely.<byte value="xd"/>
If you insist to proceed, we&apos;re not providing with any support.</source>
<translation>V2Ray coreをV2Ray Control実行ファイルに間違って設定している可能性がありますが
V2Ray coreのファイル名は通常&apos;v2ray&apos;&apos;v2ray.exe&apos;
</translation>
</message>
<message>
<source>V2ray Core Executable Path</source>
<translation>V2rayコアのパス</translation>
</message>
<message>
<source>Check System Date and Time from the Internet</source>
<translation></translation>
</message>
<message>
<source>V2ray API Subsystem</source>
<translation>V2ray APIサブシステム</translation>
</message>
<message>
<source>V2ray API Port</source>
<translation>V2ray APIポート</translation>
</message>
<message>
<source>Outbound Statistics (V2ray Core v4.26+)</source>
<translation>V2ray Core v4.26</translation>
</message>
<message>
<source>Currently:
- vmess/shadowsocks/socks/http will be treated as PROXY.
@ -1893,14 +1809,106 @@ V2Ray coreのファイル名は通常&apos;v2ray&apos;または&apos;v2ray.exe&a
<source>Include Direct Connection</source>
<translation></translation>
</message>
<message>
<source>Only V2ray Core v4.21+ is supported.</source>
<translation>V2ray Core v4.21</translation>
</message>
<message>
<source>Old Share Link Format</source>
<translation></translation>
</message>
<message>
<source>Adapt Dark Theme</source>
<translation></translation>
</message>
<message>
<source>Adapt Dark Tray Theme</source>
<translation></translation>
</message>
<message>
<source>V2Ray Core Settings</source>
<translation>V2Rayコア設定</translation>
</message>
<message>
<source>V2Ray Core Executable Path</source>
<translation>V2Ray </translation>
</message>
<message>
<source>V2Ray Assets Directory</source>
<translation>V2Ray </translation>
</message>
<message>
<source>Check V2Ray Core Settings</source>
<translation>V2Rayコア設定を確認する</translation>
</message>
<message>
<source>V2Ray API Subsystem</source>
<translation>V2Ray APIサブシステム</translation>
</message>
<message>
<source>V2Ray API Port</source>
<translation>V2Ray APIポート</translation>
</message>
<message>
<source>Outbound Statistics (V2Ray Core v4.26+)</source>
<translation>V2Rayコアv4.26</translation>
</message>
<message>
<source>Enabling V2Ray Integration will allow the kernel benefit from the V2Ray routing engine.</source>
<translation>V2Ray統合を有効にするとV2Rayルーティングエンジンの恩恵を受けることができます</translation>
</message>
<message>
<source>V2Ray Integration</source>
<translation>V2Rayの統合</translation>
</message>
<message>
<source>Only V2Ray Core v4.21+ is supported.</source>
<translation>V2Rayコアv4.21</translation>
</message>
<message>
<source>Use V2Ray DNS for Direct Connection</source>
<translation>V2Ray DNSを使用</translation>
</message>
<message>
<source>Open V2Ray assets folder</source>
<translation>V2Rayアセットフォルダーを開く</translation>
</message>
<message>
<source>Open V2Ray core file</source>
<translation>V2Rayコアファイルを開く</translation>
</message>
<message>
<source>This will append capabilities to the V2Ray executable.</source>
<translation>V2Ray実行可能ファイルに機能が追加されます</translation>
</message>
<message>
<source>Qv2ray will copy your V2Ray core to this path: </source>
<translation>Qv2rayはV2Rayコアを次のパスにコピーします: </translation>
</message>
<message>
<source>Qv2ray cannot copy one or both V2Ray files from: </source>
<translation>Qv2rayはV2Rayファイルの一つまたは二つを以下からコピーできません: </translation>
</message>
<message>
<source>Failed to setcap onto V2Ray executable. You may need to run `setcap` manually.</source>
<translation>V2Ray実行可能ファイルへのsetcapに失敗しました`setcap`</translation>
</message>
<message>
<source>V2Ray path configuration check passed.</source>
<translation>V2Rayパス構成チェックに通過しました</translation>
</message>
<message>
<source>Current version of V2Ray is: </source>
<translation>V2Rayの現在のバージョンは次のとおりです: </translation>
</message>
<message>
<source>You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.<byte value="xd"/>
The filename of V2Ray core is usually &apos;v2ray&apos; or &apos;v2ray.exe&apos;. Make sure to choose it wisely.<byte value="xd"/>
If you insist to proceed, we&apos;re not providing with any support.</source>
<translation>V2RayコアをV2Ray制御実行ファイルに間違って設定している可能性がありますが
V2Rayコアのファイル名は通常&apos;v2ray&apos;&apos;v2ray.exe&apos;
</translation>
</message>
<message>
<source>This will make your TLS fingerpring different from common Golang programs.</source>
<translation>TLSのフィンガースプリングが一般的なGolangプログラムとは異なるものになります</translation>
</message>
</context>
<context>
<name>QObject</name>
@ -2004,10 +2012,6 @@ V2Ray coreのファイル名は通常&apos;v2ray&apos;または&apos;v2ray.exe&a
<source>It will be removed or be provided as a plugin in the future.</source>
<translation></translation>
</message>
<message>
<source>PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible.</source>
<translation>PACは現在も機能しますがV2Rayの組み込みルーティングに切り替えてください</translation>
</message>
<message>
<source>Configuration Upgrade Failed</source>
<translation></translation>
@ -2196,6 +2200,10 @@ V2Ray coreのファイル名は通常&apos;v2ray&apos;または&apos;v2ray.exe&a
<source>Unknown state.</source>
<translation></translation>
</message>
<message>
<source>PAC will still work currently, but please switch to the V2Ray built-in routing as soon as possible.</source>
<translation>PACは現在も機能しますがV2Rayの組み込みルーティングに切り替えてください</translation>
</message>
</context>
<context>
<name>Qv2ray::Qv2rayApplication</name>
@ -2307,14 +2315,14 @@ V2Ray coreのファイル名は通常&apos;v2ray&apos;または&apos;v2ray.exe&a
<source>Exit Qv2ray</source>
<translation>Qv2rayを終了</translation>
</message>
<message>
<source>Qv2ray - A cross-platform Qt frontend for V2ray.</source>
<translation>Qv2ray - V2Ray用のクロスプラットフォームQtフロントエンド</translation>
</message>
<message>
<source>Do not automatically connect</source>
<translation></translation>
</message>
<message>
<source>Qv2ray - A cross-platform Qt frontend for V2Ray.</source>
<translation>Qv2ray - V2Ray用のクロスプラットフォームQtフロントエンド</translation>
</message>
</context>
<context>
<name>Qv2ray::components::QvUpdateChecker</name>
@ -2407,76 +2415,26 @@ V2Ray coreのファイル名は通常&apos;v2ray&apos;または&apos;v2ray.exe&a
<numerusform>%n %1 </numerusform>
</translation>
</message>
<message>
<source>Would you like to remove them?</source>
<translation></translation>
</message>
<message numerus="yes">
<source>There&apos;re %n connection(s) in the group that do not belong the current subscription (any more).</source>
<translation>
<numerusform> %n </numerusform>
</translation>
</message>
</context>
<context>
<name>Qv2ray::core::kernel::APIWorker</name>
<message>
<source>Failed to get statistics data, please check if V2ray is running properly</source>
<translation>V2rayが正常に動作しているか確認してください</translation>
<source>Failed to get statistics data, please check if V2Ray is running properly</source>
<translation>V2Rayが正常に動作しているか確認してください</translation>
</message>
</context>
<context>
<name>Qv2ray::core::kernel::V2rayKernelInstance</name>
<message>
<source>V2ray core executable not found.</source>
<translation>V2rayコア実行可能ファイルが見つかりません</translation>
</message>
<message>
<source>V2ray core file cannot be opened, please ensure there&apos;s a file instead of a folder.</source>
<translation>V2rayコアファイルを開けません</translation>
</message>
<message>
<source>V2Ray core is incompatible with your platform.<byte value="xd"/>
Expected core ABI is %1, but got actual %2.<byte value="xd"/>
Maybe you have downloaded the wrong core?</source>
<translation>V2Rayコアはプラットフォームと互換性がありません
ABIは%1%2
</translation>
</message>
<message>
<source>V2ray assets path is not valid.</source>
<translation>V2rayアセットのパスが無効です</translation>
</message>
<message>
<source>No geoip.dat in assets path.</source>
<translation>geoip.datはありません</translation>
</message>
<message>
<source>No geosite.dat in assets path.</source>
<translation>geosite.datはありません</translation>
</message>
<message>
<source>V2ray core failed with an exit code: </source>
<translation>V2rayコアがエラー終了しました: </translation>
</message>
<message>
<source>V2ray core returns empty string.</source>
<translation>V2rayコアは空の文字列を返します</translation>
</message>
<message>
<source>Configuration Error</source>
<translation></translation>
</message>
<message>
<source>Cannot start V2ray</source>
<translation>V2rayを起動できません</translation>
</message>
<message>
<source>V2ray core settings is incorrect.</source>
<translation>V2rayコアの設定が正しくありません</translation>
</message>
<message>
<source>The error is: </source>
<translation>: </translation>
</message>
<message>
<source>Invalid V2ray Instance Status.</source>
<translation>V2rayインスタンスステータス</translation>
</message>
<message>
<source>V2ray kernel failed to start.</source>
<translation>V2rayカーネルの起動に失敗しました</translation>
</message>
<name>Qv2ray::core::kernel::V2RayKernelInstance</name>
<message>
<source>Core file is lacking executable permission for the current user.</source>
<translation></translation>
@ -2493,6 +2451,66 @@ Maybe you have downloaded the wrong core?</source>
<source>Check is skipped</source>
<translation></translation>
</message>
<message>
<source>V2Ray core executable not found.</source>
<translation>V2Rayコア実行可能ファイルが見つかりません</translation>
</message>
<message>
<source>V2Ray core file cannot be opened, please ensure there&apos;s a file instead of a folder.</source>
<translation>V2Rayコアファイルを開けません</translation>
</message>
<message>
<source>V2Ray core is incompatible with your platform.<byte value="xd"/>
Expected core ABI is %1, but got actual %2.<byte value="xd"/>
Maybe you have downloaded the wrong core?</source>
<translation>V2Rayコアはプラットフォームと互換性がありません
ABIは%1%2
</translation>
</message>
<message>
<source>V2Ray assets path is not valid.</source>
<translation>V2Rayアセットのパスが無効です</translation>
</message>
<message>
<source>No geoip.dat in assets path.</source>
<translation>geoip.datはありません</translation>
</message>
<message>
<source>No geosite.dat in assets path.</source>
<translation>geosite.datはありません</translation>
</message>
<message>
<source>V2Ray core failed with an exit code: </source>
<translation>V2Rayコアがエラー終了しました: </translation>
</message>
<message>
<source>V2Ray core returns empty string.</source>
<translation>V2Rayコアは空の文字列を返します</translation>
</message>
<message>
<source>Configuration Error</source>
<translation></translation>
</message>
<message>
<source>Cannot start V2Ray</source>
<translation>V2Rayを起動できません</translation>
</message>
<message>
<source>V2Ray core settings is incorrect.</source>
<translation>V2Rayコアの設定が正しくありません</translation>
</message>
<message>
<source>The error is: </source>
<translation>: </translation>
</message>
<message>
<source>Invalid V2Ray Instance Status.</source>
<translation>V2Rayインスタンスステータス</translation>
</message>
<message>
<source>V2Ray kernel failed to start.</source>
<translation>V2Rayカーネルの起動に失敗しました</translation>
</message>
</context>
<context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
@ -2628,18 +2646,6 @@ Maybe you have downloaded the wrong core?</source>
<source>Inbound</source>
<translation></translation>
</message>
<message>
<source>Add From Global Settings</source>
<translation></translation>
</message>
<message>
<source>Add Black Hole</source>
<translation></translation>
</message>
<message>
<source>Add Direct</source>
<translation></translation>
</message>
<message>
<source>Selected Inbound/Outbound Info</source>
<translation>/</translation>
@ -2856,14 +2862,6 @@ Maybe you have downloaded the wrong core?</source>
<source>Add Rule</source>
<translation></translation>
</message>
<message>
<source>Add an Inbound</source>
<translation></translation>
</message>
<message>
<source>Add an Outbound</source>
<translation></translation>
</message>
<message>
<source>Misc Settings</source>
<translation></translation>
@ -2872,6 +2870,34 @@ Maybe you have downloaded the wrong core?</source>
<source>Rename</source>
<translation></translation>
</message>
<message>
<source>Add Inbound</source>
<translation></translation>
</message>
<message>
<source>Add Global Settings</source>
<translation></translation>
</message>
<message>
<source>New Outbound</source>
<translation></translation>
</message>
<message>
<source>Import</source>
<translation></translation>
</message>
<message>
<source>Blackhole</source>
<translation></translation>
</message>
<message>
<source>Direct / Freedom</source>
<translation></translation>
</message>
<message>
<source>Existing Outbound</source>
<translation></translation>
</message>
</context>
<context>
<name>RouteSettingsMatrix</name>

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,7 @@
<RCC>
<qresource prefix="/translations">
<file>en_US.qm</file>
<file>ru_RU.qm</file>
<file>ja_JP.qm</file>
<file>zh_CN.qm</file>
<file>es_ES.qm</file>
</qresource>
</RCC>

View File

@ -293,6 +293,14 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Would you like to update the subscription?</source>
<translation></translation>
</message>
<message>
<source>The subscription link is empty.</source>
<translation></translation>
</message>
<message>
<source>The subscription link is invalid.</source>
<translation></translation>
</message>
</context>
<context>
<name>ImportConfigWindow</name>
@ -950,7 +958,7 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
</message>
<message>
<source>Set as automatically connected</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Edit</source>
@ -1209,14 +1217,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Enabled</source>
<translation></translation>
</message>
<message>
<source>Darkmode UI Icons</source>
<translation> UI </translation>
</message>
<message>
<source>Darkmode Tray Icon</source>
<translation></translation>
</message>
<message>
<source>Language</source>
<translation></translation>
@ -1353,14 +1353,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source> lines</source>
<translation> </translation>
</message>
<message>
<source>V2ray Assets Directory</source>
<translation>V2ray </translation>
</message>
<message>
<source>Check V2ray Core Settings</source>
<translation> V2ray </translation>
</message>
<message>
<source>UDP Local IP</source>
<translation>UDP IP</translation>
@ -1409,34 +1401,10 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Invalid inbound listening address.</source>
<translation></translation>
</message>
<message>
<source>Open V2ray assets folder</source>
<translation> V2ray </translation>
</message>
<message>
<source>Open V2ray core file</source>
<translation> V2ray </translation>
</message>
<message>
<source>This will append capabilities to the V2ray executable.</source>
<translation> V2ray </translation>
</message>
<message>
<source>Qv2ray will copy your V2ray core to this path: </source>
<translation>Qv2ray V2ray </translation>
</message>
<message>
<source>If anything goes wrong after enabling this, please check issue #57 or the link below:</source>
<translation> Issue #57 </translation>
</message>
<message>
<source>Qv2ray cannot copy one or both V2ray files from: </source>
<translation>Qv2ray V2ray </translation>
</message>
<message>
<source>Failed to setcap onto V2ray executable. You may need to run `setcap` manually.</source>
<translation> Capcap V2ray setcap</translation>
</message>
<message>
<source>tProxy is not supported on macOS and Windows</source>
<translation> macOS Windows tProxy</translation>
@ -1461,18 +1429,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Failed to set auto start option.</source>
<translation></translation>
</message>
<message>
<source>V2ray Core Settings</source>
<translation>V2ray </translation>
</message>
<message>
<source>V2ray path configuration check passed.</source>
<translation>V2ray </translation>
</message>
<message>
<source>Current version of V2ray is: </source>
<translation>V2ray </translation>
</message>
<message>
<source>Transparent Proxy Settings</source>
<translation></translation>
@ -1561,14 +1517,6 @@ This entry is ignored by V2Ray core when using DoH servers.</source>
<source>Plugin Kernel Settings</source>
<translation></translation>
</message>
<message>
<source>Enabling V2ray Integration will allow the kernel benefit from the V2ray routing engine.</source>
<translation> V2Ray V2Ray </translation>
</message>
<message>
<source>V2ray Integration</source>
<translation>V2Ray </translation>
</message>
<message>
<source>If not checked, these features will be disabled:
@ -1813,10 +1761,6 @@ For example, for updating subscriptions.</source>
<source>DNS Settings</source>
<translation>DNS </translation>
</message>
<message>
<source>Use V2ray DNS for Direct Connection</source>
<translation>使 V2Ray DNS</translation>
</message>
<message>
<source>You can configure default DNS settings for all simple connection config here.</source>
<translation> DNS </translation>
@ -1835,10 +1779,6 @@ But could damage your server if improperly used.</source>
<translation>
使</translation>
</message>
<message>
<source>This will make your TLS fingerpring different from common golang programs.</source>
<translation> TLS Golang </translation>
</message>
<message>
<source>Watch Out!</source>
<translation></translation>
@ -1851,34 +1791,10 @@ If your V2Ray core filename happened to be &apos;qv2ray&apos;-something, you are
Fork Qv2ray
V2Ray &apos;qv2ray&apos; </translation>
</message>
<message>
<source>You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.<byte value="xd"/>
The filename of V2Ray core is usually &apos;v2ray&apos; or &apos;v2ray.exe&apos;. Make sure to choose it wisely.<byte value="xd"/>
If you insist to proceed, we&apos;re not providing with any support.</source>
<translation> V2Ray V2Ray
V2Ray &apos;v2ray&apos; &apos;v2ray.exe&apos;
</translation>
</message>
<message>
<source>V2ray Core Executable Path</source>
<translation>V2ray </translation>
</message>
<message>
<source>Check System Date and Time from the Internet</source>
<translation></translation>
</message>
<message>
<source>V2ray API Subsystem</source>
<translation>V2Ray API </translation>
</message>
<message>
<source>V2ray API Port</source>
<translation>V2Ray API </translation>
</message>
<message>
<source>Outbound Statistics (V2ray Core v4.26+)</source>
<translation> (V2Ray v2.46+)</translation>
</message>
<message>
<source>Currently:
- vmess/shadowsocks/socks/http will be treated as PROXY.
@ -1894,12 +1810,104 @@ V2Ray 核心的文件名通常为 &apos;v2ray&apos; 或者 &apos;v2ray.exe&apos;
<translation></translation>
</message>
<message>
<source>Only V2ray Core v4.21+ is supported.</source>
<source>Old Share Link Format</source>
<translation> VMess </translation>
</message>
<message>
<source>Adapt Dark Theme</source>
<translation></translation>
</message>
<message>
<source>Adapt Dark Tray Theme</source>
<translation></translation>
</message>
<message>
<source>V2Ray Core Settings</source>
<translation>V2Ray </translation>
</message>
<message>
<source>V2Ray Core Executable Path</source>
<translation>V2Ray </translation>
</message>
<message>
<source>V2Ray Assets Directory</source>
<translation>V2Ray </translation>
</message>
<message>
<source>Check V2Ray Core Settings</source>
<translation> V2Ray </translation>
</message>
<message>
<source>V2Ray API Subsystem</source>
<translation>V2Ray API </translation>
</message>
<message>
<source>V2Ray API Port</source>
<translation>V2Ray API </translation>
</message>
<message>
<source>Outbound Statistics (V2Ray Core v4.26+)</source>
<translation> (V2Ray v4.26+)</translation>
</message>
<message>
<source>Enabling V2Ray Integration will allow the kernel benefit from the V2Ray routing engine.</source>
<translation> V2Ray V2Ray </translation>
</message>
<message>
<source>V2Ray Integration</source>
<translation>V2Ray </translation>
</message>
<message>
<source>Only V2Ray Core v4.21+ is supported.</source>
<translation> V2Ray v4.21+</translation>
</message>
<message>
<source>Old Share Link Format</source>
<translation> VMess </translation>
<source>Use V2Ray DNS for Direct Connection</source>
<translation>使 V2Ray DNS</translation>
</message>
<message>
<source>Open V2Ray assets folder</source>
<translation> V2Ray </translation>
</message>
<message>
<source>Open V2Ray core file</source>
<translation> V2Ray </translation>
</message>
<message>
<source>This will append capabilities to the V2Ray executable.</source>
<translation> V2Ray </translation>
</message>
<message>
<source>Qv2ray will copy your V2Ray core to this path: </source>
<translation>Qv2ray V2Ray : </translation>
</message>
<message>
<source>Qv2ray cannot copy one or both V2Ray files from: </source>
<translation>Qv2ray V2Ray : </translation>
</message>
<message>
<source>Failed to setcap onto V2Ray executable. You may need to run `setcap` manually.</source>
<translation> V2Ray setcap setcap</translation>
</message>
<message>
<source>V2Ray path configuration check passed.</source>
<translation>V2Ray </translation>
</message>
<message>
<source>Current version of V2Ray is: </source>
<translation>V2Ray : </translation>
</message>
<message>
<source>You may be about to set V2Ray core incorrectly to V2Ray Control executable, which is absolutely not correct.<byte value="xd"/>
The filename of V2Ray core is usually &apos;v2ray&apos; or &apos;v2ray.exe&apos;. Make sure to choose it wisely.<byte value="xd"/>
If you insist to proceed, we&apos;re not providing with any support.</source>
<translation> V2Ray V2Ray
V2Ray &apos;v2ray&apos; &apos;v2ray.exe&apos;
</translation>
</message>
<message>
<source>This will make your TLS fingerpring different from common Golang programs.</source>
<translation>使 TLS Golang </translation>
</message>
</context>
<context>
@ -1956,10 +1964,6 @@ V2Ray 核心的文件名通常为 &apos;v2ray&apos; 或者 &apos;v2ray.exe&apos;
<source>It will be removed or be provided as a plugin in the future.</source>
<translation></translation>
</message>
<message>
<source>PAC will still work currently, but please switch to the V2ray built-in routing as soon as possible.</source>
<translation>PAC 使 V2ray </translation>
</message>
<message>
<source>Configuration Upgrade Failed</source>
<translation></translation>
@ -2196,6 +2200,10 @@ V2Ray 核心的文件名通常为 &apos;v2ray&apos; 或者 &apos;v2ray.exe&apos;
<source>Unknown state.</source>
<translation></translation>
</message>
<message>
<source>PAC will still work currently, but please switch to the V2Ray built-in routing as soon as possible.</source>
<translation>PAC 使 V2Ray </translation>
</message>
</context>
<context>
<name>Qv2ray::Qv2rayApplication</name>
@ -2307,14 +2315,14 @@ V2Ray 核心的文件名通常为 &apos;v2ray&apos; 或者 &apos;v2ray.exe&apos;
<source>Exit Qv2ray</source>
<translation>退 Qv2ray</translation>
</message>
<message>
<source>Qv2ray - A cross-platform Qt frontend for V2ray.</source>
<translation>Qv2ray - V2Ray Qt </translation>
</message>
<message>
<source>Do not automatically connect</source>
<translation></translation>
</message>
<message>
<source>Qv2ray - A cross-platform Qt frontend for V2Ray.</source>
<translation>Qv2ray - V2Ray Qt </translation>
</message>
</context>
<context>
<name>Qv2ray::components::QvUpdateChecker</name>
@ -2407,76 +2415,26 @@ V2Ray 核心的文件名通常为 &apos;v2ray&apos; 或者 &apos;v2ray.exe&apos;
<numerusform>%n %1 </numerusform>
</translation>
</message>
<message>
<source>Would you like to remove them?</source>
<translation></translation>
</message>
<message numerus="yes">
<source>There&apos;re %n connection(s) in the group that do not belong the current subscription (any more).</source>
<translation>
<numerusform> %n </numerusform>
</translation>
</message>
</context>
<context>
<name>Qv2ray::core::kernel::APIWorker</name>
<message>
<source>Failed to get statistics data, please check if V2ray is running properly</source>
<source>Failed to get statistics data, please check if V2Ray is running properly</source>
<translation> V2Ray </translation>
</message>
</context>
<context>
<name>Qv2ray::core::kernel::V2rayKernelInstance</name>
<message>
<source>V2ray core executable not found.</source>
<translation>V2ray </translation>
</message>
<message>
<source>V2ray core file cannot be opened, please ensure there&apos;s a file instead of a folder.</source>
<translation> V2ray </translation>
</message>
<message>
<source>V2Ray core is incompatible with your platform.<byte value="xd"/>
Expected core ABI is %1, but got actual %2.<byte value="xd"/>
Maybe you have downloaded the wrong core?</source>
<translation>V2Ray
ABI %1 %2
</translation>
</message>
<message>
<source>V2ray assets path is not valid.</source>
<translation>V2ray Assets </translation>
</message>
<message>
<source>No geoip.dat in assets path.</source>
<translation> Assets geoip.dat</translation>
</message>
<message>
<source>No geosite.dat in assets path.</source>
<translation> Assets geosite.dat</translation>
</message>
<message>
<source>V2ray core failed with an exit code: </source>
<translation>V2ray 退 </translation>
</message>
<message>
<source>V2ray core returns empty string.</source>
<translation>V2ray </translation>
</message>
<message>
<source>Configuration Error</source>
<translation></translation>
</message>
<message>
<source>Cannot start V2ray</source>
<translation> V2ray</translation>
</message>
<message>
<source>V2ray core settings is incorrect.</source>
<translation>V2ray </translation>
</message>
<message>
<source>The error is: </source>
<translation> </translation>
</message>
<message>
<source>Invalid V2ray Instance Status.</source>
<translation>V2ray </translation>
</message>
<message>
<source>V2ray kernel failed to start.</source>
<translation>V2ray </translation>
</message>
<name>Qv2ray::core::kernel::V2RayKernelInstance</name>
<message>
<source>Core file is lacking executable permission for the current user.</source>
<translation> V2Ray </translation>
@ -2493,6 +2451,66 @@ Maybe you have downloaded the wrong core?</source>
<source>Check is skipped</source>
<translation></translation>
</message>
<message>
<source>V2Ray core executable not found.</source>
<translation>V2Ray </translation>
</message>
<message>
<source>V2Ray core file cannot be opened, please ensure there&apos;s a file instead of a folder.</source>
<translation> V2Ray </translation>
</message>
<message>
<source>V2Ray core is incompatible with your platform.<byte value="xd"/>
Expected core ABI is %1, but got actual %2.<byte value="xd"/>
Maybe you have downloaded the wrong core?</source>
<translation>V2Ray
ABI %1 %2
</translation>
</message>
<message>
<source>V2Ray assets path is not valid.</source>
<translation>V2Ray </translation>
</message>
<message>
<source>No geoip.dat in assets path.</source>
<translation> V2Ray geoip.dat</translation>
</message>
<message>
<source>No geosite.dat in assets path.</source>
<translation> V2Ray geosite.dat</translation>
</message>
<message>
<source>V2Ray core failed with an exit code: </source>
<translation>V2Ray 退: </translation>
</message>
<message>
<source>V2Ray core returns empty string.</source>
<translation>V2Ray </translation>
</message>
<message>
<source>Configuration Error</source>
<translation></translation>
</message>
<message>
<source>Cannot start V2Ray</source>
<translation> V2Ray</translation>
</message>
<message>
<source>V2Ray core settings is incorrect.</source>
<translation>V2Ray </translation>
</message>
<message>
<source>The error is: </source>
<translation>: </translation>
</message>
<message>
<source>Invalid V2Ray Instance Status.</source>
<translation>V2Ray </translation>
</message>
<message>
<source>V2Ray kernel failed to start.</source>
<translation>V2Ray </translation>
</message>
</context>
<context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>
@ -2628,18 +2646,6 @@ Maybe you have downloaded the wrong core?</source>
<source>Inbound</source>
<translation></translation>
</message>
<message>
<source>Add From Global Settings</source>
<translation></translation>
</message>
<message>
<source>Add Black Hole</source>
<translation></translation>
</message>
<message>
<source>Add Direct</source>
<translation></translation>
</message>
<message>
<source>Selected Inbound/Outbound Info</source>
<translation></translation>
@ -2856,14 +2862,6 @@ Maybe you have downloaded the wrong core?</source>
<source>Add Rule</source>
<translation></translation>
</message>
<message>
<source>Add an Inbound</source>
<translation></translation>
</message>
<message>
<source>Add an Outbound</source>
<translation></translation>
</message>
<message>
<source>Misc Settings</source>
<translation></translation>
@ -2872,6 +2870,34 @@ Maybe you have downloaded the wrong core?</source>
<source>Rename</source>
<translation></translation>
</message>
<message>
<source>Add Inbound</source>
<translation></translation>
</message>
<message>
<source>Add Global Settings</source>
<translation></translation>
</message>
<message>
<source>New Outbound</source>
<translation></translation>
</message>
<message>
<source>Import</source>
<translation></translation>
</message>
<message>
<source>Blackhole</source>
<translation></translation>
</message>
<message>
<source>Direct / Freedom</source>
<translation> / </translation>
</message>
<message>
<source>Existing Outbound</source>
<translation></translation>
</message>
</context>
<context>
<name>RouteSettingsMatrix</name>
@ -3230,7 +3256,7 @@ Maybe you have downloaded the wrong core?</source>
</message>
<message>
<source>This group is a subscription</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Name</source>