Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d89238e1aa | ||
|
|
52710020ea | ||
|
|
a18b8f4f2b | ||
|
|
01e0a6570d | ||
|
|
cd6ef8f062 | ||
|
|
ea383c43bd | ||
|
|
68e08e3866 | ||
|
|
329ed26e85 | ||
|
|
c830a4cea4 | ||
|
|
e7e088ec83 | ||
|
|
cf6c814eb4 | ||
|
|
8f62e42ae8 | ||
|
|
89b4060ba2 | ||
|
|
e4d4b329a0 | ||
|
|
09c5f41995 | ||
|
|
02b25787c1 | ||
|
|
cdb050b6c5 | ||
|
|
21f47b536d | ||
|
|
f14484c986 | ||
|
|
358dd78dc3 | ||
|
|
d79e072316 | ||
|
|
c24dee567a | ||
|
|
9f75bafcea | ||
|
|
2150452629 | ||
|
|
507a32a08e | ||
|
|
44dee8e850 | ||
|
|
5e4d9246c2 | ||
|
|
9fe7419467 | ||
|
|
41b2251dfe | ||
|
|
73fad43573 | ||
|
|
4676717582 | ||
|
|
834766e6e7 | ||
|
|
e304dce347 | ||
|
|
61654aefeb | ||
|
|
1664aaa25b | ||
|
|
68f1f64f3d | ||
|
|
7bad57ca52 | ||
|
|
1c8e1f0993 | ||
|
|
6037ae6fc4 | ||
|
|
dc1c5400b8 | ||
|
|
9ae4688171 | ||
|
|
e3f39234b2 | ||
|
|
0df0b2d6ac | ||
|
|
9ce96d0591 | ||
|
|
a7ef0618ba | ||
|
|
cc9b083e5d | ||
|
|
5af322552c | ||
|
|
fc852281dd | ||
|
|
0b2f036a22 | ||
|
|
cf2becb5e9 | ||
|
|
82d8eba1b9 | ||
|
|
286ad34d94 | ||
|
|
ff0bc6594d | ||
|
|
7b8113aef1 | ||
|
|
81d2ef5db5 | ||
|
|
bdea3ef88c | ||
|
|
c62c86fc29 | ||
|
|
59f698f755 | ||
|
|
9ac979006e | ||
|
|
da6291a965 | ||
|
|
bf6555e57c | ||
|
|
35b114220e | ||
|
|
800bb6a4e9 | ||
|
|
2c80521f5b | ||
|
|
6351ce5991 | ||
|
|
683362f0ee | ||
|
|
84fc909339 | ||
|
|
74171e26db | ||
|
|
f25c0cc890 | ||
|
|
29848053a4 | ||
|
|
0d9856919e | ||
|
|
0ae7f2f7b3 | ||
|
|
3dde6b0ca3 | ||
|
|
6b28208044 | ||
|
|
13f855e3c4 | ||
|
|
c870595e98 | ||
|
|
ae19a3f68d | ||
|
|
545afc41b3 | ||
|
|
7177d88144 | ||
|
|
294ed50afd | ||
|
|
0105fe48f7 | ||
|
|
c7ff23e3d5 | ||
|
|
23e9d7fde5 | ||
|
|
c93edd8875 | ||
|
|
caa2edcf05 | ||
|
|
dbe78d0aa5 | ||
|
|
71f2f590a7 | ||
|
|
ed26120581 | ||
|
|
71bd684b46 | ||
|
|
02ae19f0c7 | ||
|
|
062c0d8ddb | ||
|
|
775fa5ea62 | ||
|
|
a5bb39ac8a | ||
|
|
073c7c0410 | ||
|
|
7e88e3ba4f |
64
.github/workflows/build.yml
vendored
Normal file
64
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Build APK
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
XRAY_CORE_VERSION:
|
||||
description: 'Xray core version or commit hash'
|
||||
required: false
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.21.4'
|
||||
|
||||
- name: Install gomobile
|
||||
run: |
|
||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
|
||||
|
||||
|
||||
- name: Setup Android environment
|
||||
uses: android-actions/setup-android@v2
|
||||
|
||||
|
||||
- name: Build dependencies
|
||||
run: |
|
||||
mkdir ${{ github.workspace }}/build
|
||||
cd ${{ github.workspace }}/build
|
||||
git clone --depth=1 -b main https://github.com/2dust/AndroidLibXrayLite.git
|
||||
cd AndroidLibXrayLite
|
||||
go get github.com/xtls/xray-core@${{ github.event.inputs.XRAY_CORE_VERSION }} || true
|
||||
gomobile init
|
||||
go mod tidy -v
|
||||
gomobile bind -v -androidapi 19 -ldflags='-s -w' ./
|
||||
cp *.aar ${{ github.workspace }}/V2rayNG/app/libs/
|
||||
|
||||
- name: Build APK
|
||||
run: |
|
||||
cd ${{ github.workspace }}/V2rayNG
|
||||
chmod 777 *
|
||||
sed -i 's/org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8/org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8/' ${{ github.workspace }}/V2rayNG/gradle.properties
|
||||
./gradlew assembleDebug
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: apk
|
||||
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/
|
||||
41
CR.md
41
CR.md
@@ -1,29 +1,40 @@
|
||||
v2rayNG 隐私条款
|
||||
**v2rayNG 隐私权政策**
|
||||
|
||||
最后更新 2017-11-22
|
||||
本政策自2023年11月17日起施行
|
||||
|
||||
v2rayNG 尊重并保护所有用户的个人隐私权,为此我们向大众公开这份隐私条款。**您使用 v2rayNG 即代表您以阅读并同意了这份条款,如果您不同意这份条款请立即停止使用并卸载 v2rayNG。**
|
||||
2dust 将 v2rayNG 应用程序构建为开源应用程序。 本服务由 2dust 免费提供,并且旨在按原样使用。
|
||||
|
||||
1. 信息收集
|
||||
v2rayNG 尊重并保护所有用户的个人隐私权,为此我们向大众公开这份隐私权政策。**您使用 v2rayNG 即代表您以阅读并同意了这份条款,如果您不同意这份条款请立即停止使用并卸载 v2rayNG。**
|
||||
|
||||
v2rayNG 软件自身不会发送任何信息到开发者,但是您下载软件的应用市场(如 Google Play)可能会收集关于应用运行状态的相关信息并提供给 v2rayNG 开发者。有关这些信息,请阅读您使用的应用市场所提供的隐私条款。
|
||||
**信息收集**
|
||||
|
||||
v2rayNG 软件中可能包含需要通过 IAP 支付解锁的功能,您的支付信息将由相关的 IAP 渠道进行处理,而我们对支付信息没有访问权。
|
||||
v2rayNG 软件自身不会发送任何信息到开发者,但是您下载软件的应用市场(如 Google Play)可能会收集关于应用运行状态的相关信息并提供给 v2rayNG 开发者。有关这些信息,请阅读您使用的应用市场所提供的隐私权政策。
|
||||
|
||||
当您向 v2rayNG 开发者反馈软件运行中的错误时,开发者可能会要求您提供软件以及系统的日志以帮助确认问题的原因。因日志中可能包括敏感信息,此类信息只能由您自己操作发送。**我们不对任何传输服务的安全性和隐私性做任何明示或暗示的担保,请您在传送相关信息时选择可以您自身可以接受的方式。**
|
||||
v2rayNG 软件中可能包含需要通过 IAP 支付解锁的功能,您的支付信息将由相关的 IAP 渠道进行处理,而我们对支付信息没有访问权。
|
||||
|
||||
2. 信息共享
|
||||
当您向 v2rayNG 开发者反馈软件运行中的错误时,开发者可能会要求您提供软件以及系统的日志以帮助确认问题的原因。因日志中可能包括敏感信息,此类信息只能由您自己操作发送。**我们不对任何传输服务的安全性和隐私性做任何明示或暗示的担保,请您在传送相关信息时选择可以您自身可以接受的方式。**
|
||||
|
||||
我们不会向任何第三方出售收集到的用户数据。我们可能向外部开发者提供信息以协助软件的开发,但是在提供信息之前我们会传达相关保密义务并确定其可以遵守。
|
||||
**信息共享**
|
||||
|
||||
3. 信息存留
|
||||
我们不会向任何第三方出售收集到的用户数据。我们可能向外部开发者提供信息以协助软件的开发,但是在提供信息之前我们会传达相关保密义务并确定其可以遵守。
|
||||
|
||||
除非有相关法律规定,我们会在 30 天内清除不需要继续使用的用户数据,或将统计数据整合为无法识别单个用户的综合报告。
|
||||
**信息存留**
|
||||
|
||||
4. 信息泄露
|
||||
除非有相关法律规定,我们会在 30 天内清除不需要继续使用的用户数据,或将统计数据整合为无法识别单个用户的综合报告。
|
||||
|
||||
我们会使用合理的技术和安全手段尽力保护用户的数据,但是无法保证数据的绝对安全。如果我们确认数据发生了泄露,我们会在 7 天内通过可用的渠道通知用户。**您同意不向我们追责任何因不可抗力而造成的损失。**
|
||||
**信息泄露**
|
||||
|
||||
5. 条款修改
|
||||
我们会使用合理的技术和安全手段尽力保护用户的数据,但是无法保证数据的绝对安全。如果我们确认数据发生了泄露,我们会在 7 天内通过可用的渠道通知用户。**您同意不向我们追责任何因不可抗力而造成的损失。**
|
||||
|
||||
**儿童隐私**
|
||||
|
||||
这些服务不针对 13 岁以下的任何人。我不会故意收集 13 岁以下儿童的个人身份信息。 如果我发现 13 岁以下的儿童向我提供了个人信息,我会立即从我们的服务器中删除该信息。 如果您是父母或监护人,并且您知道您的孩子向我们提供了个人信息,请与我联系,以便我能够采取必要的行动。
|
||||
|
||||
**条款修改**
|
||||
|
||||
我们保留修改这份隐私权政策的权利,但是会确保在更新条款前至少 30 天通过我们的可用渠道和应用内提示来通知用户。**在新条款生效后继续使用软件即表示您同意修改后的隐私权政策。**
|
||||
|
||||
**联系我们**
|
||||
|
||||
如果您对我的隐私政策有任何疑问或建议,请随时通过 CaptainIronng@protonmail.com 与我联系。
|
||||
|
||||
我们保留修改这份隐私条款的权利,但是会确保在更新条款前至少 30 天通过我们的可用渠道和应用内提示来通知用户。**在新条款生效后继续使用软件即表示您同意修改后的隐私条款。**
|
||||
|
||||
@@ -17,8 +17,8 @@ android {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion Integer.parseInt("$targetSdkVer")
|
||||
multiDexEnabled true
|
||||
versionCode 523
|
||||
versionName "1.8.9"
|
||||
versionCode 539
|
||||
versionName "1.8.14"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -132,4 +132,9 @@ dependencies {
|
||||
implementation 'com.blacksquircle.ui:language-json:2.8.0'
|
||||
implementation 'io.github.g00fy2.quickie:quickie-bundled:1.6.0'
|
||||
implementation 'com.google.zxing:core:3.5.1'
|
||||
|
||||
def work_version = "2.8.1"
|
||||
|
||||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||
implementation "androidx.work:work-multiprocess:$work_version"
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="MissingLeanbackLauncher">
|
||||
|
||||
<supports-screens
|
||||
android:anyDensity="true"
|
||||
@@ -26,6 +27,9 @@
|
||||
<!-- <useapplications-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"
|
||||
android:minSdkVersion="34" />
|
||||
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
@@ -50,7 +54,7 @@
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
|
||||
<!-- <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>-->
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||
@@ -127,6 +131,7 @@
|
||||
android:exported="false"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:process=":RunSoLibV2RayDaemon">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService" />
|
||||
@@ -134,12 +139,19 @@
|
||||
<meta-data
|
||||
android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
|
||||
android:value="true" />
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="vpn" />
|
||||
</service>
|
||||
|
||||
<service android:name=".service.V2RayProxyOnlyService"
|
||||
android:exported="false"
|
||||
android:label="@string/app_name"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:process=":RunSoLibV2RayDaemon">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="proxy" />
|
||||
</service>
|
||||
|
||||
<service android:name=".service.V2RayTestService"
|
||||
@@ -166,11 +178,15 @@
|
||||
android:name=".service.QSTileService"
|
||||
android:icon="@drawable/ic_stat_name"
|
||||
android:label="@string/app_tile_name"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
android:process=":RunSoLibV2RayDaemon">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="tile" />
|
||||
</service>
|
||||
<!-- =====================Tasker===================== -->
|
||||
<activity
|
||||
@@ -192,6 +208,18 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- =====================Tasker===================== -->
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
|
||||
<meta-data
|
||||
android:name="androidx.work.WorkManagerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
package com.v2ray.ang
|
||||
|
||||
import android.content.Context
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Configuration
|
||||
import com.tencent.mmkv.MMKV
|
||||
|
||||
class AngApplication : MultiDexApplication() {
|
||||
class AngApplication : MultiDexApplication(), Configuration.Provider {
|
||||
companion object {
|
||||
const val PREF_LAST_VERSION = "pref_last_version"
|
||||
lateinit var application: AngApplication
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
super.attachBaseContext(base)
|
||||
application = this
|
||||
}
|
||||
|
||||
var firstRun = false
|
||||
@@ -25,4 +33,10 @@ class AngApplication : MultiDexApplication() {
|
||||
//Logger.init().logLevel(if (BuildConfig.DEBUG) LogLevel.FULL else LogLevel.NONE)
|
||||
MMKV.initialize(this)
|
||||
}
|
||||
|
||||
override fun getWorkManagerConfiguration(): Configuration {
|
||||
return Configuration.Builder()
|
||||
.setDefaultProcessName("${BuildConfig.APPLICATION_ID}:bg")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ object AppConfig {
|
||||
const val PREF_BYPASS_APPS = "pref_bypass_apps"
|
||||
const val PREF_CONFIRM_REMOVE = "pref_confirm_remove"
|
||||
const val PREF_START_SCAN_IMMEDIATE = "pref_start_scan_immediate"
|
||||
const val PREF_MUX_ENABLED = "pref_mux_enabled"
|
||||
const val PREF_MUX_CONCURRENCY = "pref_mux_concurency"
|
||||
const val PREF_MUX_XUDP_CONCURRENCY = "pref_mux_xudp_concurency"
|
||||
const val PREF_MUX_XUDP_QUIC = "pref_mux_xudp_quic"
|
||||
|
||||
const val HTTP_PROTOCOL: String = "http://"
|
||||
const val HTTPS_PROTOCOL: String = "https://"
|
||||
@@ -58,12 +62,15 @@ object AppConfig {
|
||||
const val TAG_DIRECT = "direct"
|
||||
const val TAG_BLOCKED = "block"
|
||||
|
||||
const val androidpackagenamelistUrl = "https://raw.githubusercontent.com/2dust/androidpackagenamelist/master/proxy.txt"
|
||||
const val v2rayCustomRoutingListUrl = "https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"
|
||||
const val androidpackagenamelistUrl =
|
||||
"https://raw.githubusercontent.com/2dust/androidpackagenamelist/master/proxy.txt"
|
||||
const val v2rayCustomRoutingListUrl =
|
||||
"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"
|
||||
const val v2rayNGIssues = "https://github.com/2dust/v2rayNG/issues"
|
||||
const val v2rayNGWikiMode = "https://github.com/2dust/v2rayNG/wiki/Mode"
|
||||
const val v2rayNGPrivacyPolicy = "https://raw.githubusercontent.com/2dust/v2rayNG/master/CR.md"
|
||||
const val promotionUrl = "aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="
|
||||
const val geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/";
|
||||
const val geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/"
|
||||
|
||||
const val DNS_AGENT = "1.1.1.1"
|
||||
const val DNS_DIRECT = "223.5.5.5"
|
||||
@@ -71,6 +78,9 @@ object AppConfig {
|
||||
const val PORT_LOCAL_DNS = "10853"
|
||||
const val PORT_SOCKS = "10808"
|
||||
const val PORT_HTTP = "10809"
|
||||
const val WIREGUARD_LOCAL_ADDRESS_V4 = "172.16.0.2/32"
|
||||
const val WIREGUARD_LOCAL_ADDRESS_V6 = "2606:4700:110:8f81:d551:a0:532e:a2b3/128"
|
||||
const val WIREGUARD_LOCAL_MTU = "1420"
|
||||
|
||||
const val MSG_REGISTER_CLIENT = 1
|
||||
const val MSG_STATE_RUNNING = 11
|
||||
@@ -87,4 +97,13 @@ object AppConfig {
|
||||
const val MSG_MEASURE_CONFIG = 7
|
||||
const val MSG_MEASURE_CONFIG_SUCCESS = 71
|
||||
const val MSG_MEASURE_CONFIG_CANCEL = 72
|
||||
|
||||
// subscription settings
|
||||
const val SUBSCRIPTION_AUTO_UPDATE = "pref_auto_update_subscription"
|
||||
const val SUBSCRIPTION_AUTO_UPDATE_INTERVAL = "pref_auto_update_interval"
|
||||
const val SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL = "1440" // 24 hours
|
||||
const val SUBSCRIPTION_UPDATE_TASK_NAME = "subscription_updater"
|
||||
|
||||
const val CACHE_SUBSCRIPTION_ID = "cache_subscription_id"
|
||||
const val CACHE_KEYWORD_FILTER = "cache_keyword_filter"
|
||||
}
|
||||
|
||||
@@ -19,23 +19,32 @@ data class ServerConfig(
|
||||
when(configType) {
|
||||
EConfigType.VMESS, EConfigType.VLESS ->
|
||||
return ServerConfig(
|
||||
configType = configType,
|
||||
outboundBean = V2rayConfig.OutboundBean(
|
||||
protocol = configType.name.lowercase(),
|
||||
settings = V2rayConfig.OutboundBean.OutSettingsBean(
|
||||
vnext = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
|
||||
users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())))),
|
||||
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
|
||||
EConfigType.CUSTOM, EConfigType.WIREGUARD ->
|
||||
configType = configType,
|
||||
outboundBean = V2rayConfig.OutboundBean(
|
||||
protocol = configType.name.lowercase(),
|
||||
settings = V2rayConfig.OutboundBean.OutSettingsBean(
|
||||
vnext = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
|
||||
users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())))),
|
||||
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
|
||||
EConfigType.CUSTOM ->
|
||||
return ServerConfig(configType = configType)
|
||||
EConfigType.SHADOWSOCKS, EConfigType.SOCKS, EConfigType.TROJAN ->
|
||||
return ServerConfig(
|
||||
configType = configType,
|
||||
outboundBean = V2rayConfig.OutboundBean(
|
||||
protocol = configType.name.lowercase(),
|
||||
settings = V2rayConfig.OutboundBean.OutSettingsBean(
|
||||
servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())),
|
||||
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
|
||||
configType = configType,
|
||||
outboundBean = V2rayConfig.OutboundBean(
|
||||
protocol = configType.name.lowercase(),
|
||||
settings = V2rayConfig.OutboundBean.OutSettingsBean(
|
||||
servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())),
|
||||
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
|
||||
EConfigType.WIREGUARD ->
|
||||
return ServerConfig(
|
||||
configType = configType,
|
||||
outboundBean = V2rayConfig.OutboundBean(
|
||||
protocol = configType.name.lowercase(),
|
||||
settings = V2rayConfig.OutboundBean.OutSettingsBean(
|
||||
secretKey = "",
|
||||
peers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.WireGuardBean())
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,10 +69,6 @@ data class ServerConfig(
|
||||
fun getV2rayPointDomainAndPort(): String {
|
||||
val address = getProxyOutbound()?.getServerAddress().orEmpty()
|
||||
val port = getProxyOutbound()?.getServerPort()
|
||||
return if (Utils.isIpv6Address(address)) {
|
||||
String.format("[%s]:%s", address, port)
|
||||
} else {
|
||||
String.format("%s:%s", address, port)
|
||||
}
|
||||
return Utils.getIpv6Address(address) + ":" + port
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.v2ray.ang.dto
|
||||
|
||||
data class SubscriptionItem(
|
||||
var remarks: String = "",
|
||||
var url: String = "",
|
||||
var enabled: Boolean = true,
|
||||
val addedTime: Long = System.currentTimeMillis()) {
|
||||
}
|
||||
var remarks: String = "",
|
||||
var url: String = "",
|
||||
var enabled: Boolean = true,
|
||||
val addedTime: Long = System.currentTimeMillis(),
|
||||
var lastUpdated: Long = -1,
|
||||
var autoUpdate: Boolean = false,
|
||||
val updateInterval: Int? = null,
|
||||
)
|
||||
@@ -74,7 +74,7 @@ data class V2rayConfig(
|
||||
var response: Response? = null,
|
||||
/*DNS*/
|
||||
val network: String? = null,
|
||||
val address: Any? = null,
|
||||
var address: Any? = null,
|
||||
val port: Int? = null,
|
||||
/*Freedom*/
|
||||
var domainStrategy: String? = null,
|
||||
@@ -83,8 +83,10 @@ data class V2rayConfig(
|
||||
/*Loopback*/
|
||||
val inboundTag: String? = null,
|
||||
/*Wireguard*/
|
||||
val secretKey: String? = null,
|
||||
var secretKey: String? = null,
|
||||
val peers: List<WireGuardBean>? = null,
|
||||
var reserved: List<Int>? = null,
|
||||
var mtu :Int? = null
|
||||
) {
|
||||
|
||||
data class VnextBean(var address: String = "",
|
||||
@@ -292,7 +294,10 @@ data class V2rayConfig(
|
||||
}
|
||||
}
|
||||
|
||||
data class MuxBean(var enabled: Boolean, var concurrency: Int = 8)
|
||||
data class MuxBean(var enabled: Boolean,
|
||||
var concurrency: Int = 8,
|
||||
var xudpConcurrency: Int = 8,
|
||||
var xudpProxyUDP443: String = "",)
|
||||
|
||||
fun getServerAddress(): String? {
|
||||
if (protocol.equals(EConfigType.VMESS.name, true)
|
||||
|
||||
@@ -17,16 +17,16 @@ val Context.v2RayApplication: AngApplication
|
||||
get() = applicationContext as AngApplication
|
||||
|
||||
fun Context.toast(message: Int): Toast = ToastCompat
|
||||
.makeText(this, message, Toast.LENGTH_SHORT)
|
||||
.apply {
|
||||
show()
|
||||
}
|
||||
.makeText(this, message, Toast.LENGTH_SHORT)
|
||||
.apply {
|
||||
show()
|
||||
}
|
||||
|
||||
fun Context.toast(message: CharSequence): Toast = ToastCompat
|
||||
.makeText(this, message, Toast.LENGTH_SHORT)
|
||||
.apply {
|
||||
show()
|
||||
}
|
||||
.makeText(this, message, Toast.LENGTH_SHORT)
|
||||
.apply {
|
||||
show()
|
||||
}
|
||||
|
||||
fun JSONObject.putOpt(pair: Pair<String, Any>) = putOpt(pair.first, pair.second)
|
||||
fun JSONObject.putOpt(pairs: Map<String, Any>) = pairs.forEach { putOpt(it.key to it.value) }
|
||||
@@ -77,4 +77,8 @@ val URLConnection.responseLength: Long
|
||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) contentLengthLong else contentLength.toLong()
|
||||
|
||||
val URI.idnHost: String
|
||||
get() = (host!!).replace("[", "").replace("]", "")
|
||||
get() = (host!!).replace("[", "").replace("]", "")
|
||||
|
||||
fun String.removeWhiteSpace(): String {
|
||||
return this.replace(" ", "")
|
||||
}
|
||||
@@ -36,7 +36,12 @@ class QSTileService : TileService() {
|
||||
super.onStartListening()
|
||||
setState(Tile.STATE_INACTIVE)
|
||||
mMsgReceive = ReceiveMessageHandler(this)
|
||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY), Context.RECEIVER_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
|
||||
}
|
||||
|
||||
MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.v2ray.ang.service
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.util.AngConfigManager
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
object SubscriptionUpdater {
|
||||
|
||||
const val notificationChannel = "subscription_update_channel"
|
||||
|
||||
class UpdateTask(context: Context, params: WorkerParameters) :
|
||||
CoroutineWorker(context, params) {
|
||||
|
||||
private val notificationManager = NotificationManagerCompat.from(applicationContext)
|
||||
private val notification =
|
||||
NotificationCompat.Builder(applicationContext, notificationChannel)
|
||||
.setWhen(0)
|
||||
.setTicker("Update")
|
||||
.setContentTitle(context.getString(R.string.title_pref_auto_update_subscription))
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override suspend fun doWork(): Result {
|
||||
Log.d(AppConfig.ANG_PACKAGE, "subscription automatic update starting")
|
||||
|
||||
val subs = MmkvManager.decodeSubscriptions().filter { it.second.autoUpdate }
|
||||
|
||||
for (i in subs) {
|
||||
val subscription = i.second
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
notification.setChannelId(notificationChannel)
|
||||
val channel =
|
||||
NotificationChannel(
|
||||
notificationChannel,
|
||||
"Subscription Update Service",
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
notificationManager.notify(3, notification.build())
|
||||
Log.d(
|
||||
AppConfig.ANG_PACKAGE,
|
||||
"subscription automatic update: ---${subscription.remarks}"
|
||||
)
|
||||
val configs = Utils.getUrlContentWithCustomUserAgent(subscription.url)
|
||||
importBatchConfig(configs, i.first)
|
||||
notification.setContentText("Updating ${subscription.remarks}")
|
||||
}
|
||||
notificationManager.cancel(3)
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
fun importBatchConfig(server: String?, subid: String = "") {
|
||||
val append = subid.isEmpty()
|
||||
|
||||
val count = AngConfigManager.importBatchConfig(server, subid, append)
|
||||
if (count <= 0) {
|
||||
AngConfigManager.importBatchConfig(Utils.decode(server!!), subid, append)
|
||||
}
|
||||
if (count <= 0) {
|
||||
AngConfigManager.appendCustomConfigServer(server, subid)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ object V2RayServiceManager {
|
||||
set(value) {
|
||||
field = value
|
||||
Seq.setContext(value?.get()?.getService()?.applicationContext)
|
||||
Libv2ray.initV2Env(Utils.userAssetPath(value?.get()?.getService()))
|
||||
Libv2ray.initV2Env(Utils.userAssetPath(value?.get()?.getService()), Utils.getDeviceIdForXUDPBaseKey())
|
||||
}
|
||||
var currentConfig: ServerConfig? = null
|
||||
|
||||
@@ -133,7 +133,11 @@ object V2RayServiceManager {
|
||||
mFilter.addAction(Intent.ACTION_SCREEN_ON)
|
||||
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
|
||||
mFilter.addAction(Intent.ACTION_USER_PRESENT)
|
||||
service.registerReceiver(mMsgReceive, mFilter)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
service.registerReceiver(mMsgReceive, mFilter, Context.RECEIVER_EXPORTED)
|
||||
} else {
|
||||
service.registerReceiver(mMsgReceive, mFilter)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.d(ANG_PACKAGE, e.toString())
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class V2RayTestService : Service() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Seq.setContext(this)
|
||||
Libv2ray.initV2Env(Utils.userAssetPath(this))
|
||||
Libv2ray.initV2Env(Utils.userAssetPath(this), Utils.getDeviceIdForXUDPBaseKey())
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
|
||||
@@ -103,7 +103,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
binding.drawerLayout.addDrawerListener(toggle)
|
||||
toggle.syncState()
|
||||
binding.navView.setNavigationItemSelectedListener(this)
|
||||
binding.version.text = "v${BuildConfig.VERSION_NAME} (${SpeedtestUtil.getLibVersion()})"
|
||||
"v${BuildConfig.VERSION_NAME} (${SpeedtestUtil.getLibVersion()})".also { binding.version.text = it }
|
||||
|
||||
setupViewModel()
|
||||
copyAssets()
|
||||
@@ -253,6 +253,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
importManually(EConfigType.TROJAN.value)
|
||||
true
|
||||
}
|
||||
R.id.import_manually_wireguard -> {
|
||||
importManually(EConfigType.WIREGUARD.value)
|
||||
true
|
||||
}
|
||||
R.id.import_config_custom_clipboard -> {
|
||||
importConfigCustomClipboard()
|
||||
true
|
||||
@@ -415,6 +419,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
if (count <= 0) {
|
||||
count = AngConfigManager.importBatchConfig(Utils.decode(server!!), subid2, append)
|
||||
}
|
||||
if (count <= 0) {
|
||||
count = AngConfigManager.appendCustomConfigServer(server, subid2)
|
||||
}
|
||||
if (count > 0) {
|
||||
toast(R.string.toast_success)
|
||||
mainViewModel.reloadServerList()
|
||||
@@ -682,6 +689,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
R.id.logcat -> {
|
||||
startActivity(Intent(this, LogcatActivity::class.java))
|
||||
}
|
||||
R.id.privacy_policy-> {
|
||||
Utils.openUri(this, AppConfig.v2rayNGPrivacyPolicy)
|
||||
}
|
||||
}
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
return true
|
||||
|
||||
@@ -96,7 +96,8 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
holder.itemMainBinding.tvType.text = config.configType.name.lowercase()
|
||||
}
|
||||
}
|
||||
holder.itemMainBinding.tvStatistics.text = "${outbound?.getServerAddress()} : ${outbound?.getServerPort()}"
|
||||
val strState = "${outbound?.getServerAddress()?.dropLast(3)}*** : ${outbound?.getServerPort()}"
|
||||
holder.itemMainBinding.tvStatistics.text = strState
|
||||
|
||||
holder.itemMainBinding.layoutShare.setOnClickListener {
|
||||
AlertDialog.Builder(mActivity).setItems(shareOptions.toTypedArray()) { _, i ->
|
||||
|
||||
@@ -10,22 +10,32 @@ import androidx.appcompat.app.AlertDialog
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.PREF_ALLOW_INSECURE
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V6
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_MTU
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.dto.ServerConfig
|
||||
import com.v2ray.ang.dto.V2rayConfig
|
||||
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_PORT
|
||||
import com.v2ray.ang.dto.V2rayConfig.Companion.TLS
|
||||
import com.v2ray.ang.extension.removeWhiteSpace
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.MmkvManager.ID_MAIN
|
||||
import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.util.Utils.getIpv6Address
|
||||
|
||||
class ServerActivity : BaseActivity() {
|
||||
|
||||
private val mainStorage by lazy { MMKV.mmkvWithID(ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
|
||||
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
|
||||
private val settingsStorage by lazy {
|
||||
MMKV.mmkvWithID(
|
||||
MmkvManager.ID_SETTING,
|
||||
MMKV.MULTI_PROCESS_MODE
|
||||
)
|
||||
}
|
||||
private val editGuid by lazy { intent.getStringExtra("guid").orEmpty() }
|
||||
private val isRunning by lazy {
|
||||
intent.getBooleanExtra("isRunning", false)
|
||||
@@ -33,7 +43,8 @@ class ServerActivity : BaseActivity() {
|
||||
&& editGuid == mainStorage?.decodeString(KEY_SELECTED_SERVER)
|
||||
}
|
||||
private val createConfigType by lazy {
|
||||
EConfigType.fromInt(intent.getIntExtra("createConfigType", EConfigType.VMESS.value)) ?: EConfigType.VMESS
|
||||
EConfigType.fromInt(intent.getIntExtra("createConfigType", EConfigType.VMESS.value))
|
||||
?: EConfigType.VMESS
|
||||
}
|
||||
private val subscriptionId by lazy {
|
||||
intent.getStringExtra("subscriptionId")
|
||||
@@ -66,12 +77,13 @@ class ServerActivity : BaseActivity() {
|
||||
private val allowinsecures: Array<out String> by lazy {
|
||||
resources.getStringArray(R.array.allowinsecures)
|
||||
}
|
||||
private val uTlsItems: Array<out String> by lazy {
|
||||
private val uTlsItems: Array<out String> by lazy {
|
||||
resources.getStringArray(R.array.streamsecurity_utls)
|
||||
}
|
||||
private val alpns: Array<out String> by lazy {
|
||||
resources.getStringArray(R.array.streamsecurity_alpn)
|
||||
}
|
||||
|
||||
// Kotlin synthetics was used, but since it is removed in 1.8. We switch to old manual approach.
|
||||
// We don't use AndroidViewBinding because, it is better to share similar logics for different
|
||||
// protocols. Use findViewById manually ensures the xml are de-coupled with the activity logic.
|
||||
@@ -103,26 +115,38 @@ class ServerActivity : BaseActivity() {
|
||||
private val container_short_id: LinearLayout? by lazy { findViewById(R.id.l7) }
|
||||
private val et_spider_x: EditText? by lazy { findViewById(R.id.et_spider_x) }
|
||||
private val container_spider_x: LinearLayout? by lazy { findViewById(R.id.l8) }
|
||||
private val et_reserved1: EditText? by lazy { findViewById(R.id.et_reserved1) }
|
||||
private val et_reserved2: EditText? by lazy { findViewById(R.id.et_reserved2) }
|
||||
private val et_reserved3: EditText? by lazy { findViewById(R.id.et_reserved3) }
|
||||
private val et_local_address: EditText? by lazy { findViewById(R.id.et_local_address) }
|
||||
private val et_local_mtu: EditText? by lazy { findViewById(R.id.et_local_mtu) }
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
title = getString(R.string.title_server)
|
||||
|
||||
val config = MmkvManager.decodeServerConfig(editGuid)
|
||||
when(config?.configType ?: createConfigType) {
|
||||
when (config?.configType ?: createConfigType) {
|
||||
EConfigType.VMESS -> setContentView(R.layout.activity_server_vmess)
|
||||
EConfigType.CUSTOM -> return
|
||||
EConfigType.SHADOWSOCKS -> setContentView(R.layout.activity_server_shadowsocks)
|
||||
EConfigType.SOCKS -> setContentView(R.layout.activity_server_socks)
|
||||
EConfigType.VLESS -> setContentView(R.layout.activity_server_vless)
|
||||
EConfigType.TROJAN -> setContentView(R.layout.activity_server_trojan)
|
||||
else -> setContentView(R.layout.activity_server_vmess)
|
||||
EConfigType.WIREGUARD -> setContentView(R.layout.activity_server_wireguard)
|
||||
}
|
||||
sp_network?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
override fun onItemSelected(
|
||||
parent: AdapterView<*>?,
|
||||
view: View?,
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
val types = transportTypes(networks[position])
|
||||
sp_header_type?.isEnabled = types.size > 1
|
||||
val adapter = ArrayAdapter(this@ServerActivity, android.R.layout.simple_spinner_item, types)
|
||||
val adapter =
|
||||
ArrayAdapter(this@ServerActivity, android.R.layout.simple_spinner_item, types)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
sp_header_type?.adapter = adapter
|
||||
sp_header_type_title?.text = if (networks[position] == "grpc")
|
||||
@@ -134,12 +158,18 @@ class ServerActivity : BaseActivity() {
|
||||
et_path?.text = Utils.getEditable(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
sp_stream_security?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
override fun onItemSelected(
|
||||
parent: AdapterView<*>?,
|
||||
view: View?,
|
||||
position: Int,
|
||||
id: Long
|
||||
) {
|
||||
if (streamSecuritys[position].isBlank()) {
|
||||
container_sni?.visibility = View.GONE
|
||||
container_fingerprint?.visibility = View.GONE
|
||||
@@ -166,6 +196,7 @@ class ServerActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNothingSelected(p0: AdapterView<*>?) {
|
||||
// do nothing
|
||||
}
|
||||
@@ -182,37 +213,67 @@ class ServerActivity : BaseActivity() {
|
||||
*/
|
||||
private fun bindingServer(config: ServerConfig): Boolean {
|
||||
val outbound = config.getProxyOutbound() ?: return false
|
||||
val streamSetting = config.outboundBean?.streamSettings ?: return false
|
||||
|
||||
et_remarks.text = Utils.getEditable(config.remarks)
|
||||
et_address.text = Utils.getEditable(outbound.getServerAddress().orEmpty())
|
||||
et_port.text = Utils.getEditable(outbound.getServerPort()?.toString() ?: DEFAULT_PORT.toString())
|
||||
et_port.text =
|
||||
Utils.getEditable(outbound.getServerPort()?.toString() ?: DEFAULT_PORT.toString())
|
||||
et_id.text = Utils.getEditable(outbound.getPassword().orEmpty())
|
||||
et_alterId?.text = Utils.getEditable(outbound.settings?.vnext?.get(0)?.users?.get(0)?.alterId.toString())
|
||||
et_alterId?.text =
|
||||
Utils.getEditable(outbound.settings?.vnext?.get(0)?.users?.get(0)?.alterId.toString())
|
||||
if (config.configType == EConfigType.SOCKS) {
|
||||
et_security?.text = Utils.getEditable(outbound.settings?.servers?.get(0)?.users?.get(0)?.user.orEmpty())
|
||||
et_security?.text =
|
||||
Utils.getEditable(outbound.settings?.servers?.get(0)?.users?.get(0)?.user.orEmpty())
|
||||
} else if (config.configType == EConfigType.VLESS) {
|
||||
et_security?.text = Utils.getEditable(outbound.getSecurityEncryption().orEmpty())
|
||||
val flow = Utils.arrayFind(flows, outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow.orEmpty())
|
||||
val flow = Utils.arrayFind(
|
||||
flows,
|
||||
outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow.orEmpty()
|
||||
)
|
||||
if (flow >= 0) {
|
||||
sp_flow?.setSelection(flow)
|
||||
}
|
||||
} else if (config.configType == EConfigType.TROJAN) {
|
||||
val flow = Utils.arrayFind(flows, outbound.settings?.servers?.get(0)?.flow.orEmpty())
|
||||
if (flow >= 0) {
|
||||
sp_flow?.setSelection(flow)
|
||||
} else if (config.configType == EConfigType.WIREGUARD) {
|
||||
et_public_key?.text =
|
||||
Utils.getEditable(outbound.settings?.peers?.get(0)?.publicKey.orEmpty())
|
||||
if (outbound.settings?.reserved == null) {
|
||||
et_reserved1?.text = Utils.getEditable("0")
|
||||
et_reserved2?.text = Utils.getEditable("0")
|
||||
et_reserved3?.text = Utils.getEditable("0")
|
||||
} else {
|
||||
et_reserved1?.text =
|
||||
Utils.getEditable(outbound.settings?.reserved?.get(0).toString())
|
||||
et_reserved2?.text =
|
||||
Utils.getEditable(outbound.settings?.reserved?.get(1).toString())
|
||||
et_reserved3?.text =
|
||||
Utils.getEditable(outbound.settings?.reserved?.get(2).toString())
|
||||
}
|
||||
if (outbound.settings?.address == null) {
|
||||
et_local_address?.text =
|
||||
Utils.getEditable("${WIREGUARD_LOCAL_ADDRESS_V4},${WIREGUARD_LOCAL_ADDRESS_V6}")
|
||||
} else {
|
||||
val list = outbound.settings?.address as List<*>
|
||||
et_local_address?.text = Utils.getEditable(list.joinToString())
|
||||
}
|
||||
if (outbound.settings?.mtu == null) {
|
||||
et_local_mtu?.text = Utils.getEditable(WIREGUARD_LOCAL_MTU)
|
||||
} else {
|
||||
et_local_mtu?.text = Utils.getEditable(outbound.settings?.mtu.toString())
|
||||
}
|
||||
}
|
||||
val securityEncryptions = if (config.configType == EConfigType.SHADOWSOCKS) shadowsocksSecuritys else securitys
|
||||
val security = Utils.arrayFind(securityEncryptions, outbound.getSecurityEncryption().orEmpty())
|
||||
val securityEncryptions =
|
||||
if (config.configType == EConfigType.SHADOWSOCKS) shadowsocksSecuritys else securitys
|
||||
val security =
|
||||
Utils.arrayFind(securityEncryptions, outbound.getSecurityEncryption().orEmpty())
|
||||
if (security >= 0) {
|
||||
sp_security?.setSelection(security)
|
||||
}
|
||||
|
||||
val streamSetting = config.outboundBean?.streamSettings ?: return true
|
||||
val streamSecurity = Utils.arrayFind(streamSecuritys, streamSetting.security)
|
||||
if (streamSecurity >= 0) {
|
||||
sp_stream_security?.setSelection(streamSecurity)
|
||||
(streamSetting.tlsSettings?: streamSetting.realitySettings)?.let { tlsSetting ->
|
||||
(streamSetting.tlsSettings ?: streamSetting.realitySettings)?.let { tlsSetting ->
|
||||
container_sni?.visibility = View.VISIBLE
|
||||
container_fingerprint?.visibility = View.VISIBLE
|
||||
container_alpn?.visibility = View.VISIBLE
|
||||
@@ -222,12 +283,16 @@ class ServerActivity : BaseActivity() {
|
||||
sp_stream_fingerprint?.setSelection(utlsIndex)
|
||||
}
|
||||
tlsSetting.alpn?.let {
|
||||
val alpnIndex = Utils.arrayFind(alpns, Utils.removeWhiteSpace(tlsSetting.alpn.joinToString())!!)
|
||||
val alpnIndex = Utils.arrayFind(
|
||||
alpns,
|
||||
Utils.removeWhiteSpace(tlsSetting.alpn.joinToString())!!
|
||||
)
|
||||
sp_stream_alpn?.setSelection(alpnIndex)
|
||||
}
|
||||
if (streamSetting.tlsSettings != null) {
|
||||
container_allow_insecure?.visibility = View.VISIBLE
|
||||
val allowinsecure = Utils.arrayFind(allowinsecures, tlsSetting.allowInsecure.toString())
|
||||
val allowinsecure =
|
||||
Utils.arrayFind(allowinsecures, tlsSetting.allowInsecure.toString())
|
||||
if (allowinsecure >= 0) {
|
||||
sp_allow_insecure?.setSelection(allowinsecure)
|
||||
}
|
||||
@@ -282,6 +347,13 @@ class ServerActivity : BaseActivity() {
|
||||
|
||||
//et_security.text = null
|
||||
sp_flow?.setSelection(0)
|
||||
et_public_key?.text = null
|
||||
et_reserved1?.text = Utils.getEditable("0")
|
||||
et_reserved2?.text = Utils.getEditable("0")
|
||||
et_reserved3?.text = Utils.getEditable("0")
|
||||
et_local_address?.text =
|
||||
Utils.getEditable("${WIREGUARD_LOCAL_ADDRESS_V4},${WIREGUARD_LOCAL_ADDRESS_V6}")
|
||||
et_local_mtu?.text = Utils.getEditable(WIREGUARD_LOCAL_MTU)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -302,9 +374,14 @@ class ServerActivity : BaseActivity() {
|
||||
toast(R.string.server_lab_port)
|
||||
return false
|
||||
}
|
||||
val config = MmkvManager.decodeServerConfig(editGuid) ?: ServerConfig.create(createConfigType)
|
||||
val config =
|
||||
MmkvManager.decodeServerConfig(editGuid) ?: ServerConfig.create(createConfigType)
|
||||
if (config.configType != EConfigType.SOCKS && TextUtils.isEmpty(et_id.text.toString())) {
|
||||
toast(R.string.server_lab_id)
|
||||
if (config.configType == EConfigType.TROJAN || config.configType == EConfigType.SHADOWSOCKS) {
|
||||
toast(R.string.server_lab_id3)
|
||||
} else {
|
||||
toast(R.string.server_lab_id)
|
||||
}
|
||||
return false
|
||||
}
|
||||
sp_stream_security?.let {
|
||||
@@ -328,10 +405,14 @@ class ServerActivity : BaseActivity() {
|
||||
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||
saveServers(server, port, config)
|
||||
}
|
||||
val wireguard = config.outboundBean?.settings
|
||||
wireguard?.peers?.get(0)?.let { _ ->
|
||||
savePeer(wireguard, port)
|
||||
}
|
||||
config.outboundBean?.streamSettings?.let {
|
||||
saveStreamSettings(it)
|
||||
}
|
||||
if(config.subscriptionId.isEmpty() && !subscriptionId.isNullOrEmpty()) {
|
||||
if (config.subscriptionId.isEmpty() && !subscriptionId.isNullOrEmpty()) {
|
||||
config.subscriptionId = subscriptionId!!
|
||||
}
|
||||
|
||||
@@ -341,7 +422,11 @@ class ServerActivity : BaseActivity() {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun saveVnext(vnext: V2rayConfig.OutboundBean.OutSettingsBean.VnextBean, port: Int, config: ServerConfig) {
|
||||
private fun saveVnext(
|
||||
vnext: V2rayConfig.OutboundBean.OutSettingsBean.VnextBean,
|
||||
port: Int,
|
||||
config: ServerConfig
|
||||
) {
|
||||
vnext.address = et_address.text.toString().trim()
|
||||
vnext.port = port
|
||||
vnext.users[0].id = et_id.text.toString().trim()
|
||||
@@ -354,7 +439,11 @@ class ServerActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveServers(server: V2rayConfig.OutboundBean.OutSettingsBean.ServersBean, port: Int, config: ServerConfig) {
|
||||
private fun saveServers(
|
||||
server: V2rayConfig.OutboundBean.OutSettingsBean.ServersBean,
|
||||
port: Int,
|
||||
config: ServerConfig
|
||||
) {
|
||||
server.address = et_address.text.toString().trim()
|
||||
server.port = port
|
||||
if (config.configType == EConfigType.SHADOWSOCKS) {
|
||||
@@ -364,7 +453,8 @@ class ServerActivity : BaseActivity() {
|
||||
if (TextUtils.isEmpty(et_security?.text) && TextUtils.isEmpty(et_id.text)) {
|
||||
server.users = null
|
||||
} else {
|
||||
val socksUsersBean = V2rayConfig.OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
val socksUsersBean =
|
||||
V2rayConfig.OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
socksUsersBean.user = et_security?.text.toString().trim()
|
||||
socksUsersBean.pass = et_id.text.toString().trim()
|
||||
server.users = listOf(socksUsersBean)
|
||||
@@ -374,6 +464,23 @@ class ServerActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun savePeer(wireguard: V2rayConfig.OutboundBean.OutSettingsBean, port: Int) {
|
||||
wireguard.secretKey = et_id.text.toString().trim()
|
||||
wireguard.peers?.get(0)?.publicKey = et_public_key?.text.toString().trim()
|
||||
wireguard.peers?.get(0)?.endpoint =
|
||||
getIpv6Address(et_address.text.toString().trim()) + ":" + port
|
||||
val reserved1 = Utils.parseInt(et_reserved1?.text.toString())
|
||||
val reserved2 = Utils.parseInt(et_reserved2?.text.toString())
|
||||
val reserved3 = Utils.parseInt(et_reserved3?.text.toString())
|
||||
if (reserved1 > 0 || reserved2 > 0 || reserved3 > 0) {
|
||||
wireguard.reserved = listOf(reserved1, reserved2, reserved3)
|
||||
} else {
|
||||
wireguard.reserved = null
|
||||
}
|
||||
wireguard.address = et_local_address?.text.toString().removeWhiteSpace().split(",")
|
||||
wireguard.mtu = Utils.parseInt(et_local_mtu?.text.toString())
|
||||
}
|
||||
|
||||
private fun saveStreamSettings(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean) {
|
||||
val network = sp_network?.selectedItemPosition ?: return
|
||||
val type = sp_header_type?.selectedItemPosition ?: return
|
||||
@@ -389,15 +496,15 @@ class ServerActivity : BaseActivity() {
|
||||
val spiderX = et_spider_x?.text?.toString()?.trim() ?: return
|
||||
|
||||
var sni = streamSetting.populateTransportSettings(
|
||||
transport = networks[network],
|
||||
headerType = transportTypes(networks[network])[type],
|
||||
host = requestHost,
|
||||
path = path,
|
||||
seed = path,
|
||||
quicSecurity = requestHost,
|
||||
key = path,
|
||||
mode = transportTypes(networks[network])[type],
|
||||
serviceName = path
|
||||
transport = networks[network],
|
||||
headerType = transportTypes(networks[network])[type],
|
||||
host = requestHost,
|
||||
path = path,
|
||||
seed = path,
|
||||
quicSecurity = requestHost,
|
||||
key = path,
|
||||
mode = transportTypes(networks[network])[type],
|
||||
serviceName = path
|
||||
)
|
||||
if (sniField.isNotBlank()) {
|
||||
sni = sniField
|
||||
@@ -409,14 +516,14 @@ class ServerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
streamSetting.populateTlsSettings(
|
||||
streamSecurity = streamSecuritys[streamSecurity],
|
||||
allowInsecure = allowInsecure,
|
||||
sni = sni,
|
||||
fingerprint = uTlsItems[utlsIndex],
|
||||
alpns = alpns[alpnIndex],
|
||||
publicKey = publicKey,
|
||||
shortId = shortId,
|
||||
spiderX = spiderX
|
||||
streamSecurity = streamSecuritys[streamSecurity],
|
||||
allowInsecure = allowInsecure,
|
||||
sni = sni,
|
||||
fingerprint = uTlsItems[utlsIndex],
|
||||
alpns = alpns[alpnIndex],
|
||||
publicKey = publicKey,
|
||||
shortId = shortId,
|
||||
spiderX = spiderX
|
||||
)
|
||||
}
|
||||
|
||||
@@ -425,12 +532,15 @@ class ServerActivity : BaseActivity() {
|
||||
"tcp" -> {
|
||||
tcpTypes
|
||||
}
|
||||
|
||||
"kcp", "quic" -> {
|
||||
kcpAndQuicTypes
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
grpcModes
|
||||
}
|
||||
|
||||
else -> {
|
||||
arrayOf("---")
|
||||
}
|
||||
@@ -481,10 +591,12 @@ class ServerActivity : BaseActivity() {
|
||||
deleteServer()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.save_config -> {
|
||||
saveServer()
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,16 @@ import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.preference.*
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.multiprocess.RemoteWorkManager
|
||||
import com.v2ray.ang.AngApplication
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.service.SubscriptionUpdater
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.SettingsViewModel
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SettingsActivity : BaseActivity() {
|
||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||
@@ -29,12 +35,21 @@ class SettingsActivity : BaseActivity() {
|
||||
private val fakeDns by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_FAKE_DNS_ENABLED) }
|
||||
private val localDnsPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_LOCAL_DNS_PORT) }
|
||||
private val vpnDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_VPN_DNS) }
|
||||
|
||||
private val mux by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_MUX_ENABLED) }
|
||||
private val muxConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_CONCURRENCY) }
|
||||
private val muxXudpConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_XUDP_CONCURRENCY) }
|
||||
private val muxXudpQuic by lazy { findPreference<ListPreference>(AppConfig.PREF_MUX_XUDP_QUIC) }
|
||||
|
||||
|
||||
// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
|
||||
private val remoteDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_REMOTE_DNS) }
|
||||
private val domesticDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DOMESTIC_DNS) }
|
||||
private val socksPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_SOCKS_PORT) }
|
||||
private val httpPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_HTTP_PORT) }
|
||||
private val routingCustom by lazy { findPreference<Preference>(AppConfig.PREF_ROUTING_CUSTOM) }
|
||||
private val autoUpdateCheck by lazy { findPreference<CheckBoxPreference>(AppConfig.SUBSCRIPTION_AUTO_UPDATE) }
|
||||
private val autoUpdateInterval by lazy { findPreference<EditTextPreference>(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL) }
|
||||
// val licenses: Preference by lazy { findPreference(PREF_LICENSES) }
|
||||
// val feedback: Preference by lazy { findPreference(PREF_FEEDBACK) }
|
||||
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
|
||||
@@ -49,6 +64,27 @@ class SettingsActivity : BaseActivity() {
|
||||
false
|
||||
}
|
||||
|
||||
autoUpdateCheck?.setOnPreferenceChangeListener { _, newValue ->
|
||||
val value = newValue as Boolean
|
||||
autoUpdateCheck?.isChecked = value
|
||||
autoUpdateInterval?.isEnabled = value
|
||||
autoUpdateInterval?.text?.toLong()?.let {
|
||||
if (newValue) configureUpdateTask(it) else cancelUpdateTask()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
autoUpdateInterval?.setOnPreferenceChangeListener { _, any ->
|
||||
var nval = any as String
|
||||
|
||||
autoUpdateInterval?.summary = nval
|
||||
// It must be greater than 15 minutes because WorkManager couldn't run tasks under 15 minutes intervals
|
||||
nval =
|
||||
if (TextUtils.isEmpty(nval) or (nval.toLong() < 15)) AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL else nval
|
||||
configureUpdateTask(nval.toLong())
|
||||
true
|
||||
}
|
||||
|
||||
// licenses.onClick {
|
||||
// val fragment = LicensesDialogFragment.Builder(act)
|
||||
// .setNotices(R.raw.licenses)
|
||||
@@ -90,13 +126,14 @@ class SettingsActivity : BaseActivity() {
|
||||
true
|
||||
}
|
||||
|
||||
localDns?.setOnPreferenceChangeListener{ _, any ->
|
||||
localDns?.setOnPreferenceChangeListener { _, any ->
|
||||
updateLocalDns(any as Boolean)
|
||||
true
|
||||
}
|
||||
localDnsPort?.setOnPreferenceChangeListener { _, any ->
|
||||
val nval = any as String
|
||||
localDnsPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_LOCAL_DNS else nval
|
||||
localDnsPort?.summary =
|
||||
if (TextUtils.isEmpty(nval)) AppConfig.PORT_LOCAL_DNS else nval
|
||||
true
|
||||
}
|
||||
vpnDns?.setOnPreferenceChangeListener { _, any ->
|
||||
@@ -119,18 +156,36 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
mode?.dialogLayoutResource = R.layout.preference_with_help_link
|
||||
//loglevel.summary = "LogLevel"
|
||||
mux?.setOnPreferenceChangeListener { _, newValue ->
|
||||
updateMux(newValue as Boolean)
|
||||
true
|
||||
}
|
||||
muxConcurrency?.setOnPreferenceChangeListener { _, newValue ->
|
||||
updateMuxConcurrency(newValue as String)
|
||||
true
|
||||
}
|
||||
muxXudpConcurrency?.setOnPreferenceChangeListener { _, newValue ->
|
||||
updateMuxXudpConcurrency(newValue as String)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
val defaultSharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
updateMode(defaultSharedPreferences.getString(AppConfig.PREF_MODE, "VPN"))
|
||||
var remoteDnsString = defaultSharedPreferences.getString(AppConfig.PREF_REMOTE_DNS, "")
|
||||
domesticDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_DOMESTIC_DNS, "")
|
||||
|
||||
domesticDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_DOMESTIC_DNS, "")
|
||||
localDnsPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PORT_LOCAL_DNS)
|
||||
socksPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
|
||||
httpPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_HTTP_PORT, AppConfig.PORT_HTTP)
|
||||
updateMux(defaultSharedPreferences.getBoolean(AppConfig.PREF_MUX_ENABLED, false))
|
||||
muxConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_CONCURRENCY, "8")
|
||||
muxXudpConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8")
|
||||
autoUpdateInterval?.summary = defaultSharedPreferences.getString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
|
||||
autoUpdateInterval?.isEnabled = defaultSharedPreferences.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
|
||||
|
||||
if (TextUtils.isEmpty(remoteDnsString)) {
|
||||
remoteDnsString = AppConfig.DNS_AGENT
|
||||
@@ -139,7 +194,8 @@ class SettingsActivity : BaseActivity() {
|
||||
domesticDns?.summary = AppConfig.DNS_DIRECT
|
||||
}
|
||||
remoteDns?.summary = remoteDnsString
|
||||
vpnDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_VPN_DNS, remoteDnsString)
|
||||
vpnDns?.summary =
|
||||
defaultSharedPreferences.getString(AppConfig.PREF_VPN_DNS, remoteDnsString)
|
||||
|
||||
if (TextUtils.isEmpty(localDnsPort?.summary)) {
|
||||
localDnsPort?.summary = AppConfig.PORT_LOCAL_DNS
|
||||
@@ -153,17 +209,24 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun updateMode(mode: String?) {
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
val defaultSharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
val vpn = mode == "VPN"
|
||||
perAppProxy?.isEnabled = vpn
|
||||
perAppProxy?.isChecked = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
perAppProxy?.isChecked =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
.getBoolean(AppConfig.PREF_PER_APP_PROXY, false)
|
||||
localDns?.isEnabled = vpn
|
||||
fakeDns?.isEnabled = vpn
|
||||
localDnsPort?.isEnabled = vpn
|
||||
vpnDns?.isEnabled = vpn
|
||||
if (vpn) {
|
||||
updateLocalDns(defaultSharedPreferences.getBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false))
|
||||
updateLocalDns(
|
||||
defaultSharedPreferences.getBoolean(
|
||||
AppConfig.PREF_LOCAL_DNS_ENABLED,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +235,58 @@ class SettingsActivity : BaseActivity() {
|
||||
localDnsPort?.isEnabled = enabled
|
||||
vpnDns?.isEnabled = !enabled
|
||||
}
|
||||
|
||||
private fun configureUpdateTask(interval: Long) {
|
||||
val rw = RemoteWorkManager.getInstance(AngApplication.application)
|
||||
rw.cancelUniqueWork(AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME)
|
||||
rw.enqueueUniquePeriodicWork(
|
||||
AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME,
|
||||
ExistingPeriodicWorkPolicy.UPDATE,
|
||||
PeriodicWorkRequest.Builder(
|
||||
SubscriptionUpdater.UpdateTask::class.java,
|
||||
interval,
|
||||
TimeUnit.MINUTES
|
||||
)
|
||||
.apply {
|
||||
setInitialDelay(interval, TimeUnit.MINUTES)
|
||||
}
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
private fun cancelUpdateTask() {
|
||||
val rw = RemoteWorkManager.getInstance(AngApplication.application)
|
||||
rw.cancelUniqueWork(AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME)
|
||||
}
|
||||
|
||||
private fun updateMux(enabled: Boolean) {
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
muxConcurrency?.isEnabled = enabled
|
||||
muxXudpConcurrency?.isEnabled = enabled
|
||||
muxXudpQuic?.isEnabled = enabled
|
||||
if (enabled) {
|
||||
updateMuxConcurrency(defaultSharedPreferences.getString(AppConfig.PREF_MUX_CONCURRENCY, "8"))
|
||||
updateMuxXudpConcurrency(defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMuxConcurrency(value: String?) {
|
||||
if (value == null) {
|
||||
} else {
|
||||
val concurrency = value.toIntOrNull() ?: 8
|
||||
muxConcurrency?.summary = concurrency.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMuxXudpConcurrency(value: String?) {
|
||||
if (value == null) {
|
||||
muxXudpQuic?.isEnabled = true
|
||||
} else {
|
||||
val concurrency = value.toIntOrNull() ?: 8
|
||||
muxXudpConcurrency?.summary = concurrency.toString()
|
||||
muxXudpQuic?.isEnabled = concurrency >= 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onModeHelpClicked(view: View) {
|
||||
|
||||
@@ -5,14 +5,22 @@ import android.text.TextUtils
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.multiprocess.RemoteWorkManager
|
||||
import com.google.gson.Gson
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AngApplication
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivitySubEditBinding
|
||||
import com.v2ray.ang.dto.SubscriptionItem
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.service.SubscriptionUpdater
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SubEditActivity : BaseActivity() {
|
||||
private lateinit var binding: ActivitySubEditBinding
|
||||
@@ -45,6 +53,7 @@ class SubEditActivity : BaseActivity() {
|
||||
binding.etRemarks.text = Utils.getEditable(subItem.remarks)
|
||||
binding.etUrl.text = Utils.getEditable(subItem.url)
|
||||
binding.chkEnable.isChecked = subItem.enabled
|
||||
binding.autoUpdateCheck.isChecked = subItem.autoUpdate
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -75,6 +84,7 @@ class SubEditActivity : BaseActivity() {
|
||||
subItem.remarks = binding.etRemarks.text.toString()
|
||||
subItem.url = binding.etUrl.text.toString()
|
||||
subItem.enabled = binding.chkEnable.isChecked
|
||||
subItem.autoUpdate = binding.autoUpdateCheck.isChecked
|
||||
|
||||
if (TextUtils.isEmpty(subItem.remarks)) {
|
||||
toast(R.string.sub_setting_remarks)
|
||||
@@ -129,4 +139,5 @@ class SubEditActivity : BaseActivity() {
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_CONFIG
|
||||
import com.v2ray.ang.AppConfig.HTTPS_PROTOCOL
|
||||
import com.v2ray.ang.AppConfig.HTTP_PROTOCOL
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_MTU
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.*
|
||||
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_SECURITY
|
||||
@@ -20,6 +22,7 @@ import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import com.v2ray.ang.extension.idnHost
|
||||
import com.v2ray.ang.extension.removeWhiteSpace
|
||||
import com.v2ray.ang.extension.toast
|
||||
|
||||
object AngConfigManager {
|
||||
@@ -432,6 +435,28 @@ object AngConfigManager {
|
||||
queryParam["security"] ?: "", allowInsecure,
|
||||
queryParam["sni"] ?: sni, fingerprint, queryParam["alpn"], pbk, sid, spx
|
||||
)
|
||||
} else if (str.startsWith(EConfigType.WIREGUARD.protocolScheme)) {
|
||||
val uri = URI(Utils.fixIllegalUrl(str))
|
||||
config = ServerConfig.create(EConfigType.WIREGUARD)
|
||||
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||
|
||||
if (uri.rawQuery != null) {
|
||||
val queryParam = uri.rawQuery.split("&")
|
||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||
|
||||
config.outboundBean?.settings?.let { wireguard ->
|
||||
wireguard.secretKey = uri.userInfo
|
||||
wireguard.address =
|
||||
(queryParam["address"] ?: WIREGUARD_LOCAL_ADDRESS_V4).removeWhiteSpace()
|
||||
.split(",")
|
||||
wireguard.peers?.get(0)?.publicKey = queryParam["publickey"] ?: ""
|
||||
wireguard.peers?.get(0)?.endpoint = "${uri.idnHost}:${uri.port}"
|
||||
wireguard.mtu = Utils.parseInt(queryParam["mtu"] ?: WIREGUARD_LOCAL_MTU)
|
||||
wireguard.reserved =
|
||||
(queryParam["reserved"] ?: "0,0,0").removeWhiteSpace().split(",")
|
||||
.map { it.toInt() }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config == null) {
|
||||
return R.string.toast_incorrect_protocol
|
||||
@@ -443,7 +468,8 @@ object AngConfigManager {
|
||||
?.getServerAddress() == removedSelectedServer.getProxyOutbound()
|
||||
?.getServerAddress() &&
|
||||
config.getProxyOutbound()
|
||||
?.getServerPort() == removedSelectedServer.getProxyOutbound()?.getServerPort()
|
||||
?.getServerPort() == removedSelectedServer.getProxyOutbound()
|
||||
?.getServerPort()
|
||||
) {
|
||||
mainStorage?.encode(KEY_SELECTED_SERVER, guid)
|
||||
}
|
||||
@@ -571,7 +597,11 @@ object AngConfigManager {
|
||||
try {
|
||||
val config = MmkvManager.decodeServerConfig(guid) ?: return ""
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
val streamSetting = outbound.streamSettings ?: return ""
|
||||
val streamSetting =
|
||||
outbound.streamSettings ?: V2rayConfig.OutboundBean.StreamSettingsBean()
|
||||
if (config.configType != EConfigType.WIREGUARD) {
|
||||
if (outbound.streamSettings == null) return ""
|
||||
}
|
||||
return config.configType.protocolScheme + when (config.configType) {
|
||||
EConfigType.VMESS -> {
|
||||
val vmessQRCode = VmessQRCode()
|
||||
@@ -600,7 +630,8 @@ object AngConfigManager {
|
||||
Utils.encode(json)
|
||||
}
|
||||
|
||||
EConfigType.CUSTOM, EConfigType.WIREGUARD -> ""
|
||||
EConfigType.CUSTOM -> ""
|
||||
|
||||
EConfigType.SHADOWSOCKS -> {
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
val pw =
|
||||
@@ -617,10 +648,13 @@ object AngConfigManager {
|
||||
EConfigType.SOCKS -> {
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
val pw =
|
||||
Utils.encode("${outbound.settings?.servers?.get(0)?.users?.get(0)?.user}:${outbound.getPassword()}")
|
||||
if (outbound.settings?.servers?.get(0)?.users?.get(0)?.user != null)
|
||||
"${outbound.settings?.servers?.get(0)?.users?.get(0)?.user}:${outbound.getPassword()}"
|
||||
else
|
||||
":"
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
pw,
|
||||
Utils.encode(pw),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()!!),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
@@ -672,7 +706,8 @@ object AngConfigManager {
|
||||
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX!!)
|
||||
}
|
||||
}
|
||||
dicQuery["type"] = streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||
dicQuery["type"] =
|
||||
streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||
|
||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||
when (streamSetting.network) {
|
||||
@@ -733,6 +768,36 @@ object AngConfigManager {
|
||||
)
|
||||
url + query + remark
|
||||
}
|
||||
|
||||
EConfigType.WIREGUARD -> {
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
|
||||
val dicQuery = HashMap<String, String>()
|
||||
dicQuery["publickey"] =
|
||||
Utils.urlEncode(outbound.settings?.peers?.get(0)?.publicKey.toString())
|
||||
dicQuery["reserved"] = Utils.urlEncode(
|
||||
Utils.removeWhiteSpace(outbound.settings?.reserved?.joinToString())
|
||||
.toString()
|
||||
)
|
||||
dicQuery["address"] = Utils.urlEncode(
|
||||
Utils.removeWhiteSpace((outbound.settings?.address as List<*>).joinToString())
|
||||
.toString()
|
||||
)
|
||||
if (outbound.settings?.mtu != null) {
|
||||
dicQuery["mtu"] = outbound.settings?.mtu.toString()
|
||||
}
|
||||
val query = "?" + dicQuery.toList().joinToString(
|
||||
separator = "&",
|
||||
transform = { it.first + "=" + it.second })
|
||||
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
Utils.urlEncode(outbound.getPassword().toString()),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()!!),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
url + query + remark
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
@@ -858,17 +923,19 @@ object AngConfigManager {
|
||||
return 0
|
||||
}
|
||||
val removedSelectedServer =
|
||||
if (!TextUtils.isEmpty(subid) && !append) {
|
||||
MmkvManager.decodeServerConfig(mainStorage?.decodeString(KEY_SELECTED_SERVER) ?: "")?.let {
|
||||
if (it.subscriptionId == subid) {
|
||||
return@let it
|
||||
}
|
||||
return@let null
|
||||
if (!TextUtils.isEmpty(subid) && !append) {
|
||||
MmkvManager.decodeServerConfig(
|
||||
mainStorage?.decodeString(KEY_SELECTED_SERVER) ?: ""
|
||||
)?.let {
|
||||
if (it.subscriptionId == subid) {
|
||||
return@let it
|
||||
}
|
||||
} else {
|
||||
null
|
||||
return@let null
|
||||
}
|
||||
if(!append) {
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (!append) {
|
||||
MmkvManager.removeServerViaSubid(subid)
|
||||
}
|
||||
// var servers = server
|
||||
@@ -908,4 +975,24 @@ object AngConfigManager {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun appendCustomConfigServer(server: String?, subid: String): Int {
|
||||
if (server == null) {
|
||||
return 0
|
||||
}
|
||||
if (server.contains("inbounds")
|
||||
&& server.contains("outbounds")
|
||||
&& server.contains("routing")
|
||||
) {
|
||||
val config = ServerConfig.create(EConfigType.CUSTOM)
|
||||
config.remarks = System.currentTimeMillis().toString()
|
||||
config.subscriptionId = subid
|
||||
config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java)
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
serverRawStorage?.encode(key, server)
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.LocaleList
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.webkit.URLUtil
|
||||
@@ -282,7 +283,7 @@ object Utils {
|
||||
|
||||
fun urlDecode(url: String): String {
|
||||
return try {
|
||||
URLDecoder.decode(URLDecoder.decode(url), "utf-8")
|
||||
URLDecoder.decode(url, "UTF-8")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
url
|
||||
@@ -317,6 +318,11 @@ object Utils {
|
||||
return extDir.absolutePath
|
||||
}
|
||||
|
||||
fun getDeviceIdForXUDPBaseKey(): String {
|
||||
val androidId = Settings.Secure.ANDROID_ID.toByteArray(charset("UTF-8"))
|
||||
return Base64.encodeToString(androidId.copyOf(32), Base64.NO_PADDING.or(Base64.URL_SAFE))
|
||||
}
|
||||
|
||||
fun getUrlContext(url: String, timeout: Int): String {
|
||||
var result: String
|
||||
var conn: HttpURLConnection? = null
|
||||
@@ -360,7 +366,7 @@ object Utils {
|
||||
}
|
||||
|
||||
fun getIpv6Address(address: String): String {
|
||||
return if (isIpv6Address(address)) {
|
||||
return if (isIpv6Address(address) && !address.contains('[') && !address.contains(']')) {
|
||||
String.format("[%s]", address)
|
||||
} else {
|
||||
address
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.google.gson.*
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V6
|
||||
import com.v2ray.ang.dto.V2rayConfig
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.dto.ERoutingMode
|
||||
@@ -32,12 +34,12 @@ object V2rayConfigUtil {
|
||||
} else {
|
||||
raw
|
||||
}
|
||||
Log.d(ANG_PACKAGE, customConfig)
|
||||
//Log.d(ANG_PACKAGE, customConfig)
|
||||
return Result(true, customConfig)
|
||||
}
|
||||
val outbound = config.getProxyOutbound() ?: return Result(false, "")
|
||||
val result = getV2rayNonCustomConfig(context, outbound)
|
||||
Log.d(ANG_PACKAGE, result.content)
|
||||
//Log.d(ANG_PACKAGE, result.content)
|
||||
return result
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
@@ -64,7 +66,7 @@ object V2rayConfigUtil {
|
||||
|
||||
inbounds(v2rayConfig)
|
||||
|
||||
httpRequestObject(outbound)
|
||||
updateOutboundWithGlobalSettings(outbound)
|
||||
|
||||
v2rayConfig.outbounds[0] = outbound
|
||||
|
||||
@@ -399,10 +401,48 @@ object V2rayConfigUtil {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun httpRequestObject(outbound: V2rayConfig.OutboundBean): Boolean {
|
||||
private fun updateOutboundWithGlobalSettings(outbound: V2rayConfig.OutboundBean): Boolean {
|
||||
try {
|
||||
var muxEnabled = settingsStorage?.decodeBool(AppConfig.PREF_MUX_ENABLED, false)
|
||||
val protocol = outbound.protocol
|
||||
if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|
||||
|| protocol.equals(EConfigType.SOCKS.name, true)
|
||||
|| protocol.equals(EConfigType.TROJAN.name, true)
|
||||
) {
|
||||
muxEnabled = false
|
||||
} else if (protocol.equals(EConfigType.VLESS.name, true)
|
||||
&& outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow?.isNotEmpty() == true
|
||||
) {
|
||||
muxEnabled = false
|
||||
}
|
||||
if (muxEnabled == true) {
|
||||
outbound.mux?.enabled = true
|
||||
outbound.mux?.concurrency =
|
||||
settingsStorage?.decodeInt(AppConfig.PREF_MUX_CONCURRENCY) ?: 8
|
||||
outbound.mux?.xudpConcurrency =
|
||||
settingsStorage?.decodeInt(AppConfig.PREF_MUX_XUDP_CONCURRENCY) ?: 8
|
||||
outbound.mux?.xudpProxyUDP443 =
|
||||
settingsStorage?.decodeString(AppConfig.PREF_MUX_XUDP_QUIC) ?: "reject"
|
||||
} else {
|
||||
outbound.mux?.enabled = false
|
||||
outbound.mux?.concurrency = -1
|
||||
}
|
||||
|
||||
if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
|
||||
var localTunAddr = if (outbound.settings?.address == null) {
|
||||
listOf(WIREGUARD_LOCAL_ADDRESS_V4, WIREGUARD_LOCAL_ADDRESS_V6)
|
||||
} else {
|
||||
outbound.settings?.address as List<*>
|
||||
}
|
||||
if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) != true) {
|
||||
localTunAddr = listOf(localTunAddr.first())
|
||||
}
|
||||
outbound.settings?.address = localTunAddr
|
||||
}
|
||||
|
||||
if (outbound.streamSettings?.network == DEFAULT_NETWORK
|
||||
&& outbound.streamSettings?.tcpSettings?.header?.type == HTTP) {
|
||||
&& outbound.streamSettings?.tcpSettings?.header?.type == HTTP
|
||||
) {
|
||||
val path = outbound.streamSettings?.tcpSettings?.header?.request?.path
|
||||
val host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.v2ray.ang.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.content.*
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.ArrayAdapter
|
||||
@@ -24,12 +25,28 @@ import kotlinx.coroutines.*
|
||||
import java.util.*
|
||||
|
||||
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
|
||||
private val serverRawStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SERVER_RAW, MMKV.MULTI_PROCESS_MODE) }
|
||||
private val mainStorage by lazy {
|
||||
MMKV.mmkvWithID(
|
||||
MmkvManager.ID_MAIN,
|
||||
MMKV.MULTI_PROCESS_MODE
|
||||
)
|
||||
}
|
||||
private val serverRawStorage by lazy {
|
||||
MMKV.mmkvWithID(
|
||||
MmkvManager.ID_SERVER_RAW,
|
||||
MMKV.MULTI_PROCESS_MODE
|
||||
)
|
||||
}
|
||||
private val settingsStorage by lazy {
|
||||
MMKV.mmkvWithID(
|
||||
MmkvManager.ID_SETTING,
|
||||
MMKV.MULTI_PROCESS_MODE
|
||||
)
|
||||
}
|
||||
|
||||
var serverList = MmkvManager.decodeServerList()
|
||||
var subscriptionId: String = ""
|
||||
var keywordFilter: String = ""
|
||||
var subscriptionId: String = settingsStorage.decodeString(AppConfig.CACHE_SUBSCRIPTION_ID, "")!!
|
||||
var keywordFilter: String = settingsStorage.decodeString(AppConfig.CACHE_KEYWORD_FILTER, "")!!
|
||||
private set
|
||||
val serversCache = mutableListOf<ServersCache>()
|
||||
val isRunning by lazy { MutableLiveData<Boolean>() }
|
||||
@@ -40,7 +57,18 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
fun startListenBroadcast() {
|
||||
isRunning.value = false
|
||||
getApplication<AngApplication>().registerReceiver(mMsgReceiver, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getApplication<AngApplication>().registerReceiver(
|
||||
mMsgReceiver,
|
||||
IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY),
|
||||
Context.RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
getApplication<AngApplication>().registerReceiver(
|
||||
mMsgReceiver,
|
||||
IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
|
||||
)
|
||||
}
|
||||
MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_REGISTER_CLIENT, "")
|
||||
}
|
||||
|
||||
@@ -62,7 +90,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
serverList.remove(guid)
|
||||
MmkvManager.removeServer(guid)
|
||||
val index = getPosition(guid)
|
||||
if(index >= 0){
|
||||
if (index >= 0) {
|
||||
serversCache.removeAt(index)
|
||||
}
|
||||
}
|
||||
@@ -75,7 +103,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
serverRawStorage?.encode(key, server)
|
||||
serverList.add(0, key)
|
||||
serversCache.add(0, ServersCache(key,config))
|
||||
serversCache.add(0, ServersCache(key, config))
|
||||
}
|
||||
|
||||
fun swapServer(fromPosition: Int, toPosition: Int) {
|
||||
@@ -115,7 +143,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val testResult = SpeedtestUtil.tcping(serverAddress, serverPort)
|
||||
launch(Dispatchers.Main) {
|
||||
MmkvManager.encodeServerTestDelayMillis(item.guid, testResult)
|
||||
updateListAction.value = getPosition(item.guid)
|
||||
updateListAction.value = getPosition(item.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,12 +156,18 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
MmkvManager.clearAllTestDelayResults()
|
||||
updateListAction.value = -1 // update all
|
||||
|
||||
val serversCopy = serversCache.toList() // Create a copy of the list
|
||||
|
||||
getApplication<AngApplication>().toast(R.string.connection_test_testing)
|
||||
viewModelScope.launch(Dispatchers.Default) { // without Dispatchers.Default viewModelScope will launch in main thread
|
||||
for (item in serversCache) {
|
||||
for (item in serversCopy) {
|
||||
val config = V2rayConfigUtil.getV2rayConfig(getApplication(), item.guid)
|
||||
if (config.status) {
|
||||
MessageUtil.sendMsg2TestService(getApplication(), AppConfig.MSG_MEASURE_CONFIG, Pair(item.guid, config.content))
|
||||
MessageUtil.sendMsg2TestService(
|
||||
getApplication(),
|
||||
AppConfig.MSG_MEASURE_CONFIG,
|
||||
Pair(item.guid, config.content)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +177,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_MEASURE_DELAY, "")
|
||||
}
|
||||
|
||||
fun filterConfig(context :Context) {
|
||||
fun filterConfig(context: Context) {
|
||||
val subscriptions = MmkvManager.decodeSubscriptions()
|
||||
val listId = subscriptions.map { it.first }.toList().toMutableList()
|
||||
val listRemarks = subscriptions.map { it.second.remarks }.toList().toMutableList()
|
||||
@@ -155,7 +189,11 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
|
||||
val ivBinding = DialogConfigFilterBinding.inflate(LayoutInflater.from(context))
|
||||
ivBinding.spSubscriptionId.adapter = ArrayAdapter<String>( context, android.R.layout.simple_spinner_dropdown_item, listRemarks)
|
||||
ivBinding.spSubscriptionId.adapter = ArrayAdapter<String>(
|
||||
context,
|
||||
android.R.layout.simple_spinner_dropdown_item,
|
||||
listRemarks
|
||||
)
|
||||
ivBinding.spSubscriptionId.setSelection(checkedItem)
|
||||
ivBinding.etKeyword.text = Utils.getEditable(keywordFilter)
|
||||
val builder = AlertDialog.Builder(context).setView(ivBinding.root)
|
||||
@@ -169,6 +207,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
subscriptions[position].first
|
||||
}
|
||||
keywordFilter = ivBinding.etKeyword.text.toString()
|
||||
settingsStorage?.encode(AppConfig.CACHE_SUBSCRIPTION_ID, subscriptionId)
|
||||
settingsStorage?.encode(AppConfig.CACHE_KEYWORD_FILTER, keywordFilter)
|
||||
reloadServerList()
|
||||
|
||||
dialogInterface?.dismiss()
|
||||
@@ -193,7 +233,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
// }.show()
|
||||
}
|
||||
|
||||
fun getPosition(guid: String) : Int {
|
||||
fun getPosition(guid: String): Int {
|
||||
serversCache.forEachIndexed { index, it ->
|
||||
if (it.guid == guid)
|
||||
return index
|
||||
@@ -206,20 +246,24 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
serversCache.forEachIndexed { index, it ->
|
||||
val outbound = it.config.getProxyOutbound()
|
||||
serversCache.forEachIndexed { index2, it2 ->
|
||||
if(index2 > index){
|
||||
if (index2 > index) {
|
||||
val outbound2 = it2.config.getProxyOutbound()
|
||||
if( outbound == outbound2 && !deleteServer.contains(it2.guid))
|
||||
{
|
||||
if (outbound == outbound2 && !deleteServer.contains(it2.guid)) {
|
||||
deleteServer.add(it2.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(it in deleteServer){
|
||||
for (it in deleteServer) {
|
||||
MmkvManager.removeServer(it)
|
||||
}
|
||||
reloadServerList()
|
||||
getApplication<AngApplication>().toast(getApplication<AngApplication>().getString(R.string.title_del_duplicate_config_count, deleteServer.count()))
|
||||
getApplication<AngApplication>().toast(
|
||||
getApplication<AngApplication>().getString(
|
||||
R.string.title_del_duplicate_config_count,
|
||||
deleteServer.count()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val mMsgReceiver = object : BroadcastReceiver() {
|
||||
@@ -228,23 +272,29 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
AppConfig.MSG_STATE_RUNNING -> {
|
||||
isRunning.value = true
|
||||
}
|
||||
|
||||
AppConfig.MSG_STATE_NOT_RUNNING -> {
|
||||
isRunning.value = false
|
||||
}
|
||||
|
||||
AppConfig.MSG_STATE_START_SUCCESS -> {
|
||||
getApplication<AngApplication>().toast(R.string.toast_services_success)
|
||||
isRunning.value = true
|
||||
}
|
||||
|
||||
AppConfig.MSG_STATE_START_FAILURE -> {
|
||||
getApplication<AngApplication>().toast(R.string.toast_services_failure)
|
||||
isRunning.value = false
|
||||
}
|
||||
|
||||
AppConfig.MSG_STATE_STOP_SUCCESS -> {
|
||||
isRunning.value = false
|
||||
}
|
||||
|
||||
AppConfig.MSG_MEASURE_DELAY_SUCCESS -> {
|
||||
updateTestResultAction.value = intent.getStringExtra("content")
|
||||
}
|
||||
|
||||
AppConfig.MSG_MEASURE_CONFIG_SUCCESS -> {
|
||||
val resultPair = intent.getSerializableExtra("content") as Pair<String, Long>
|
||||
MmkvManager.encodeServerTestDelayMillis(resultPair.first, resultPair.second)
|
||||
|
||||
@@ -39,7 +39,9 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_ROUTING_MODE,
|
||||
AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
||||
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
||||
AppConfig.PREF_V2RAY_ROUTING_DIRECT, -> {
|
||||
AppConfig.PREF_V2RAY_ROUTING_DIRECT,
|
||||
AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,
|
||||
AppConfig.PREF_MUX_XUDP_QUIC, -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getString(key, ""))
|
||||
}
|
||||
AppConfig.PREF_SPEED_ENABLED,
|
||||
@@ -51,12 +53,18 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_PER_APP_PROXY,
|
||||
AppConfig.PREF_BYPASS_APPS,
|
||||
AppConfig.PREF_CONFIRM_REMOVE,
|
||||
AppConfig.PREF_START_SCAN_IMMEDIATE, -> {
|
||||
AppConfig.PREF_START_SCAN_IMMEDIATE,
|
||||
AppConfig.SUBSCRIPTION_AUTO_UPDATE,
|
||||
AppConfig.PREF_MUX_ENABLED, -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
||||
}
|
||||
AppConfig.PREF_SNIFFING_ENABLED -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, true))
|
||||
}
|
||||
AppConfig.PREF_MUX_CONCURRENCY,
|
||||
AppConfig.PREF_MUX_XUDP_CONCURRENCY -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getString(key, "8")?.toIntOrNull() ?: 8)
|
||||
}
|
||||
AppConfig.PREF_PER_APP_PROXY_SET -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getStringSet(key, setOf()))
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
android:id="@+id/layout_test"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/connection_test_height"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:background="@color/colorMainTestBg"
|
||||
android:gravity="center|start"
|
||||
android:nextFocusRight="@+id/fab"
|
||||
android:clickable="true"
|
||||
|
||||
199
V2rayNG/app/src/main/res/layout/activity_server_wireguard.xml
Normal file
199
V2rayNG/app/src/main/res/layout/activity_server_wireguard.xml
Normal file
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.ServerActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/layout_margin_top_height">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_server"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_remarks" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_remarks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_address3" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_address"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_port3" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_port"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="number" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_secret_key" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_public_key" />
|
||||
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_public_key"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_reserved" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/et_reserved1"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="number" />
|
||||
<EditText
|
||||
android:id="@+id/et_reserved2"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="number" />
|
||||
<EditText
|
||||
android:id="@+id/et_reserved3"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="number" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_local_address" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_local_address"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_local_mtu" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_local_mtu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="number" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/layout_margin_top_height"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -69,6 +69,28 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:text="@string/sub_auto_update" />
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatCheckBox
|
||||
android:id="@+id/auto_update_check"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="6dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -94,6 +116,7 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -41,7 +41,12 @@
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="9dp">
|
||||
|
||||
<TextView
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -49,18 +54,18 @@
|
||||
android:minLines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_statistics"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
android:id="@+id/feedback"
|
||||
android:icon="@drawable/ic_feedback_24dp"
|
||||
android:title="@string/title_pref_feedback" />
|
||||
<item
|
||||
android:id="@+id/privacy_policy"
|
||||
android:icon="@drawable/ic_info_24dp"
|
||||
android:title="@string/title_privacy_policy" />
|
||||
<!-- place holder for version text at the bottom -->
|
||||
<item
|
||||
android:id="@+id/placeholder"
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
android:id="@+id/import_manually_trojan"
|
||||
android:title="@string/menu_item_import_config_manually_trojan"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/import_manually_wireguard"
|
||||
android:title="@string/menu_item_import_config_manually_wireguard"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:title="@string/menu_item_import_config_custom"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<string name="menu_item_import_config_manually_ss">الكتابة يدويا [Shadowsocks]</string>
|
||||
<string name="menu_item_import_config_manually_socks">الكتابة يدويا [Socks]</string>
|
||||
<string name="menu_item_import_config_manually_trojan">الكتابة يدويا [Trojan]</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">[Wireguard] الكتابة يدويا</string>
|
||||
<string name="menu_item_import_config_custom">تكوين مخصص</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">استيراد التكوين المخصص من الحافظة</string>
|
||||
<string name="menu_item_import_config_custom_local">استيراد التكوين المخصص من ملف محلي</string>
|
||||
@@ -62,6 +63,9 @@
|
||||
<string name="server_lab_public_key" translatable="false">مفتاح عام</string>
|
||||
<string name="server_lab_short_id" translatable="false">ShortId</string>
|
||||
<string name="server_lab_spider_x" translatable="false">SpiderX</string>
|
||||
<string name="server_lab_reserved">Reserved (اختياري)</string>
|
||||
<string name="server_lab_local_address">العنوان المحلي IPv4(اختياري)</string>
|
||||
<string name="server_lab_local_mtu">Mtu(optional, default 1420)</string>
|
||||
<string name="toast_success">نجاح</string>
|
||||
<string name="toast_failure">فشل</string>
|
||||
<string name="toast_none_data">لا يوجد شيء</string>
|
||||
@@ -97,7 +101,14 @@
|
||||
<string name="title_pref_per_app_proxy">وكيل لكل تطبيق</string>
|
||||
<string name="summary_pref_per_app_proxy">عام: التطبيق المحدد هو الوكيل، الاتصال غير المحدد مباشر؛ \nوضع التجاوز: التطبيق المحدد متصل مباشرة، الوكيل غير المحدد. \nالخيار لتحديد التطبيق الوكيل تلقائيا في القائمة</string>
|
||||
<string name="title_pref_mux_enabled">تمكين Mux</string>
|
||||
<string name="summary_pref_mux_enabled">التمكين قد يسرع الشبكة والتبديل بين الشبكات قد يكون فلاش</string>
|
||||
<string name="summary_pref_mux_enabled">حركة مرور TCP مع 8 اتصالات افتراضية، قم بتخصيص كيفية التعامل مع UDP وQUIC أدناهn\أسرع، لكنه قد يسبب اتصالاً غير مستقر</string>
|
||||
<string name="title_pref_mux_xudp_concurency">اتصالات XUDP (النطاق من -1 إلى 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">التعامل مع QUIC في نفق مكس</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>يرفض</item>
|
||||
<item>مسموح</item>
|
||||
<item>يتخطى</item>
|
||||
</string-array>
|
||||
<string name="title_pref_speed_enabled">تمكين عرض السرعة</string>
|
||||
<string name="summary_pref_speed_enabled">عرض السرعة الحالية في الإشعار.\nسيتغير رمز الإشعار استنادًا إلى الاستخدام.</string>
|
||||
<string name="title_pref_sniffing_enabled">تمكين Sniffing</string>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<string name="menu_item_import_config_manually_ss">تایپ دستی[Shadowsocks]</string>
|
||||
<string name="menu_item_import_config_manually_socks">تایپ دستی[Socks]</string>
|
||||
<string name="menu_item_import_config_manually_trojan">تایپ دستی[Trojan]</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">[Wireguard]تایپ دستی</string>
|
||||
<string name="menu_item_import_config_custom">پیکربندی سفارشی</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">پیکربندی سفارشی را از کلیپبورد وارد کنید</string>
|
||||
<string name="menu_item_import_config_custom_local">پیکربندی سفارشی را به صورت محلی وارد کنید</string>
|
||||
@@ -59,6 +60,9 @@
|
||||
<string name="server_lab_security4">نامکاربری (اختیاری)</string>
|
||||
<string name="server_lab_encryption">رمزگذاری</string>
|
||||
<string name="server_lab_flow">جریان</string>
|
||||
<string name="server_lab_reserved">Reserved (اختیاری)</string>
|
||||
<string name="server_lab_local_address">آدرس محلی IPv4(اختیاری)</string>
|
||||
<string name="server_lab_local_mtu">Mtu(optional, default 1420)</string>
|
||||
<string name="toast_success">موفقیت</string>
|
||||
<string name="toast_failure">شکست</string>
|
||||
<string name="toast_none_data">چیزی نیست</string>
|
||||
@@ -98,7 +102,14 @@
|
||||
<string name="summary_pref_per_app_proxy">عمومی: برنامه بررسی شده پروکسی است، اتصال مستقیم بدون بررسی است. \nحالت bypass: برنامه بررسی شده مستقیما متصل است، پراکسی بررسی نشده است. \nگزینهای برای انتخاب خودکار پروکسی برنامه در منو است</string>
|
||||
|
||||
<string name="title_pref_mux_enabled">فعال کردن Mux</string>
|
||||
<string name="summary_pref_mux_enabled">فعال کردن شاید سرعت بخشیدن به شبکه و تغییر شبکه شاید فلش، بهبود کند</string>
|
||||
<string name="summary_pref_mux_enabled">سریعتر است، اما ممکن است باعث اتصال ناپایدار شود\nمخزن ترافیک TCP با 8 اتصال پیشفرض، نحوه مدیریت UDP و QUIC را در زیر سفارشی کنید</string>
|
||||
<string name="title_pref_mux_xudp_concurency">اتصالات XUDP (محدوده -1 تا 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">مدیریت QUIC در تونل mux</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>رد کردن</item>
|
||||
<item>مجاز</item>
|
||||
<item>جست و خیز کردن</item>
|
||||
</string-array>
|
||||
|
||||
<string name="title_pref_speed_enabled">فعال کردن نمایش سرعت</string>
|
||||
<string name="summary_pref_speed_enabled">نمایش سرعت فعلی در قسمت آگاهسازی. \nآیکون آگاهسازی بر اساس استفاده تغییر میکند.</string>
|
||||
|
||||
@@ -11,4 +11,5 @@
|
||||
<color name="colorAccent">#FFFFFF</color>
|
||||
<color name="colorBg">#000000</color>
|
||||
<color name="colorText">#FFFFFF</color>
|
||||
<color name="colorMainTestBg">#222222</color>
|
||||
</resources>
|
||||
|
||||
@@ -30,9 +30,10 @@
|
||||
<string name="menu_item_import_config_manually_ss">Ручной ввод профиля Shadowsocks</string>
|
||||
<string name="menu_item_import_config_manually_socks">Ручной ввод профиля Socks</string>
|
||||
<string name="menu_item_import_config_manually_trojan">Ручной ввод профиля Trojan</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">Ручной ввод профиля Wireguard</string>
|
||||
<string name="menu_item_import_config_custom">Пользовательский профиль</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">Импорт из буфера обмена</string>
|
||||
<string name="menu_item_import_config_custom_local">Импорт с устройства</string>
|
||||
<string name="menu_item_import_config_custom_local">Импорт из файла</string>
|
||||
<string name="menu_item_import_config_custom_url">Импорт из URL</string>
|
||||
<string name="menu_item_import_config_custom_url_scan">Импорт сканированием URL</string>
|
||||
<string name="del_config_comfirm">Подтверждаете удаление?</string>
|
||||
@@ -64,6 +65,10 @@
|
||||
<string name="server_lab_public_key" translatable="false">PublicKey</string>
|
||||
<string name="server_lab_short_id" translatable="false">ShortId</string>
|
||||
<string name="server_lab_spider_x" translatable="false">SpiderX</string>
|
||||
<string name="server_lab_secret_key" translatable="false">SecretKey</string>
|
||||
<string name="server_lab_reserved">Reserved (необязательно)</string>
|
||||
<string name="server_lab_local_address">Локальный адрес (необязательно, IPv4/IPv6 через запятую)</string>
|
||||
<string name="server_lab_local_mtu">MTU (необязательно, по умолчанию 1420)</string>
|
||||
<string name="toast_success">Успешно</string>
|
||||
<string name="toast_failure">Ошибка</string>
|
||||
<string name="toast_none_data">Ничего нет</string>
|
||||
@@ -103,7 +108,15 @@
|
||||
<string name="summary_pref_per_app_proxy">Основной: выделенное приложение соединяется через прокси, не выделенное — напрямую; \n\nРежим обхода: выделенное приложение соединяется напрямую, не выделенное — через прокси.\n\nЕсть возможность автоматического выбора проксируемых приложений в меню.</string>
|
||||
|
||||
<string name="title_pref_mux_enabled">Использовать мультиплексирование</string>
|
||||
<string name="summary_pref_mux_enabled">Включение может ускорить работу и переключение сети</string>
|
||||
<string name="summary_pref_mux_enabled">Быстрее, но это может привести к нестабильному соединению.\nНиже можно настроить обработку TCP, UDP и QUIC.</string>
|
||||
<string name="title_pref_mux_concurency">TCP-соединения (диапазон от -1 до 1024)</string>
|
||||
<string name="title_pref_mux_xudp_concurency">XUDP-соединения (диапазон от -1 до 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">Обработка QUIC в мультиплексном туннеле</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>отклонять</item>
|
||||
<item>разрешать</item>
|
||||
<item>пропускать</item>
|
||||
</string-array>
|
||||
|
||||
<string name="title_pref_speed_enabled">Отображение скорости</string>
|
||||
<string name="summary_pref_speed_enabled">Показывать текущую скорость в уведомлении.\nЗначок будет меняться в зависимости от использования.</string>
|
||||
@@ -159,10 +172,15 @@
|
||||
<string name="summary_pref_feedback">Предложить улучшение или сообщить об ошибке на GitHub</string>
|
||||
<string name="summary_pref_tg_group">Присоединиться к группе в Telegram</string>
|
||||
<string name="toast_tg_app_not_found">Приложение Telegram не найдено</string>
|
||||
<string name="title_privacy_policy">Конфиденциальность</string>
|
||||
|
||||
<string name="title_pref_promotion">Содействие</string>
|
||||
<string name="summary_pref_promotion">Содействие, нажмите для получения подробной информации (пожертвование может быть удалено)</string>
|
||||
|
||||
<string name="title_pref_auto_update_subscription">Автоматическое обновление подписок</string>
|
||||
<string name="summary_pref_auto_update_subscription">Автоматическое обновление подписок в фоновом режиме с указанным интервалом. В зависимости от устройства эта функция может работать не всегда.</string>
|
||||
<string name="title_pref_auto_update_interval">Интервал автообновления (мин., не менее 15)</string>
|
||||
|
||||
<string name="title_core_loglevel">Подробность ведения журнала</string>
|
||||
<string name="title_mode">Режим</string>
|
||||
<string name="title_mode_help">Нажмите для получения дополнительной информации</string>
|
||||
@@ -175,12 +193,13 @@
|
||||
<string name="title_service_restart">Перезапуск службы</string>
|
||||
<string name="title_del_all_config">Удалить все профили</string>
|
||||
<string name="title_del_duplicate_config">Удалить дубликаты профилей</string>
|
||||
<string name="title_del_invalid_config">Удалить сбойные профили (после проверки)</string>
|
||||
<string name="title_del_invalid_config">Удалить нерабочие профили (после проверки)</string>
|
||||
<string name="title_export_all">Экспорт всех профилей в буфер обмена</string>
|
||||
<string name="title_sub_setting">Группы</string>
|
||||
<string name="sub_setting_remarks">примечания</string>
|
||||
<string name="sub_setting_url">URL (необязательно)</string>
|
||||
<string name="sub_setting_enable">использовать обновление</string>
|
||||
<string name="sub_setting_enable">Использовать обновление</string>
|
||||
<string name="sub_auto_update">Использовать автоматическое обновление</string>
|
||||
<string name="title_sub_update">Обновить подписку</string>
|
||||
<string name="title_ping_all_server">Проверка доступности профилей</string>
|
||||
<string name="title_real_ping_all_server">Время отклика профилей</string>
|
||||
@@ -199,7 +218,7 @@
|
||||
<string name="routing_settings_delete">Очистить</string>
|
||||
<string name="routing_settings_scan_replace">Сканировать и заменить</string>
|
||||
<string name="routing_settings_scan_append">Сканировать и добавить</string>
|
||||
<string name="routing_settings_default_rules"> Правила по умолчанию</string>
|
||||
<string name="routing_settings_default_rules">Правила по умолчанию</string>
|
||||
|
||||
<string name="connection_test_pending">Проверить подключение</string>
|
||||
<string name="connection_test_testing">Проверка…</string>
|
||||
@@ -210,6 +229,9 @@
|
||||
<string name="connection_connected">Подключено, нажмите для проверки</string>
|
||||
<string name="connection_not_connected">Не подключено</string>
|
||||
|
||||
<string name="import_subscription_success">Подписка импортирована</string>
|
||||
<string name="import_subscription_failure">Невозможно импортировать подписку</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>QR-код</item>
|
||||
<item>Экспорт в буфер обмена</item>
|
||||
@@ -239,7 +261,5 @@
|
||||
<item>VPN</item>
|
||||
<item>Только прокси</item>
|
||||
</string-array>
|
||||
<string name="import_subscription_success">Подписка импортирована</string>
|
||||
<string name="import_subscription_failure">Подписка не импортирована</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
<string name="notification_action_stop_v2ray">Ngắt kết nối v2rayNG</string>
|
||||
<string name="toast_permission_denied">Vui lòng cấp quyền cần thiết cho v2rayNG! Bạn đã từ chối các quyền cần thiết như Camera hay Bộ nhớ?</string>
|
||||
<string name="notification_action_more">Nhấn để biết thêm</string>
|
||||
<string name="toast_services_start">Đang bắt đầu v2rayNG...</string>
|
||||
<string name="toast_services_start">Đang khởi động v2rayNG...</string>
|
||||
<string name="toast_services_stop">Đã dừng v2rayNG!</string>
|
||||
<string name="toast_services_success">Đã bắt đầu v2rayNG!</string>
|
||||
<string name="toast_services_failure">Không thể bắt đầu v2rayNG, kiểm tra lại cấu hình hoặc khởi động lại thiết bị.</string>
|
||||
<string name="toast_services_success">Đã khởi động v2rayNG!</string>
|
||||
<string name="toast_services_failure">Không thể khởi động v2rayNG, kiểm tra lại cấu hình.</string>
|
||||
|
||||
<!--ServerActivity-->
|
||||
<string name="title_server">v2rayNG</string>
|
||||
@@ -29,35 +29,39 @@
|
||||
<string name="menu_item_import_config_manually_ss">Nhập thủ công [Shadowsocks]</string>
|
||||
<string name="menu_item_import_config_manually_socks">Nhập thủ công [Socks]</string>
|
||||
<string name="menu_item_import_config_manually_trojan">Nhập thủ công [Trojan]</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">Nhập thủ công [Wireguard]</string>
|
||||
<string name="menu_item_import_config_custom">Nâng cao / Cấu hình tùy chỉnh</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">Nhập cấu hình tùy chỉnh từ Clipboard</string>
|
||||
<string name="menu_item_import_config_custom_local">Nhập cấu hình tùy chỉnh từ Tệp</string>
|
||||
<string name="menu_item_import_config_custom_url">Nhập cấu hình tùy chỉnh từ URL</string>
|
||||
<string name="menu_item_import_config_custom_url_scan">Nhập cấu hình tùy chỉnh quét URL</string>
|
||||
<string name="del_config_comfirm">Bạn có muốn xóa cấu hình không?</string>
|
||||
<string name="del_config_comfirm">Xác nhận xóa?</string>
|
||||
<string name="server_lab_remarks">Tên cấu hình</string>
|
||||
<string name="server_lab_address">Địa chỉ</string>
|
||||
<string name="server_lab_port">Cổng</string>
|
||||
<string name="server_lab_id">ID</string>
|
||||
<string name="server_lab_alterid">ID thay thế</string>
|
||||
<string name="server_lab_security">Bảo mật</string>
|
||||
<string name="server_lab_network">Kiểu kết nối</string>
|
||||
<string name="server_lab_alterid">alterId</string>
|
||||
<string name="server_lab_security">Thuật toán mã hóa</string>
|
||||
<string name="server_lab_network">Giao thức truyền tải (network)</string>
|
||||
<string name="server_lab_more_function">Nâng cao</string>
|
||||
<string name="server_lab_head_type">Loại Head</string>
|
||||
<string name="server_lab_head_type">Kiểu ngụy trang (type)</string>
|
||||
<string name="server_lab_mode_type">Chế độ gRPC</string>
|
||||
<string name="server_lab_request_host">Yêu cầu host (Host/WS/H2) / Bảo mật QUIC</string>
|
||||
<string name="server_lab_path">Đường dẫn (WS/H2) / Khóa QUIC / KCP seed / Dịch vụ gRPC</string>
|
||||
<string name="server_lab_request_host">Yêu cầu host(host/ws host/h2 host)/QUIC security</string>
|
||||
<string name="server_lab_path">path(ws path/h2 path)/QUIC key/kcp seed/gRPC serviceName</string>
|
||||
<string name="server_lab_stream_security">TLS</string>
|
||||
<string name="server_lab_allow_insecure">Bỏ qua xác minh chứng chỉ</string>
|
||||
<string name="server_lab_sni">Địa chỉ SNI</string>
|
||||
<string name="server_lab_allow_insecure">allowInsecure</string>
|
||||
<string name="server_lab_sni">SNI</string>
|
||||
<string name="server_lab_address3">Địa chỉ</string>
|
||||
<string name="server_lab_port3">Cổng</string>
|
||||
<string name="server_lab_id3">Mật khẩu</string>
|
||||
<string name="server_lab_security3">Bảo mật</string>
|
||||
<string name="server_lab_id4">Mật khẩu (Bổ sung)</string>
|
||||
<string name="server_lab_security4">Tên người dùng (Bổ sung)</string>
|
||||
<string name="server_lab_encryption">Mã hoá</string>
|
||||
<string name="server_lab_flow">Kiểm soát lưu lượng</string>
|
||||
<string name="server_lab_security3">Thuật toán mã hóa</string>
|
||||
<string name="server_lab_id4">Mật khẩu (không bắt buộc)</string>
|
||||
<string name="server_lab_security4">Tên người dùng (không bắt buộc)</string>
|
||||
<string name="server_lab_encryption">Mã hóa</string>
|
||||
<string name="server_lab_flow">Kiểm soát lưu lượng (flow)</string>
|
||||
<string name="server_lab_reserved">Reserved (không bắt buộc)</string>
|
||||
<string name="server_lab_local_address">Địa chỉ cục bộ (IPv4/IPv6, phân cách bằng dấu phẩy)</string>
|
||||
<string name="server_lab_local_mtu">MTU (không bắt buộc, mặc định 1420)</string>
|
||||
<string name="toast_success">Thành công!</string>
|
||||
<string name="toast_failure">Đã xảy ra lỗi, vui lòng thử lại!</string>
|
||||
<string name="toast_none_data">Không có gì ở đây</string>
|
||||
@@ -72,7 +76,7 @@
|
||||
<string name="toast_invalid_url">URL không hợp lệ hoặc trống!</string>
|
||||
<string name="server_lab_need_inbound">Vui lòng đảm bảo cấu hình tùy chỉnh này không bị lỗi trước khi sử dụng!</string>
|
||||
<string name="toast_malformed_josn">Cấu hình không hợp lệ!</string>
|
||||
<string name="server_lab_request_host6">Host (SNI) (Bổ sung)</string>
|
||||
<string name="server_lab_request_host6">Host (SNI) (không bắt buộc)</string>
|
||||
<string name="toast_asset_copy_failed">Không thể sao chép tệp tin, hãy dùng trình quản lý tệp!</string>
|
||||
<string name="menu_item_add_file">Thêm tệp</string>
|
||||
<string name="menu_item_download_file">Tải xuống tệp tin</string>
|
||||
@@ -82,7 +86,7 @@
|
||||
<string name="menu_item_search">Tìm kiếm</string>
|
||||
<string name="menu_item_select_all">Chọn tất cả</string>
|
||||
<string name="msg_enter_keywords">Nhập từ khoá</string>
|
||||
<string name="switch_bypass_apps_mode">Bỏ qua kết nối VPN</string>
|
||||
<string name="switch_bypass_apps_mode">Chế độ Bypass</string>
|
||||
<string name="menu_item_select_proxy_app">Tự động chọn ứng dụng Proxy</string>
|
||||
<string name="msg_downloading_content">Đang tải xuống nội dung...</string>
|
||||
<string name="menu_item_export_proxy_app">Xuất và sao chép</string>
|
||||
@@ -93,46 +97,55 @@
|
||||
<string name="title_settings">Cài đặt</string>
|
||||
<string name="title_advanced">Cài đặt nâng cao</string>
|
||||
<string name="title_vpn_settings">Cài đặt VPN</string>
|
||||
<string name="title_pref_per_app_proxy">Proxy ứng dụng</string>
|
||||
<string name="summary_pref_per_app_proxy">- Chung: Ứng dụng đã chọn sẽ kết nối Proxy, chưa lựa chọn sẽ kết nối trực tiếp. \n- Bỏ qua kết nối: Ứng dụng được chọn sẽ trực tiếp kết nối, không lựa chọn sẽ kết nối qua Proxy. \n- Lựa chọn để tự động chọn ứng dụng Proxy trong Menu.</string>
|
||||
<string name="title_pref_per_app_proxy">Proxy Theo Ứng Dụng</string>
|
||||
<string name="summary_pref_per_app_proxy">- Bình thường: Ứng dụng đã chọn sẽ kết nối thông qua Proxy, chưa lựa chọn sẽ kết nối trực tiếp. \n- Chế độ Bypass: Ứng dụng được chọn sẽ kết nối trực tiếp, không lựa chọn sẽ kết nối qua Proxy. \n- Nếu bạn ở Trung Quốc thì chọn Tự động chọn ứng dụng Proxy trong Menu.</string>
|
||||
|
||||
<string name="title_pref_mux_enabled">Cho phép Mux</string>
|
||||
<string name="summary_pref_mux_enabled">Bật lên có thể làm tăng tốc độ mạng và chuyển mạng nhanh hơn.</string>
|
||||
<string name="title_pref_mux_enabled">Bật Mux</string>
|
||||
<string name="summary_pref_mux_enabled">Giảm độ trễ trong bước bắt tay của kết nối TCP. Mux phân phối dữ liệu từ nhiều kết nối TCP trên một kết nối TCP duy nhất. Không nên sử dụng Mux để xem video, download file hoặc chạy speedtest vì thường không hiệu quả.</string>
|
||||
<string name="title_pref_mux_concurency">TCP connections (từ 1 đến 1024)</string>
|
||||
<string name="title_pref_mux_xudp_concurency">XUDP connections (từ 1 đến 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">Handling of QUIC traffic in mux tunnel.</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>Từ chối</item>
|
||||
<item>Cho phép</item>
|
||||
<item>Bỏ qua</item>
|
||||
</string-array>
|
||||
|
||||
<string name="title_pref_speed_enabled">Cho phép hiển thị tốc độ mạng</string>
|
||||
<string name="summary_pref_speed_enabled">Hiển thị tốc độ mạng hiện tại trên thanh thông báo.\nBiểu tượng trên thanh trạng thái có thể thay đổi tùy vào mức sử dụng.</string>
|
||||
|
||||
<string name="title_pref_sniffing_enabled">Bật tính năng phát hiện luồng</string>
|
||||
<string name="summary_pref_sniffing_enabled">Thử chuyển kết nối hiện tại của bạn qua trung gian để trung gian xử lý kết nối về lại cho bạn. (Mặc định là bật, hãy tắt nó nếu kết nối không ổn định)</string>
|
||||
<string name="title_pref_speed_enabled">Bật Hiển thị tốc độ mạng</string>
|
||||
<string name="summary_pref_speed_enabled">Hiển thị tốc độ mạng hiện tại trên thanh thông báo. \nBiểu tượng trên thanh trạng thái có thể thay đổi tùy vào mức sử dụng.</string>
|
||||
|
||||
<string name="title_pref_local_dns_enabled">Cho phép DNS cục bộ</string>
|
||||
<string name="summary_pref_local_dns_enabled">DNS được xử lý bởi mô đun của lõi DNS. (Khuyến nghị, nếu cần định tuyến Bỏ qua mạng LAN và địa chỉ đất liền)</string>
|
||||
<string name="title_pref_sniffing_enabled">Bật Sniffing</string>
|
||||
<string name="summary_pref_sniffing_enabled">Nhận diện tên miền từ gói tin để phục vụ định tuyến. \n(phải tắt để xài Zalo)</string>
|
||||
|
||||
<string name="title_pref_fake_dns_enabled">Cho phép DNS giả</string>
|
||||
<string name="summary_pref_fake_dns_enabled">DNS cục bộ trả về địa chỉ IP giả. (Nhanh hơn, nhưng có thể không hoạt động với một số ứng dụng)</string>
|
||||
<string name="title_pref_local_dns_enabled">Bật Local DNS</string>
|
||||
<string name="summary_pref_local_dns_enabled">DNS được xử lý bởi mô-đun DNS của xray-core (dùng nếu cần định tuyến bypass cho mạng LAN và địa chỉ nội địa)</string>
|
||||
|
||||
<string name="title_pref_fake_dns_enabled">Bật FakeDNS</string>
|
||||
<string name="summary_pref_fake_dns_enabled">FakeDNS lấy tên miền mục tiêu bằng cách giả mạo DNS (nhanh hơn, nhưng có thể không hoạt động cho một số ứng dụng)</string>
|
||||
|
||||
<string name="title_pref_prefer_ipv6">Ưu tiên IPv6</string>
|
||||
<string name="summary_pref_prefer_ipv6">Ưu tiên sử dụng địa chỉ IPv6 cho kết nối và lộ trình.</string>
|
||||
<string name="summary_pref_prefer_ipv6">Ưu tiên sử dụng địa chỉ IPv6 cho kết nối và định tuyến.</string>
|
||||
|
||||
<string name="title_pref_routing">Lộ trình</string>
|
||||
<string name="title_pref_routing_domain_strategy">Tùy chọn tên miền</string>
|
||||
<string name="title_pref_routing_mode">Tùy chỉnh quy tắc lộ trình</string>
|
||||
<string name="title_pref_routing_custom">Tùy chỉnh lộ trình</string>
|
||||
<string name="title_pref_routing">Định tuyến</string>
|
||||
<string name="title_pref_routing_domain_strategy">Chiến lược tên miền (domainStrategy)</string>
|
||||
<string name="title_pref_routing_mode">Quy tắc được định nghĩa trước</string>
|
||||
<string name="title_pref_routing_custom">Quy tắc tùy chỉnh</string>
|
||||
|
||||
<string name="title_pref_remote_dns">Điều khiển DNS (Bổ sung)</string>
|
||||
<string name="title_pref_remote_dns">DNS ngoại quốc (không bắt buộc)</string>
|
||||
<string name="summary_pref_remote_dns">DNS</string>
|
||||
|
||||
<string name="title_pref_vpn_dns">VPN DNS (Chỉ IPv4/IPv6)</string>
|
||||
|
||||
<string name="title_pref_domestic_dns">DNS trong nước (Bổ sung)</string>
|
||||
<string name="title_pref_domestic_dns">DNS nội địa (không bắt buộc)</string>
|
||||
<string name="summary_pref_domestic_dns">DNS</string>
|
||||
|
||||
<string name="title_pref_proxy_sharing_enabled">Cho phép kết nối từ mạng LAN</string>
|
||||
<string name="summary_pref_proxy_sharing_enabled">Các thiết bị khác có thể kết nối đến Proxy bởi địa chỉ IP thông qua Socks/HTTP, chỉ bật khi bạn tin tưởng kết nối đó.</string>
|
||||
<string name="toast_warning_pref_proxysharing_short">Cho phép kết nối từ mạng LAN, đảm bảo rằng bạn tin tưởng kết nối hiện tại!</string>
|
||||
<string name="summary_pref_proxy_sharing_enabled">Các thiết bị khác trong cùng mạng LAN có thể kết nối đến SOCKS/HTTP proxy trên thiết bị của ban. \nChỉ bật tính năng này trong các mạng đáng tin cậy để tránh kết nối trái phép.</string>
|
||||
<string name="toast_warning_pref_proxysharing_short">Đang bật cho phép kết nối từ mạng LAN</string>
|
||||
|
||||
<string name="title_pref_allow_insecure">Cho phép đặt lại Bỏ qua xác minh chứng chỉ</string>
|
||||
<string name="summary_pref_allow_insecure">Khi kết nối TLS, đặt cài đặt Bỏ qua xác minh chứng chỉ thành mặc định.</string>
|
||||
<string name="title_pref_allow_insecure">allowInsecure</string>
|
||||
<string name="summary_pref_allow_insecure">Khi nhập những cấu hình có bảo mật TLS, mặc định sẽ bỏ qua xác minh chứng chỉ (allowInsecure: true).</string>
|
||||
|
||||
<string name="title_pref_socks_port">Cổng Proxy SOCKS5</string>
|
||||
<string name="summary_pref_socks_port">Cổng Proxy SOCKS5</string>
|
||||
@@ -140,13 +153,13 @@
|
||||
<string name="title_pref_http_port">Cổng Proxy HTTP</string>
|
||||
<string name="summary_pref_http_port">Cổng Proxy HTTP</string>
|
||||
|
||||
<string name="title_pref_local_dns_port">Cổng DNS cục bộ</string>
|
||||
<string name="summary_pref_local_dns_port">Cổng DNS cục bộ</string>
|
||||
<string name="title_pref_local_dns_port">Cổng Local DNS</string>
|
||||
<string name="summary_pref_local_dns_port">Cổng Local DNS</string>
|
||||
|
||||
<string name="title_pref_confirm_remove">Hiển thị thông báo xác nhận xoá cấu hình</string>
|
||||
<string name="summary_pref_confirm_remove">Hiển thị thông báo xác nhận xoá cấu hình khi bạn xoá một cấu hình.</string>
|
||||
<string name="title_pref_confirm_remove">Xác nhận xóa tệp cấu hình</string>
|
||||
<string name="summary_pref_confirm_remove">Yêu cầu xác nhận từ người dùng khi thực hiện xóa tệp cấu hình.</string>
|
||||
|
||||
<string name="title_pref_start_scan_immediate">Bắt đầu quét mã QR ngay lập tức</string>
|
||||
<string name="title_pref_start_scan_immediate">Quét mã QR ngay lập tức</string>
|
||||
<string name="summary_pref_start_scan_immediate">Mở camera để quét QR ngay khi khởi động, nếu không bạn có thể chọn quét mã hoặc chọn ảnh trên thanh công cụ.</string>
|
||||
|
||||
<string name="title_pref_feedback">Phản hồi lỗi</string>
|
||||
@@ -154,58 +167,63 @@
|
||||
<string name="summary_pref_tg_group">Tham gia nhóm Telegram</string>
|
||||
<string name="toast_tg_app_not_found">Không tìm thấy ứng dụng Telegram</string>
|
||||
|
||||
<string name="title_pref_promotion">Quảng cáo Server</string>
|
||||
<string name="title_pref_promotion">Quảng bá server</string>
|
||||
<string name="summary_pref_promotion">Quảng cáo, nhấn để biết thêm (Ủng hộ có thể được gỡ bỏ)</string>
|
||||
|
||||
<string name="title_core_loglevel">Mức độ nhật ký</string>
|
||||
<string name="title_pref_auto_update_subscription">Tự động cập nhật các gói đăng ký</string>
|
||||
<string name="summary_pref_auto_update_subscription">Tự động cập nhật các gói đăng ký của bạn ở trong nền với khoảng thời gian cố định. Tùy thiết bị, tính năng này có thể không luôn hoạt động đúng như mong đợi.</string>
|
||||
<string name="title_pref_auto_update_interval">Thời gian Cập nhật tự động (Phút, Giá trị tối thiểu 15)</string>
|
||||
|
||||
<string name="title_core_loglevel">Log level</string>
|
||||
<string name="title_mode">Chế độ kết nối</string>
|
||||
<string name="title_mode_help">Nhấn vào đây nếu bạn cần trợ giúp!</string>
|
||||
<string name="title_language">Ngôn ngữ</string>
|
||||
<string name="title_ui_settings">Cài đặt UI</string>
|
||||
<string name="title_ui_settings">Cài đặt giao diện</string>
|
||||
|
||||
<string name="title_logcat">Nhật ký hoạt động</string>
|
||||
<string name="logcat_copy">Sao chép nhật ký</string>
|
||||
<string name="logcat_clear">Xoá nhật ký</string>
|
||||
<string name="title_service_restart">Kết nối lại v2rayNG</string>
|
||||
<string name="title_logcat">Logcat</string>
|
||||
<string name="logcat_copy">Sao chép</string>
|
||||
<string name="logcat_clear">Xoá</string>
|
||||
<string name="title_service_restart">Khởi động lại dịch vụ lõi</string>
|
||||
<string name="title_del_all_config">Xoá tất cả cấu hình</string>
|
||||
<string name="title_del_duplicate_config">Xoá cấu hình trùng lặp</string>
|
||||
<string name="title_del_invalid_config">Xoá cấu hình lỗi (Kiểm tra trước)</string>
|
||||
<string name="title_del_invalid_config">Xoá cấu hình lỗi</string>
|
||||
<string name="title_export_all">Xuất và sao chép tất cả cấu hình</string>
|
||||
<string name="title_sub_setting">Các gói đăng ký</string>
|
||||
<string name="sub_setting_remarks">Tên các gói đăng ký</string>
|
||||
<string name="sub_setting_remarks">Tên gói đăng ký</string>
|
||||
<string name="sub_setting_url">URL gói đăng ký</string>
|
||||
<string name="sub_setting_enable">Sử dụng gói đăng ký này</string>
|
||||
<string name="sub_auto_update">Bật tự động cập nhật</string>
|
||||
<string name="title_sub_update">Cập nhật các gói đăng ký</string>
|
||||
<string name="title_ping_all_server">Ping tất cả máy chủ</string>
|
||||
<string name="title_real_ping_all_server">Kiểm tra máy chủ</string>
|
||||
<string name="title_real_ping_all_server">Test HTTP tất cả máy chủ</string>
|
||||
<string name="title_user_asset_setting">Tệp Geo asset</string>
|
||||
<string name="title_sort_by_test_results">Sắp xếp lại theo lần kiểm tra cuối cùng</string>
|
||||
<string name="title_filter_config">Lọc cấu hình theo các gói đăng ký</string>
|
||||
<string name="filter_config_all">Hiển thị tất cả các gói đăng ký</string>
|
||||
<string name="title_del_duplicate_config_count">Xoá %d cấu hình trùng lặp</string>
|
||||
|
||||
<string name="tasker_start_service">Bắt đầu v2rayNG</string>
|
||||
<string name="tasker_start_service">Khởi động v2rayNG</string>
|
||||
<string name="tasker_setting_confirm">Xác nhận</string>
|
||||
|
||||
<string name="routing_settings_title">Cài đặt lộ trình</string>
|
||||
<string name="routing_settings_tips">Được phân cách bằng dấu phẩy (,). Hãy nhớ nó để lưu lại!</string>
|
||||
<string name="routing_settings_title">Cài đặt định tuyến</string>
|
||||
<string name="routing_settings_tips">Phân cách bằng dấu phẩy (,). Có thể tải xuống rules mặc định để tham khảo ở menu ba chấm</string>
|
||||
<string name="routing_settings_save">Lưu lại</string>
|
||||
<string name="routing_settings_delete">Xoá</string>
|
||||
<string name="routing_settings_scan_replace">Quét và thay thế</string>
|
||||
<string name="routing_settings_scan_append">Quét và nối</string>
|
||||
<string name="routing_settings_default_rules">Đặt luật cho lộ trình mặc định</string>
|
||||
<string name="routing_settings_scan_replace">Quét QR và thay thế</string>
|
||||
<string name="routing_settings_scan_append">Quét QR và nối thêm</string>
|
||||
<string name="routing_settings_default_rules">Tải xuống rules mặc định cho China</string>
|
||||
|
||||
<string name="connection_test_pending">Kiểm tra kết nối</string>
|
||||
<string name="connection_test_testing">Đang kiểm tra kết nối mạng...</string>
|
||||
<string name="connection_test_available">Kiểm tra kết nối mạng thành công! Ping hiện tại là %d</string>
|
||||
<string name="connection_test_available">Test thành công: kết nối đến Google.com mất %d ms</string>
|
||||
<string name="connection_test_error">Lỗi kết nối mạng, hãy thử đổi cấu hình hoặc kiểm tra lại! Mã lỗi: %s</string>
|
||||
<string name="connection_test_fail">Không có kết nối mạng!</string>
|
||||
<string name="connection_test_error_status_code">Mã lỗi: #%d</string>
|
||||
<string name="connection_connected">Đã kết nối, hãy nhấn vào đây để kiểm tra kết nối mạng!</string>
|
||||
<string name="connection_not_connected">Chưa kết nối, hãy chọn một cấu hình để kết nối!</string>
|
||||
<string name="connection_connected">Đã kết nối, nhấn vào đây để kiểm tra kết nối mạng!</string>
|
||||
<string name="connection_not_connected">Chưa kết nối</string>
|
||||
|
||||
<string name="import_subscription_success">Đăng ký đã nhập thành công</string>
|
||||
<string name="import_subscription_failure">Nhập đăng ký không thành công</string>
|
||||
<string name="import_subscription_success">Nhập gói đăng ký thành công!</string>
|
||||
<string name="import_subscription_failure">Nhập gói đăng ký không thành công!</string>
|
||||
|
||||
<string-array name="share_method">
|
||||
<item>Xuất ra mã QR (Chụp màn hình để lưu)</item>
|
||||
@@ -219,16 +237,16 @@
|
||||
</string-array>
|
||||
|
||||
<string-array name="routing_tag">
|
||||
<item>Proxy URL hoặc IP</item>
|
||||
<item>Direct URL hoặc IP</item>
|
||||
<item>URL đã chặn hoặc IP</item>
|
||||
<item>Proxy</item>
|
||||
<item>Direct</item>
|
||||
<item>Blocked</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="routing_mode">
|
||||
<item>Proxy toàn cầu</item>
|
||||
<item>Bỏ qua địa chỉ LAN rồi Proxy</item>
|
||||
<item>Bỏ qua địa chỉ đất liền rồi Proxy</item>
|
||||
<item>Bỏ qua LAN và địa chỉ đất liền rồi Proxy</item>
|
||||
<item>Bỏ qua địa chỉ nội địa rồi Proxy</item>
|
||||
<item>Bỏ qua LAN và địa chỉ nội địa rồi Proxy</item>
|
||||
<item>Kết nối trực tiếp toàn cầu</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<string name="menu_item_import_config_manually_ss">手动输入[Shadowsocks]</string>
|
||||
<string name="menu_item_import_config_manually_socks">手动输入[Socks]</string>
|
||||
<string name="menu_item_import_config_manually_trojan">手动输入[Trojan]</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">手动输入[Wireguard]</string>
|
||||
<string name="menu_item_import_config_custom">自定义配置</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">从剪贴板导入自定义配置</string>
|
||||
<string name="menu_item_import_config_custom_local">从本地导入自定义配置</string>
|
||||
@@ -58,6 +59,9 @@
|
||||
<string name="server_lab_security4">用户名(可选)</string>
|
||||
<string name="server_lab_encryption">加密方式(encryption)</string>
|
||||
<string name="server_lab_flow">流控(flow)</string>
|
||||
<string name="server_lab_reserved">Reserved(可选)</string>
|
||||
<string name="server_lab_local_address">本地地址(可选IPv4/IPv6,逗号隔开)</string>
|
||||
<string name="server_lab_local_mtu">Mtu(可选, 默认1420)</string>
|
||||
<string name="toast_success">成功</string>
|
||||
<string name="toast_failure">失败</string>
|
||||
<string name="toast_none_data">没有数据</string>
|
||||
@@ -96,8 +100,16 @@
|
||||
<string name="title_pref_per_app_proxy">分应用代理</string>
|
||||
<string name="summary_pref_per_app_proxy">常规:勾选的App被代理,未勾选的直连;\n绕行模式:勾选的App直连,未勾选的被代理.\n不明白者在菜单中选择自动选中需代理应用</string>
|
||||
|
||||
<string name="title_pref_mux_enabled">启用Mux多路复用</string>
|
||||
<string name="summary_pref_mux_enabled">开启可能会加速,关闭可能会减少断流</string>
|
||||
<string name="title_pref_mux_enabled">启用 Mux 多路复用</string>
|
||||
<string name="summary_pref_mux_enabled">减低延时,但可能会断流,建议不要启用。\nTCP,UDP 及 QUIC 流量处理方式下方可选。</string>
|
||||
<string name="title_pref_mux_concurency">TCP 复用子链接数(可填 -1 至 1024)</string>
|
||||
<string name="title_pref_mux_xudp_concurency">XUDP 复用子链接数(可填 -1 至 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">QUIC 流量处理方式</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>不代理</item>
|
||||
<item>多路复用</item>
|
||||
<item>原生</item>
|
||||
</string-array>
|
||||
|
||||
<string name="title_pref_speed_enabled">启用速度显示</string>
|
||||
<string name="summary_pref_speed_enabled">在通知中显示当前速度\n小图标显示流量的路由情况</string>
|
||||
@@ -153,10 +165,15 @@
|
||||
<string name="summary_pref_feedback">反馈改进或漏洞至 GitHub</string>
|
||||
<string name="summary_pref_tg_group">加入Telegram Group</string>
|
||||
<string name="toast_tg_app_not_found">未找到Telegram app</string>
|
||||
<string name="title_privacy_policy">隐私权政策</string>
|
||||
|
||||
<string name="title_pref_promotion">推广</string>
|
||||
<string name="summary_pref_promotion">一些推广,点击查看详情(捐赠可去除)</string>
|
||||
|
||||
<string name="title_pref_auto_update_subscription">自动更新订阅</string>
|
||||
<string name="summary_pref_auto_update_subscription">在后台按一定时间间隔自动更新您的订阅。受设备影响,此功能不一定总是有效</string>
|
||||
<string name="title_pref_auto_update_interval">自动更新间隔(分钟,最小值15)</string>
|
||||
|
||||
<string name="title_core_loglevel">日志级别</string>
|
||||
<string name="title_mode">模式</string>
|
||||
<string name="title_mode_help">点此查看更多帮助</string>
|
||||
@@ -175,6 +192,7 @@
|
||||
<string name="sub_setting_remarks">备注</string>
|
||||
<string name="sub_setting_url">可选地址(url)</string>
|
||||
<string name="sub_setting_enable">启用更新</string>
|
||||
<string name="sub_auto_update">启用自动更新</string>
|
||||
<string name="title_sub_update">更新订阅</string>
|
||||
<string name="title_ping_all_server">测试全部配置Tcping</string>
|
||||
<string name="title_real_ping_all_server">测试全部配置真连接</string>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<string name="menu_item_import_config_manually_ss">手動鍵入 [Shadowsocks]</string>
|
||||
<string name="menu_item_import_config_manually_socks">手動鍵入 [Socks]</string>
|
||||
<string name="menu_item_import_config_manually_trojan">手動鍵入 [Trojan]</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">手動鍵入 [Wireguard]</string>
|
||||
<string name="menu_item_import_config_custom">自訂組態</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">從剪貼簿匯入自訂組態</string>
|
||||
<string name="menu_item_import_config_custom_local">從本地匯入自訂組態</string>
|
||||
@@ -58,6 +59,9 @@
|
||||
<string name="server_lab_security4">使用者名稱 (可選)</string>
|
||||
<string name="server_lab_encryption">加密 (encryption)</string>
|
||||
<string name="server_lab_flow">流程 (flow)</string>
|
||||
<string name="server_lab_reserved">Reserved (可選)</string>
|
||||
<string name="server_lab_local_address">本機位址(可選IPv4/IPv6,逗號隔開)</string>
|
||||
<string name="server_lab_local_mtu">Mtu(可選, 預設1420)</string>
|
||||
<string name="toast_success">成功</string>
|
||||
<string name="toast_failure">失敗</string>
|
||||
<string name="toast_none_data">無資料</string>
|
||||
@@ -96,8 +100,16 @@
|
||||
<string name="title_pref_per_app_proxy">Proxy 個別應用程式</string>
|
||||
<string name="summary_pref_per_app_proxy">常規:勾選的 App 啟用 Proxy,未勾選的直接連線;\n繞行模式:勾選的 App 直接連線,未勾選的啟用 Proxy。\n可在選單中選擇自動選中需 Proxy 應用</string>
|
||||
|
||||
<string name="title_pref_mux_enabled">啟用 Mux</string>
|
||||
<string name="summary_pref_mux_enabled">啟用或許會加快網路速度,切換或許會閃爍</string>
|
||||
<string name="title_pref_mux_enabled">啟用 Mux 多路復用</string>
|
||||
<string name="summary_pref_mux_enabled">減低延時 但可能會斷流\nTCP,UDP 及 QUIC 流量處理方式下方可選</string>
|
||||
<string name="title_pref_mux_concurency">TCP 復用子鏈接數(可填 -1 至 1024)</string>
|
||||
<string name="title_pref_mux_xudp_concurency">XUDP 復用子鏈接數(可填 -1 至 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">QUIC 流量處理方式</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>不代理</item>
|
||||
<item>多路復用</item>
|
||||
<item>原生</item>
|
||||
</string-array>
|
||||
|
||||
<string name="title_pref_speed_enabled">啟用速度顯示</string>
|
||||
<string name="summary_pref_speed_enabled">在通知中顯示當前速度\n小圖示顯示流量的轉送狀況</string>
|
||||
@@ -153,10 +165,15 @@
|
||||
<string name="summary_pref_feedback">前往 GitHub 回報錯誤</string>
|
||||
<string name="summary_pref_tg_group">加入 Telegram 群組</string>
|
||||
<string name="toast_tg_app_not_found">未找到 Telegram 應用程式</string>
|
||||
<string name="title_privacy_policy">隱私權政策</string>
|
||||
|
||||
<string name="title_pref_promotion">推廣</string>
|
||||
<string name="summary_pref_promotion">一些推廣,輕觸以檢視 (捐贈可去除)</string>
|
||||
|
||||
<string name="title_pref_auto_update_subscription">自動更新訂閱</string>
|
||||
<string name="summary_pref_auto_update_subscription">在後台以一定時間間隔自動更新您的訂閱。受設備影響,此功能不一定總是有效</string>
|
||||
<string name="title_pref_auto_update_interval">自動更新間隔(分鐘,最小值15)</string>
|
||||
|
||||
<string name="title_core_loglevel">記錄層級</string>
|
||||
<string name="title_mode">模式</string>
|
||||
<string name="title_mode_help">輕觸以檢視說明</string>
|
||||
@@ -175,6 +192,7 @@
|
||||
<string name="sub_setting_remarks">備註</string>
|
||||
<string name="sub_setting_url">Optional URL</string>
|
||||
<string name="sub_setting_enable">啟用更新</string>
|
||||
<string name="sub_auto_update">啟用自動更新</string>
|
||||
<string name="title_sub_update">更新訂閱</string>
|
||||
<string name="title_ping_all_server">偵測所有組態 Tcping</string>
|
||||
<string name="title_real_ping_all_server">偵測所有組態真延遲</string>
|
||||
|
||||
@@ -76,8 +76,11 @@
|
||||
|
||||
<string-array name="streamsecurity_alpn" translatable="false">
|
||||
<item></item>
|
||||
<item>h3</item>
|
||||
<item>h2</item>
|
||||
<item>http/1.1</item>
|
||||
<item>h3,h2,http/1.1</item>
|
||||
<item>h3,h2</item>
|
||||
<item>h2,http/1.1</item>
|
||||
</string-array>
|
||||
|
||||
@@ -179,4 +182,10 @@
|
||||
<item>fa</item>
|
||||
<item>ar</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="mux_xudp_quic_value" translatable="false">
|
||||
<item>reject</item>
|
||||
<item>allow</item>
|
||||
<item>skip</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -15,4 +15,5 @@
|
||||
<color name="colorAccent">#000000</color>
|
||||
<color name="colorBg">#FFFFFF</color>
|
||||
<color name="colorText">#000000</color>
|
||||
<color name="colorMainTestBg">#F0F1F6</color>
|
||||
</resources>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<string name="menu_item_import_config_manually_ss">Type manually[Shadowsocks]</string>
|
||||
<string name="menu_item_import_config_manually_socks">Type manually[Socks]</string>
|
||||
<string name="menu_item_import_config_manually_trojan">Type manually[Trojan]</string>
|
||||
<string name="menu_item_import_config_manually_wireguard">Type manually[Wireguard]</string>
|
||||
<string name="menu_item_import_config_custom">Custom config</string>
|
||||
<string name="menu_item_import_config_custom_clipboard">Import custom config from Clipboard</string>
|
||||
<string name="menu_item_import_config_custom_local">Import custom config from locally</string>
|
||||
@@ -64,6 +65,10 @@
|
||||
<string name="server_lab_public_key" translatable="false">PublicKey</string>
|
||||
<string name="server_lab_short_id" translatable="false">ShortId</string>
|
||||
<string name="server_lab_spider_x" translatable="false">SpiderX</string>
|
||||
<string name="server_lab_secret_key" translatable="false">SecretKey</string>
|
||||
<string name="server_lab_reserved">Reserved(Optional)</string>
|
||||
<string name="server_lab_local_address">Local address (optional IPv4/IPv6, separated by commas)</string>
|
||||
<string name="server_lab_local_mtu">Mtu(optional, default 1420)</string>
|
||||
<string name="toast_success">Success</string>
|
||||
<string name="toast_failure">Failure</string>
|
||||
<string name="toast_none_data">There is nothing</string>
|
||||
@@ -103,7 +108,15 @@
|
||||
<string name="summary_pref_per_app_proxy">General: Checked App is proxy, unchecked direct connection; \nbypass mode: checked app directly connected, unchecked proxy. \nThe option to automatically select the proxy application in the menu</string>
|
||||
|
||||
<string name="title_pref_mux_enabled">Enable Mux</string>
|
||||
<string name="summary_pref_mux_enabled">Enable maybe speed up network and switch network maybe flash</string>
|
||||
<string name="summary_pref_mux_enabled">Faster, but it may cause unstable connectivity\ncustomize how to handle TCP, UDP and QUIC below</string>
|
||||
<string name="title_pref_mux_concurency">TCP connections(range -1 to 1024)</string>
|
||||
<string name="title_pref_mux_xudp_concurency">XUDP connections(range -1 to 1024)</string>
|
||||
<string name="title_pref_mux_xudp_quic">Handling of QUIC in mux tunnel</string>
|
||||
<string-array name="mux_xudp_quic_entries">
|
||||
<item>reject</item>
|
||||
<item>allow</item>
|
||||
<item>skip</item>
|
||||
</string-array>
|
||||
|
||||
<string name="title_pref_speed_enabled">Enable speed display</string>
|
||||
<string name="summary_pref_speed_enabled">Display current speed in the notification.\nNotification icon would change based on
|
||||
@@ -161,10 +174,15 @@
|
||||
<string name="summary_pref_feedback">Feedback enhancements or bugs to GitHub</string>
|
||||
<string name="summary_pref_tg_group">Join Telegram Group</string>
|
||||
<string name="toast_tg_app_not_found">Telegram app not found</string>
|
||||
<string name="title_privacy_policy">Privacy policy</string>
|
||||
|
||||
<string name="title_pref_promotion">Promotion</string>
|
||||
<string name="summary_pref_promotion">Promotion,click for details(Donation can be removed)</string>
|
||||
|
||||
<string name="title_pref_auto_update_subscription">Automatic update subscriptions</string>
|
||||
<string name="summary_pref_auto_update_subscription">Update your subscriptions automatically with an interval in background. Depending on the device, this feature may not always work</string>
|
||||
<string name="title_pref_auto_update_interval">Auto Update Interval (Minutes, Min value 15)</string>
|
||||
|
||||
<string name="title_core_loglevel">Log Level</string>
|
||||
<string name="title_mode">Mode</string>
|
||||
<string name="title_mode_help">Click me for more help</string>
|
||||
@@ -182,7 +200,8 @@
|
||||
<string name="title_sub_setting">Subscription group setting</string>
|
||||
<string name="sub_setting_remarks">remarks</string>
|
||||
<string name="sub_setting_url">Optional URL</string>
|
||||
<string name="sub_setting_enable">enable update</string>
|
||||
<string name="sub_setting_enable">Enable update</string>
|
||||
<string name="sub_auto_update">Enable automatic update</string>
|
||||
<string name="title_sub_update">Update subscription</string>
|
||||
<string name="title_ping_all_server">Tcping all configuration</string>
|
||||
<string name="title_real_ping_all_server">Real delay all configuration</string>
|
||||
|
||||
@@ -1,15 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<CheckBoxPreference
|
||||
android:key="pref_speed_enabled"
|
||||
android:summary="@string/summary_pref_speed_enabled"
|
||||
android:title="@string/title_pref_speed_enabled" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="pref_sniffing_enabled"
|
||||
android:summary="@string/summary_pref_sniffing_enabled"
|
||||
android:title="@string/title_pref_sniffing_enabled" />
|
||||
android:defaultValue="true"
|
||||
android:key="pref_sniffing_enabled"
|
||||
android:summary="@string/summary_pref_sniffing_enabled"
|
||||
android:title="@string/title_pref_sniffing_enabled" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="pref_mux_enabled"
|
||||
android:summary="@string/summary_pref_mux_enabled"
|
||||
android:title="@string/title_pref_mux_enabled" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_mux_concurency"
|
||||
android:summary="8"
|
||||
android:inputType="number"
|
||||
android:title="@string/title_pref_mux_concurency" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_mux_xudp_concurency"
|
||||
android:summary="8"
|
||||
android:inputType="number"
|
||||
android:title="@string/title_pref_mux_xudp_concurency" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="reject"
|
||||
android:entries="@array/mux_xudp_quic_entries"
|
||||
android:entryValues="@array/mux_xudp_quic_value"
|
||||
android:key="pref_mux_xudp_quic"
|
||||
android:summary="%s"
|
||||
android:title="@string/title_pref_mux_xudp_quic" />
|
||||
|
||||
<PreferenceCategory android:title="@string/title_vpn_settings">
|
||||
<CheckBoxPreference
|
||||
@@ -17,30 +38,26 @@
|
||||
android:summary="@string/summary_pref_per_app_proxy"
|
||||
android:title="@string/title_pref_per_app_proxy" />
|
||||
|
||||
<!--<CheckBoxPreference-->
|
||||
<!--android:key="pref_mux_enabled"-->
|
||||
<!--android:summary="@string/summary_pref_mux_enabled"-->
|
||||
<!--android:title="@string/title_pref_mux_enabled" />-->
|
||||
<CheckBoxPreference
|
||||
android:key="pref_local_dns_enabled"
|
||||
android:summary="@string/summary_pref_local_dns_enabled"
|
||||
android:title="@string/title_pref_local_dns_enabled" />
|
||||
android:key="pref_local_dns_enabled"
|
||||
android:summary="@string/summary_pref_local_dns_enabled"
|
||||
android:title="@string/title_pref_local_dns_enabled" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="pref_fake_dns_enabled"
|
||||
android:summary="@string/summary_pref_fake_dns_enabled"
|
||||
android:title="@string/title_pref_fake_dns_enabled" />
|
||||
android:key="pref_fake_dns_enabled"
|
||||
android:summary="@string/summary_pref_fake_dns_enabled"
|
||||
android:title="@string/title_pref_fake_dns_enabled" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_local_dns_port"
|
||||
android:summary="10853"
|
||||
android:inputType="number"
|
||||
android:title="@string/title_pref_local_dns_port" />
|
||||
android:key="pref_local_dns_port"
|
||||
android:summary="10853"
|
||||
android:inputType="number"
|
||||
android:title="@string/title_pref_local_dns_port" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_vpn_dns"
|
||||
android:summary="@string/summary_pref_remote_dns"
|
||||
android:title="@string/title_pref_vpn_dns" />
|
||||
android:key="pref_vpn_dns"
|
||||
android:summary="@string/summary_pref_remote_dns"
|
||||
android:title="@string/title_pref_vpn_dns" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/title_pref_routing">
|
||||
@@ -67,6 +84,44 @@
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/title_sub_setting">
|
||||
<CheckBoxPreference
|
||||
android:key="pref_auto_update_subscription"
|
||||
android:summary="@string/summary_pref_auto_update_subscription"
|
||||
android:title="@string/title_pref_auto_update_subscription" />
|
||||
<EditTextPreference
|
||||
android:key="pref_auto_update_interval"
|
||||
android:summary="1440"
|
||||
android:inputType="number"
|
||||
android:title="@string/title_pref_auto_update_interval" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/title_ui_settings">
|
||||
<CheckBoxPreference
|
||||
android:key="pref_speed_enabled"
|
||||
android:summary="@string/summary_pref_speed_enabled"
|
||||
android:title="@string/title_pref_speed_enabled" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="pref_confirm_remove"
|
||||
android:summary="@string/summary_pref_confirm_remove"
|
||||
android:title="@string/title_pref_confirm_remove" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="pref_start_scan_immediate"
|
||||
android:summary="@string/summary_pref_start_scan_immediate"
|
||||
android:title="@string/title_pref_start_scan_immediate" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="auto"
|
||||
android:entries="@array/language_select"
|
||||
android:entryValues="@array/language_select_value"
|
||||
android:key="pref_language"
|
||||
android:summary="%s"
|
||||
android:title="@string/title_language" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/title_advanced">
|
||||
|
||||
<CheckBoxPreference
|
||||
@@ -104,9 +159,9 @@
|
||||
android:title="@string/title_pref_remote_dns" />
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_domestic_dns"
|
||||
android:summary="@string/summary_pref_domestic_dns"
|
||||
android:title="@string/title_pref_domestic_dns" />
|
||||
android:key="pref_domestic_dns"
|
||||
android:summary="@string/summary_pref_domestic_dns"
|
||||
android:title="@string/title_pref_domestic_dns" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="warning"
|
||||
@@ -117,34 +172,12 @@
|
||||
android:title="@string/title_core_loglevel" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="VPN"
|
||||
android:entries="@array/mode_entries"
|
||||
android:entryValues="@array/mode_value"
|
||||
android:key="pref_mode"
|
||||
android:summary="%s"
|
||||
android:title="@string/title_mode" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/title_ui_settings">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="pref_confirm_remove"
|
||||
android:summary="@string/summary_pref_confirm_remove"
|
||||
android:title="@string/title_pref_confirm_remove" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="pref_start_scan_immediate"
|
||||
android:summary="@string/summary_pref_start_scan_immediate"
|
||||
android:title="@string/title_pref_start_scan_immediate" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="auto"
|
||||
android:entries="@array/language_select"
|
||||
android:entryValues="@array/language_select_value"
|
||||
android:key="pref_language"
|
||||
android:defaultValue="VPN"
|
||||
android:entries="@array/mode_entries"
|
||||
android:entryValues="@array/mode_value"
|
||||
android:key="pref_mode"
|
||||
android:summary="%s"
|
||||
android:title="@string/title_language" />
|
||||
android:title="@string/title_mode" />
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
buildToolsVer=33.0.2
|
||||
compileSdkVer=33
|
||||
targetSdkVer=33
|
||||
buildToolsVer=34.0.0
|
||||
compileSdkVer=34
|
||||
targetSdkVer=34
|
||||
kotlin.incremental=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
Reference in New Issue
Block a user