From 0b065c745db362d1df716ccdbc168634684dd374 Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Sat, 21 Sep 2024 15:36:45 +0800
Subject: [PATCH] Refactor routing function
---
V2rayNG/app/src/main/AndroidManifest.xml | 6 +-
.../app/src/main/assets/custom_routing_black | 73 +++++++
.../app/src/main/assets/custom_routing_global | 34 +++
.../app/src/main/assets/custom_routing_white | 81 +++++++
.../kotlin/com/v2ray/ang/AngApplication.kt | 3 +
.../main/kotlin/com/v2ray/ang/AppConfig.kt | 6 +-
.../kotlin/com/v2ray/ang/dto/ERoutingMode.kt | 9 -
.../kotlin/com/v2ray/ang/dto/RulesetItem.kt | 12 ++
.../com/v2ray/ang/service/V2RayVpnService.kt | 10 +-
.../kotlin/com/v2ray/ang/ui/MainActivity.kt | 5 +-
.../com/v2ray/ang/ui/RoutingEditActivity.kt | 127 +++++++++++
.../v2ray/ang/ui/RoutingSettingActivity.kt | 101 +++++++++
.../ang/ui/RoutingSettingRecyclerAdapter.kt | 51 +++++
.../v2ray/ang/ui/RoutingSettingsActivity.kt | 35 ----
.../v2ray/ang/ui/RoutingSettingsFragment.kt | 170 ---------------
.../com/v2ray/ang/ui/SettingsActivity.kt | 8 -
.../com/v2ray/ang/util/AngConfigManager.kt | 1 -
.../kotlin/com/v2ray/ang/util/MmkvManager.kt | 15 ++
.../com/v2ray/ang/util/SettingsManager.kt | 73 +++++++
.../com/v2ray/ang/util/V2rayConfigUtil.kt | 198 +++---------------
.../v2ray/ang/viewmodel/SettingsViewModel.kt | 4 -
.../res/drawable-night/ic_routing_24dp.xml | 9 +
.../src/main/res/drawable/ic_routing_24dp.xml | 9 +
.../main/res/layout/activity_routing_edit.xml | 174 +++++++++++++++
.../res/layout/activity_routing_setting.xml | 70 +++++++
.../res/layout/activity_routing_settings.xml | 16 --
.../src/main/res/layout/activity_sub_edit.xml | 3 +-
.../res/layout/fragment_routing_settings.xml | 39 ----
.../layout/item_recycler_routing_setting.xml | 104 +++++++++
.../res/layout/item_recycler_sub_setting.xml | 2 +-
V2rayNG/app/src/main/res/menu/menu_drawer.xml | 6 +-
.../app/src/main/res/menu/menu_routing.xml | 31 ---
.../main/res/menu/menu_routing_setting.xml | 18 ++
.../app/src/main/res/values-ar/strings.xml | 27 +--
.../app/src/main/res/values-bn/strings.xml | 27 +--
.../app/src/main/res/values-fa/strings.xml | 27 +--
.../app/src/main/res/values-ru/strings.xml | 27 +--
.../app/src/main/res/values-vi/strings.xml | 27 +--
.../src/main/res/values-zh-rCN/strings.xml | 30 +--
.../src/main/res/values-zh-rTW/strings.xml | 29 +--
V2rayNG/app/src/main/res/values/arrays.xml | 14 +-
V2rayNG/app/src/main/res/values/dimens.xml | 2 +-
V2rayNG/app/src/main/res/values/strings.xml | 37 ++--
.../app/src/main/res/xml/pref_settings.xml | 24 ---
44 files changed, 1059 insertions(+), 715 deletions(-)
create mode 100644 V2rayNG/app/src/main/assets/custom_routing_black
create mode 100644 V2rayNG/app/src/main/assets/custom_routing_global
create mode 100644 V2rayNG/app/src/main/assets/custom_routing_white
delete mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt
create mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/RulesetItem.kt
create mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingEditActivity.kt
create mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt
create mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingRecyclerAdapter.kt
delete mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt
delete mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt
create mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt
create mode 100644 V2rayNG/app/src/main/res/drawable-night/ic_routing_24dp.xml
create mode 100644 V2rayNG/app/src/main/res/drawable/ic_routing_24dp.xml
create mode 100644 V2rayNG/app/src/main/res/layout/activity_routing_edit.xml
create mode 100644 V2rayNG/app/src/main/res/layout/activity_routing_setting.xml
delete mode 100644 V2rayNG/app/src/main/res/layout/activity_routing_settings.xml
delete mode 100644 V2rayNG/app/src/main/res/layout/fragment_routing_settings.xml
create mode 100644 V2rayNG/app/src/main/res/layout/item_recycler_routing_setting.xml
delete mode 100644 V2rayNG/app/src/main/res/menu/menu_routing.xml
create mode 100644 V2rayNG/app/src/main/res/menu/menu_routing_setting.xml
diff --git a/V2rayNG/app/src/main/AndroidManifest.xml b/V2rayNG/app/src/main/AndroidManifest.xml
index 6021d476..bae5335a 100644
--- a/V2rayNG/app/src/main/AndroidManifest.xml
+++ b/V2rayNG/app/src/main/AndroidManifest.xml
@@ -98,8 +98,10 @@
android:name=".ui.LogcatActivity" />
+ android:name=".ui.RoutingSettingActivity" />
+
diff --git a/V2rayNG/app/src/main/assets/custom_routing_black b/V2rayNG/app/src/main/assets/custom_routing_black
new file mode 100644
index 00000000..e394a495
--- /dev/null
+++ b/V2rayNG/app/src/main/assets/custom_routing_black
@@ -0,0 +1,73 @@
+[
+ {
+ "remarks": "绕过bittorrent",
+ "outboundTag": "direct",
+ "protocol": [
+ "bittorrent"
+ ]
+ },
+ {
+ "remarks": "Google cn",
+ "outboundTag": "proxy",
+ "domain": [
+ "domain:googleapis.cn",
+ "domain:gstatic.com"
+ ]
+ },
+ {
+ "remarks": "阻断udp443",
+ "outboundTag": "block",
+ "port": "443",
+ "network": "udp"
+ },
+ {
+ "remarks": "阻断广告",
+ "outboundTag": "block",
+ "domain": [
+ "geosite:category-ads-all"
+ ]
+ },
+ {
+ "remarks": "绕过局域网域名",
+ "outboundTag": "direct",
+ "domain": [
+ "geosite:private"
+ ]
+ },
+ {
+ "remarks": "绕过局域网IP",
+ "outboundTag": "direct",
+ "ip": [
+ "geoip:private"
+ ]
+ },
+ {
+ "remarks": "代理GFW",
+ "outboundTag": "proxy",
+ "domain": [
+ "geosite:gfw",
+ "geosite:greatfire"
+ ]
+ },
+ {
+ "remarks": "代理Google等",
+ "outboundTag": "proxy",
+ "ip": [
+ "1.0.0.1",
+ "1.1.1.1",
+ "8.8.8.8",
+ "8.8.4.4",
+ "geoip:facebook",
+ "geoip:fastly",
+ "geoip:google",
+ "geoip:netflix",
+ "geoip:telegram",
+ "geoip:twitter"
+ ]
+ },
+ {
+ "remarks": "最终直连",
+ "port": "0-65535",
+ "outboundTag": "direct"
+ }
+]
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/assets/custom_routing_global b/V2rayNG/app/src/main/assets/custom_routing_global
new file mode 100644
index 00000000..75e6051b
--- /dev/null
+++ b/V2rayNG/app/src/main/assets/custom_routing_global
@@ -0,0 +1,34 @@
+[
+ {
+ "remarks": "阻断udp443",
+ "outboundTag": "block",
+ "port": "443",
+ "network": "udp"
+ },
+ {
+ "remarks": "阻断广告",
+ "outboundTag": "block",
+ "domain": [
+ "geosite:category-ads-all"
+ ]
+ },
+ {
+ "remarks": "绕过局域网域名",
+ "outboundTag": "direct",
+ "domain": [
+ "geosite:private"
+ ]
+ },
+ {
+ "remarks": "绕过局域网IP",
+ "outboundTag": "direct",
+ "ip": [
+ "geoip:private"
+ ]
+ },
+ {
+ "remarks": "最终代理",
+ "port": "0-65535",
+ "outboundTag": "proxy"
+ }
+]
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/assets/custom_routing_white b/V2rayNG/app/src/main/assets/custom_routing_white
new file mode 100644
index 00000000..008120aa
--- /dev/null
+++ b/V2rayNG/app/src/main/assets/custom_routing_white
@@ -0,0 +1,81 @@
+[
+ {
+ "remarks": "Google cn",
+ "outboundTag": "proxy",
+ "domain": [
+ "domain:googleapis.cn",
+ "domain:gstatic.com"
+ ]
+ },
+ {
+ "remarks": "阻断udp443",
+ "outboundTag": "block",
+ "port": "443",
+ "network": "udp"
+ },
+ {
+ "remarks": "阻断广告",
+ "outboundTag": "block",
+ "domain": [
+ "geosite:category-ads-all"
+ ]
+ },
+ {
+ "remarks": "绕过局域网域名",
+ "outboundTag": "direct",
+ "domain": [
+ "geosite:private"
+ ]
+ },
+ {
+ "remarks": "绕过局域网IP",
+ "outboundTag": "direct",
+ "ip": [
+ "geoip:private"
+ ]
+ },
+ {
+ "remarks": "绕过中国域名",
+ "outboundTag": "direct",
+ "domain": [
+ "domain:dns.alidns.com",
+ "domain:doh.pub",
+ "domain:dot.pub",
+ "domain:doh.360.cn",
+ "domain:dot.360.cn",
+ "geosite:cn",
+ "geosite:geolocation-cn"
+ ]
+ },
+ {
+ "remarks": "绕过中国IP",
+ "outboundTag": "direct",
+ "ip": [
+ "223.5.5.5/32",
+ "223.6.6.6/32",
+ "2400:3200::1/128",
+ "2400:3200:baba::1/128",
+ "119.29.29.29/32",
+ "1.12.12.12/32",
+ "120.53.53.53/32",
+ "2402:4e00::/128",
+ "2402:4e00:1::/128",
+ "180.76.76.76/32",
+ "2400:da00::6666/128",
+ "114.114.114.114/32",
+ "114.114.115.115/32",
+ "180.184.1.1/32",
+ "180.184.2.2/32",
+ "101.226.4.6/32",
+ "218.30.118.6/32",
+ "123.125.81.6/32",
+ "140.207.198.6/32",
+ "geoip:cn"
+ ]
+ },
+ {
+ "remarks": "最终代理",
+ "port": "0-65535",
+ "outboundTag": "proxy"
+ }
+]
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt
index a07e7f99..37b40f6e 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt
@@ -5,6 +5,7 @@ import androidx.multidex.MultiDexApplication
import androidx.work.Configuration
import androidx.work.WorkManager
import com.tencent.mmkv.MMKV
+import com.v2ray.ang.util.SettingsManager
import com.v2ray.ang.util.Utils
class AngApplication : MultiDexApplication() {
@@ -38,5 +39,7 @@ class AngApplication : MultiDexApplication() {
Utils.setNightMode(application)
// Initialize WorkManager with the custom configuration
WorkManager.initialize(this, workManagerConfiguration)
+
+ SettingsManager.initRoutingRulesets(this)
}
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
index b564a41b..480b331b 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
@@ -25,11 +25,7 @@ object AppConfig {
const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port"
const val PREF_VPN_DNS = "pref_vpn_dns"
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
- const val PREF_ROUTING_MODE = "pref_routing_mode"
- const val PREF_V2RAY_ROUTING_AGENT = "pref_v2ray_routing_agent"
- const val PREF_V2RAY_ROUTING_DIRECT = "pref_v2ray_routing_direct"
- const val PREF_V2RAY_ROUTING_BLOCKED = "pref_v2ray_routing_blocked"
- const val PREF_ROUTING_CUSTOM = "pref_routing_custom"
+ const val PREF_ROUTING_RULESET = "pref_routing_ruleset"
const val PREF_MUX_ENABLED = "pref_mux_enabled"
const val PREF_MUX_CONCURRENCY = "pref_mux_concurrency"
const val PREF_MUX_XUDP_CONCURRENCY = "pref_mux_xudp_concurrency"
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt
deleted file mode 100644
index 8d882ed6..00000000
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.v2ray.ang.dto
-
-enum class ERoutingMode(val value: String) {
- GLOBAL_PROXY("0"),
- BYPASS_LAN("1"),
- BYPASS_MAINLAND("2"),
- BYPASS_LAN_MAINLAND("3"),
- GLOBAL_DIRECT("4");
-}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/RulesetItem.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/RulesetItem.kt
new file mode 100644
index 00000000..42bf5edb
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/RulesetItem.kt
@@ -0,0 +1,12 @@
+package com.v2ray.ang.dto
+
+data class RulesetItem(
+ var remarks: String? = "",
+ var ip: List? = null,
+ var domain: List? = null,
+ var outboundTag: String = "",
+ var port: String? = null,
+ var network: String? = null,
+ var protocol: List? = null,
+ var enabled: Boolean = true,
+)
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt
index c53eb4d8..4c93bdc1 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt
@@ -18,9 +18,9 @@ import android.util.Log
import androidx.annotation.RequiresApi
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
-import com.v2ray.ang.dto.ERoutingMode
import com.v2ray.ang.util.MmkvManager.settingsStorage
import com.v2ray.ang.util.MyContextWrapper
+import com.v2ray.ang.util.SettingsManager
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -115,13 +115,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
val builder = Builder()
//val enableLocalDns = defaultDPreference.getPrefBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
- val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE)
- ?: ERoutingMode.BYPASS_LAN_MAINLAND.value
-
builder.setMtu(VPN_MTU)
builder.addAddress(PRIVATE_VLAN4_CLIENT, 30)
//builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
- if (routingMode == ERoutingMode.BYPASS_LAN.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
+ val bypassLan = SettingsManager.routingRulesetsBypassLan()
+ if (bypassLan) {
resources.getStringArray(R.array.bypass_private_ip_address).forEach {
val addr = it.split('/')
builder.addRoute(addr[0], addr[1].toInt())
@@ -132,7 +130,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) == true) {
builder.addAddress(PRIVATE_VLAN6_CLIENT, 126)
- if (routingMode == ERoutingMode.BYPASS_LAN.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
+ if (bypassLan) {
builder.addRoute("2000::", 3) //currently only 1/8 of total ipV6 is in use
} else {
builder.addRoute("::", 0)
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt
index c27a8839..ffef8f4a 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt
@@ -707,10 +707,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
)
}
- R.id.user_asset_setting -> {
- startActivity(Intent(this, UserAssetActivity::class.java))
+ R.id.routing_setting -> {
+ requestSubSettingActivity.launch(Intent(this, RoutingSettingActivity::class.java))
}
+
R.id.promotion -> {
Utils.openUri(this, "${Utils.decode(AppConfig.PromotionUrl)}?t=${System.currentTimeMillis()}")
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingEditActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingEditActivity.kt
new file mode 100644
index 00000000..f7f20761
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingEditActivity.kt
@@ -0,0 +1,127 @@
+package com.v2ray.ang.ui
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
+import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.lifecycleScope
+import com.google.gson.Gson
+import com.v2ray.ang.R
+import com.v2ray.ang.databinding.ActivityRoutingEditBinding
+import com.v2ray.ang.dto.RulesetItem
+import com.v2ray.ang.extension.toast
+import com.v2ray.ang.util.SettingsManager
+import com.v2ray.ang.util.Utils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class RoutingEditActivity : BaseActivity() {
+ private val binding by lazy { ActivityRoutingEditBinding.inflate(layoutInflater) }
+ private val position by lazy { intent.getIntExtra("position", -1) }
+
+ private val outbound_tag: Array by lazy {
+ resources.getStringArray(R.array.outbound_tag)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ title = getString(R.string.routing_settings_rule_title)
+
+ val rulesetItem = SettingsManager.getRoutingRuleset(position)
+ if (rulesetItem != null) {
+ bindingServer(rulesetItem)
+ } else {
+ clearServer()
+ }
+ }
+
+ private fun bindingServer(rulesetItem: RulesetItem): Boolean {
+ binding.etRemarks.text = Utils.getEditable(rulesetItem.remarks)
+ binding.etDomain.text = Utils.getEditable(rulesetItem.domain?.joinToString())
+ binding.etIp.text = Utils.getEditable(rulesetItem.ip?.joinToString())
+ binding.etPort.text = Utils.getEditable(rulesetItem.port)
+ binding.etProtocol.text = Utils.getEditable(rulesetItem.protocol?.joinToString())
+ binding.etNetwork.text = Utils.getEditable(rulesetItem.network)
+ val outbound = Utils.arrayFind(outbound_tag, rulesetItem.outboundTag)
+ binding.spOutboundTag.setSelection(outbound)
+
+ return true
+ }
+
+ private fun clearServer(): Boolean {
+ binding.etRemarks.text = null
+ binding.spOutboundTag.setSelection(0)
+ return true
+ }
+
+ private fun saveServer(): Boolean {
+ val rulesetItem = SettingsManager.getRoutingRuleset(position) ?: RulesetItem()
+
+ rulesetItem.remarks = binding.etRemarks.text.toString()
+ binding.etDomain.text.toString().let { rulesetItem.domain = if (it.isEmpty()) null else it.split(',') }
+ binding.etIp.text.toString().let { rulesetItem.ip = if (it.isEmpty()) null else it.split(',') }
+ binding.etProtocol.text.toString().let { rulesetItem.protocol = if (it.isEmpty()) null else it.split(',') }
+ binding.etPort.text.toString().let { rulesetItem.port = it.ifEmpty { null } }
+ binding.etNetwork.text.toString().let { rulesetItem.network = it.ifEmpty { null } }
+ rulesetItem.outboundTag = outbound_tag[binding.spOutboundTag.selectedItemPosition]
+
+ if (TextUtils.isEmpty(rulesetItem.remarks)) {
+ toast(R.string.sub_setting_remarks)
+ return false
+ }
+
+ Log.d("====", Gson().toJson(rulesetItem))
+ SettingsManager.saveRoutingRuleset(position, rulesetItem)
+ toast(R.string.toast_success)
+ finish()
+ return true
+ }
+
+ private fun deleteServer(): Boolean {
+ if (position >= 0) {
+ AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ lifecycleScope.launch(Dispatchers.IO) {
+ SettingsManager.removeRoutingRuleset(position)
+ launch(Dispatchers.Main) {
+ finish()
+ }
+ }
+ }
+ .setNegativeButton(android.R.string.no) { _, _ ->
+ // do nothing
+ }
+ .show()
+ }
+ return true
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.action_server, menu)
+ val del_config = menu.findItem(R.id.del_config)
+
+ if (position < 0) {
+ del_config?.isVisible = false
+ }
+
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
+ R.id.del_config -> {
+ deleteServer()
+ true
+ }
+
+ R.id.save_config -> {
+ saveServer()
+ true
+ }
+
+ else -> super.onOptionsItemSelected(item)
+ }
+
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt
new file mode 100644
index 00000000..22eb5de3
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt
@@ -0,0 +1,101 @@
+package com.v2ray.ang.ui
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.AdapterView
+import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.v2ray.ang.AppConfig
+import com.v2ray.ang.R
+import com.v2ray.ang.databinding.ActivityRoutingSettingBinding
+import com.v2ray.ang.dto.RulesetItem
+import com.v2ray.ang.extension.toast
+import com.v2ray.ang.util.MmkvManager
+import com.v2ray.ang.util.MmkvManager.settingsStorage
+import com.v2ray.ang.util.SettingsManager
+import com.v2ray.ang.util.Utils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class RoutingSettingActivity : BaseActivity() {
+ private val binding by lazy { ActivityRoutingSettingBinding.inflate(layoutInflater) }
+
+ var rulesets: MutableList = mutableListOf()
+ private val adapter by lazy { RoutingSettingRecyclerAdapter(this) }
+ private val routing_domain_strategy: Array by lazy {
+ resources.getStringArray(R.array.routing_domain_strategy)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+
+ title = getString(R.string.routing_settings_title)
+
+ binding.recyclerView.setHasFixedSize(true)
+ binding.recyclerView.layoutManager = LinearLayoutManager(this)
+ binding.recyclerView.adapter = adapter
+
+ val found = Utils.arrayFind(routing_domain_strategy, settingsStorage?.decodeString(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY) ?: "")
+ found.let { binding.spDomainStrategy.setSelection(if (it >= 0) it else 0) }
+ binding.spDomainStrategy.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+ }
+
+ override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
+ settingsStorage.encode(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY, routing_domain_strategy[position])
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ refreshData()
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_routing_setting, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
+ R.id.add_rule -> {
+ startActivity(Intent(this, RoutingEditActivity::class.java))
+ true
+ }
+
+ R.id.user_asset_setting -> {
+ startActivity(Intent(this, UserAssetActivity::class.java))
+ true
+ }
+
+ R.id.import_rulesets -> {
+ AlertDialog.Builder(this).setMessage(R.string.routing_settings_import_rulesets_tip)
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ lifecycleScope.launch(Dispatchers.IO) {
+ SettingsManager.resetRoutingRulesets(this@RoutingSettingActivity)
+ launch(Dispatchers.Main) {
+ refreshData()
+ toast(R.string.toast_success)
+ }
+ }
+ }
+ .setNegativeButton(android.R.string.no) { _, _ ->
+ //do noting
+ }
+ .show()
+ true
+ }
+
+ else -> super.onOptionsItemSelected(item)
+ }
+
+ private fun refreshData() {
+ rulesets = MmkvManager.decodeRoutingRulesets() ?: mutableListOf()
+ adapter.notifyDataSetChanged()
+ }
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingRecyclerAdapter.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingRecyclerAdapter.kt
new file mode 100644
index 00000000..aecf7c5a
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingRecyclerAdapter.kt
@@ -0,0 +1,51 @@
+package com.v2ray.ang.ui
+
+import android.content.Intent
+import android.graphics.Color
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.v2ray.ang.databinding.ItemRecyclerRoutingSettingBinding
+import com.v2ray.ang.util.SettingsManager
+
+class RoutingSettingRecyclerAdapter(val activity: RoutingSettingActivity) :
+ RecyclerView.Adapter() {
+
+ private var mActivity: RoutingSettingActivity = activity
+ override fun getItemCount() = mActivity.rulesets.size
+
+ override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
+ val ruleset = mActivity.rulesets[position]
+
+ holder.itemRoutingSettingBinding.remarks.text = ruleset.remarks
+ holder.itemRoutingSettingBinding.domainIp.text = (ruleset.domain ?: ruleset.ip ?: ruleset.port)?.toString()
+ holder.itemRoutingSettingBinding.outboundTag.text = ruleset.outboundTag
+ holder.itemRoutingSettingBinding.chkEnable.isChecked = ruleset.enabled
+ holder.itemView.setBackgroundColor(Color.TRANSPARENT)
+
+ holder.itemRoutingSettingBinding.layoutEdit.setOnClickListener {
+ mActivity.startActivity(
+ Intent(mActivity, RoutingEditActivity::class.java)
+ .putExtra("position", position)
+ )
+ }
+
+ holder.itemRoutingSettingBinding.chkEnable.setOnCheckedChangeListener { _, isChecked ->
+ ruleset.enabled = isChecked
+ SettingsManager.saveRoutingRuleset(position, ruleset)
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
+ return MainViewHolder(
+ ItemRecyclerRoutingSettingBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+ }
+
+ class MainViewHolder(val itemRoutingSettingBinding: ItemRecyclerRoutingSettingBinding) :
+ RecyclerView.ViewHolder(itemRoutingSettingBinding.root)
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt
deleted file mode 100644
index c8d84ab0..00000000
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.v2ray.ang.ui
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import com.google.android.material.tabs.TabLayoutMediator
-import com.v2ray.ang.AppConfig
-import com.v2ray.ang.R
-import com.v2ray.ang.databinding.ActivityRoutingSettingsBinding
-
-class RoutingSettingsActivity : BaseActivity() {
- private val binding by lazy { ActivityRoutingSettingsBinding.inflate(layoutInflater) }
-
- private val titles: Array by lazy {
- resources.getStringArray(R.array.routing_tag)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(binding.root)
-
- title = getString(R.string.title_pref_routing_custom)
-
- val fragments = ArrayList()
- fragments.add(RoutingSettingsFragment().newInstance(AppConfig.PREF_V2RAY_ROUTING_AGENT))
- fragments.add(RoutingSettingsFragment().newInstance(AppConfig.PREF_V2RAY_ROUTING_DIRECT))
- fragments.add(RoutingSettingsFragment().newInstance(AppConfig.PREF_V2RAY_ROUTING_BLOCKED))
-
- val adapter = FragmentAdapter(this, fragments)
- binding.viewpager.adapter = adapter
- //tablayout.setTabTextColors(Color.BLACK, Color.RED)
- TabLayoutMediator(binding.tablayout, binding.viewpager) { tab, position ->
- tab.text = titles[position]
- }.attach()
- }
-}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt
deleted file mode 100644
index 429ab3fb..00000000
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-package com.v2ray.ang.ui
-
-import android.Manifest
-import android.content.Intent
-import android.os.Bundle
-import android.text.TextUtils
-import android.view.LayoutInflater
-import android.view.Menu
-import android.view.MenuInflater
-import android.view.MenuItem
-import android.view.View
-import android.view.ViewGroup
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AppCompatActivity.RESULT_OK
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.lifecycleScope
-import com.tbruyelle.rxpermissions3.RxPermissions
-import com.v2ray.ang.AppConfig
-import com.v2ray.ang.R
-import com.v2ray.ang.databinding.FragmentRoutingSettingsBinding
-import com.v2ray.ang.extension.toast
-import com.v2ray.ang.extension.v2RayApplication
-import com.v2ray.ang.util.MmkvManager
-import com.v2ray.ang.util.MmkvManager.settingsStorage
-import com.v2ray.ang.util.Utils
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-
-class RoutingSettingsFragment : Fragment() {
- private val binding by lazy { FragmentRoutingSettingsBinding.inflate(layoutInflater) }
-
- companion object {
- private const val routing_arg = "routing_arg"
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- // Inflate the layout for this fragment
- return binding.root// inflater.inflate(R.layout.fragment_routing_settings, container, false)
- }
-
- fun newInstance(arg: String): Fragment {
- val fragment = RoutingSettingsFragment()
- val bundle = Bundle()
- bundle.putString(routing_arg, arg)
- fragment.arguments = bundle
- return fragment
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- val content = settingsStorage?.getString(requireArguments().getString(routing_arg), "")
- binding.etRoutingContent.text = Utils.getEditable(content)
-
- setHasOptionsMenu(true)
- }
-
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- inflater.inflate(R.menu.menu_routing, menu)
- return super.onCreateOptionsMenu(menu, inflater)
- }
-
- override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
- R.id.save_routing -> {
- saveRouting()
- true
- }
-
- R.id.del_routing -> {
- binding.etRoutingContent.text = null
- true
- }
-
- R.id.scan_replace -> {
- scanQRcode(true)
- true
- }
-
- R.id.scan_append -> {
- scanQRcode(false)
- true
- }
-
- R.id.default_rules -> {
- setDefaultRules()
- true
- }
-
- else -> super.onOptionsItemSelected(item)
- }
-
- private fun saveRouting() {
- val content = binding.etRoutingContent.text.toString()
- settingsStorage?.encode(requireArguments().getString(routing_arg), content)
- activity?.toast(R.string.toast_success)
- }
-
- fun scanQRcode(forReplace: Boolean): Boolean {
-// try {
-// startActivityForResult(Intent("com.google.zxing.client.android.SCAN")
-// .addCategory(Intent.CATEGORY_DEFAULT)
-// .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), requestCode)
-// } catch (e: Exception) {
- RxPermissions(requireActivity())
- .request(Manifest.permission.CAMERA)
- .subscribe {
- if (it)
- if (forReplace)
- scanQRCodeForReplace.launch(Intent(activity, ScannerActivity::class.java))
- else
- scanQRCodeForAppend.launch(Intent(activity, ScannerActivity::class.java))
- else
- activity?.toast(R.string.toast_permission_denied)
- }
-// }
- return true
- }
-
- private val scanQRCodeForReplace = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
- if (it.resultCode == RESULT_OK) {
- val content = it.data?.getStringExtra("SCAN_RESULT")
- binding.etRoutingContent.text = Utils.getEditable(content)
- }
- }
-
- private val scanQRCodeForAppend = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
- if (it.resultCode == RESULT_OK) {
- val content = it.data?.getStringExtra("SCAN_RESULT")
- binding.etRoutingContent.text = Utils.getEditable("${binding.etRoutingContent.text},$content")
- }
- }
-
- fun setDefaultRules(): Boolean {
- var url = AppConfig.v2rayCustomRoutingListUrl
- var tag = ""
- when (requireArguments().getString(routing_arg)) {
- AppConfig.PREF_V2RAY_ROUTING_AGENT -> {
- tag = AppConfig.TAG_PROXY
- }
-
- AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
- tag = AppConfig.TAG_DIRECT
- }
-
- AppConfig.PREF_V2RAY_ROUTING_BLOCKED -> {
- tag = AppConfig.TAG_BLOCKED
- }
- }
- url += tag
-
- activity?.toast(R.string.msg_downloading_content)
- lifecycleScope.launch(Dispatchers.IO) {
- val content = Utils.getUrlContext(url, 5000)
- launch(Dispatchers.Main) {
- val routingList = if (TextUtils.isEmpty(content)) {
- Utils.readTextFromAssets(activity?.v2RayApplication, "custom_routing_$tag")
- } else {
- content
- }
- binding.etRoutingContent.text = Utils.getEditable(routingList)
- saveRouting()
- //toast(R.string.toast_success)
- }
- }
- return true
- }
-}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
index aa1a649e..818c211c 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
@@ -43,8 +43,6 @@ class SettingsActivity : BaseActivity() {
private val localDnsPort by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_PORT) }
private val vpnDns by lazy { findPreference(AppConfig.PREF_VPN_DNS) }
- private val routingCustom by lazy { findPreference(AppConfig.PREF_ROUTING_CUSTOM) }
-
private val mux by lazy { findPreference(AppConfig.PREF_MUX_ENABLED) }
private val muxConcurrency by lazy { findPreference(AppConfig.PREF_MUX_CONCURRENCY) }
private val muxXudpConcurrency by lazy { findPreference(AppConfig.PREF_MUX_XUDP_CONCURRENCY) }
@@ -88,11 +86,6 @@ class SettingsActivity : BaseActivity() {
true
}
- routingCustom?.setOnPreferenceClickListener {
- startActivity(Intent(activity, RoutingSettingsActivity::class.java))
- false
- }
-
mux?.setOnPreferenceChangeListener { _, newValue ->
updateMux(newValue as Boolean)
true
@@ -251,7 +244,6 @@ class SettingsActivity : BaseActivity() {
listOf(
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
- AppConfig.PREF_ROUTING_MODE,
AppConfig.PREF_MUX_XUDP_QUIC,
AppConfig.PREF_FRAGMENT_PACKETS,
AppConfig.PREF_LANGUAGE,
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt
index 87e3e74e..2286405d 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt
@@ -65,7 +65,6 @@ object AngConfigManager {
// AppConfig.PREF_HTTP_PORT,
// AppConfig.PREF_LOGLEVEL,
// AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
-// AppConfig.PREF_ROUTING_MODE,
// AppConfig.PREF_V2RAY_ROUTING_AGENT,
// AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
// AppConfig.PREF_V2RAY_ROUTING_DIRECT,
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
index 2215a2ba..5d7d5156 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
@@ -2,8 +2,10 @@ package com.v2ray.ang.util
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
+import com.v2ray.ang.AppConfig.PREF_ROUTING_RULESET
import com.v2ray.ang.dto.AssetUrlItem
import com.v2ray.ang.dto.ProfileItem
+import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.dto.ServerAffiliationInfo
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.SubscriptionItem
@@ -225,4 +227,17 @@ object MmkvManager {
}
return null
}
+
+ fun decodeRoutingRulesets(): MutableList? {
+ val ruleset = settingsStorage.decodeString(PREF_ROUTING_RULESET)
+ if (ruleset.isNullOrEmpty()) return null
+ return Gson().fromJson(ruleset, Array::class.java).toMutableList()
+ }
+
+ fun encodeRoutingRulesets(rulesetList: MutableList?) {
+ if (rulesetList.isNullOrEmpty())
+ settingsStorage.encode(PREF_ROUTING_RULESET, "")
+ else
+ settingsStorage.encode(PREF_ROUTING_RULESET, Gson().toJson(rulesetList))
+ }
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt
new file mode 100644
index 00000000..c05422bb
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt
@@ -0,0 +1,73 @@
+package com.v2ray.ang.util
+
+import android.content.Context
+import android.text.TextUtils
+import android.util.Log
+import com.google.gson.Gson
+import com.v2ray.ang.dto.RulesetItem
+
+object SettingsManager {
+
+ fun initRoutingRulesets(context: Context) {
+ Log.d("=====", "initRoutingRuleset")
+ val exist = MmkvManager.decodeRoutingRulesets()
+
+ if (exist.isNullOrEmpty()) {
+ Log.d("=====", "isNullOrEmpty")
+ val assets = Utils.readTextFromAssets(context, "custom_routing_white")
+ if (TextUtils.isEmpty(assets)) {
+ return
+ }
+
+ val rulesetList = Gson().fromJson(assets, Array::class.java).toMutableList()
+ Log.d("=====", "rulesetList==" + rulesetList.count())
+ MmkvManager.encodeRoutingRulesets(rulesetList)
+ }
+ }
+
+ fun resetRoutingRulesets(context: Context) {
+ MmkvManager.encodeRoutingRulesets(null)
+ initRoutingRulesets(context)
+ }
+
+ fun getRoutingRuleset(index: Int): RulesetItem? {
+ if (index < 0) return null
+
+ val rulesetList = MmkvManager.decodeRoutingRulesets()
+ if (rulesetList.isNullOrEmpty()) return null
+
+ return rulesetList[index]
+ }
+
+ fun saveRoutingRuleset(index: Int, ruleset: RulesetItem?) {
+ if (ruleset == null) return
+
+ val rulesetList = MmkvManager.decodeRoutingRulesets()
+ if (rulesetList.isNullOrEmpty()) return
+
+ if (index < 0 || index >= rulesetList.count()) {
+ rulesetList.add(ruleset)
+ } else {
+ rulesetList[index] = ruleset
+ }
+ MmkvManager.encodeRoutingRulesets(rulesetList)
+ }
+
+ fun removeRoutingRuleset(index: Int) {
+ if (index < 0) return
+
+ val rulesetList = MmkvManager.decodeRoutingRulesets()
+ if (rulesetList.isNullOrEmpty()) return
+
+ rulesetList.removeAt(index)
+ MmkvManager.encodeRoutingRulesets(rulesetList)
+ }
+
+ fun routingRulesetsBypassLan(): Boolean {
+ val rulesetItems = MmkvManager.decodeRoutingRulesets()
+ val exist = rulesetItems?.any { it.enabled && it.domain?.contains(":private") == true }
+ return exist == true
+ }
+
+
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
index 9d1f6226..a3387874 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
@@ -14,11 +14,12 @@ import com.v2ray.ang.AppConfig.TAG_PROXY
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V6
import com.v2ray.ang.dto.EConfigType
-import com.v2ray.ang.dto.ERoutingMode
+import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_NETWORK
import com.v2ray.ang.dto.V2rayConfig.Companion.HTTP
+import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean
import com.v2ray.ang.util.MmkvManager.settingsStorage
object V2rayConfigUtil {
@@ -40,7 +41,7 @@ object V2rayConfigUtil {
}
val result = getV2rayNonCustomConfig(context, config)
- //Log.d(ANG_PACKAGE, result.content)
+ Log.d(ANG_PACKAGE, result.content)
return result
} catch (e: Exception) {
e.printStackTrace()
@@ -167,84 +168,13 @@ object V2rayConfigUtil {
private fun routing(v2rayConfig: V2rayConfig): Boolean {
try {
- val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE)
- ?: ERoutingMode.BYPASS_LAN_MAINLAND.value
- routingUserRule(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_BLOCKED)
- .orEmpty(), TAG_BLOCKED, v2rayConfig
- )
- if (routingMode == ERoutingMode.GLOBAL_DIRECT.value) {
- routingUserRule(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT)
- .orEmpty(), TAG_DIRECT, v2rayConfig
- )
- routingUserRule(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT)
- .orEmpty(), TAG_PROXY, v2rayConfig
- )
- } else {
- routingUserRule(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT)
- .orEmpty(), TAG_PROXY, v2rayConfig
- )
- routingUserRule(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT)
- .orEmpty(), TAG_DIRECT, v2rayConfig
- )
+ v2rayConfig.routing.domainStrategy = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY) ?: "IPIfNonMatch"
+
+ val rulesetItems = MmkvManager.decodeRoutingRulesets()
+ rulesetItems?.forEach { key ->
+ routingUserRule(key, v2rayConfig)
}
-
- v2rayConfig.routing.domainStrategy =
- settingsStorage?.decodeString(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY)
- ?: "IPIfNonMatch"
-
- // Hardcode googleapis.cn gstatic.com
- val googleapisRoute = V2rayConfig.RoutingBean.RulesBean(
- outboundTag = TAG_PROXY,
- domain = arrayListOf("domain:googleapis.cn", "domain:gstatic.com")
- )
-
- when (routingMode) {
- ERoutingMode.BYPASS_LAN.value -> {
- routingGeo("", "private", TAG_DIRECT, v2rayConfig)
- }
-
- ERoutingMode.BYPASS_MAINLAND.value -> {
- routingGeo("", "cn", TAG_DIRECT, v2rayConfig)
- v2rayConfig.routing.rules.add(0, googleapisRoute)
- }
-
- ERoutingMode.BYPASS_LAN_MAINLAND.value -> {
- routingGeo("", "private", TAG_DIRECT, v2rayConfig)
- routingGeo("", "cn", TAG_DIRECT, v2rayConfig)
- v2rayConfig.routing.rules.add(0, googleapisRoute)
- }
-
- ERoutingMode.GLOBAL_DIRECT.value -> {
- val globalDirect = V2rayConfig.RoutingBean.RulesBean(
- outboundTag = TAG_DIRECT,
- )
- if (v2rayConfig.routing.domainStrategy != "IPIfNonMatch") {
- globalDirect.port = "0-65535"
- } else {
- globalDirect.ip = arrayListOf("0.0.0.0/0", "::/0")
- }
- v2rayConfig.routing.rules.add(globalDirect)
- }
- }
-
- if (routingMode != ERoutingMode.GLOBAL_DIRECT.value) {
- val globalProxy = V2rayConfig.RoutingBean.RulesBean(
- outboundTag = TAG_PROXY,
- )
- if (v2rayConfig.routing.domainStrategy != "IPIfNonMatch") {
- globalProxy.port = "0-65535"
- } else {
- globalProxy.ip = arrayListOf("0.0.0.0/0", "::/0")
- }
- v2rayConfig.routing.rules.add(globalProxy)
- }
-
} catch (e: Exception) {
e.printStackTrace()
return false
@@ -252,73 +182,35 @@ object V2rayConfigUtil {
return true
}
- private fun routingGeo(ipOrDomain: String, code: String, tag: String, v2rayConfig: V2rayConfig) {
+ private fun routingUserRule(item: RulesetItem?, v2rayConfig: V2rayConfig) {
try {
- if (!TextUtils.isEmpty(code)) {
- //IP
- if (ipOrDomain == "ip" || ipOrDomain == "") {
- val rulesIP = V2rayConfig.RoutingBean.RulesBean()
- rulesIP.outboundTag = tag
- rulesIP.ip = ArrayList()
- rulesIP.ip?.add("geoip:$code")
- v2rayConfig.routing.rules.add(rulesIP)
- }
-
- if (ipOrDomain == "domain" || ipOrDomain == "") {
- //Domain
- val rulesDomain = V2rayConfig.RoutingBean.RulesBean()
- rulesDomain.outboundTag = tag
- rulesDomain.domain = ArrayList()
- rulesDomain.domain?.add("geosite:$code")
- v2rayConfig.routing.rules.add(rulesDomain)
- }
+ if (item == null || !item.enabled) {
+ return
}
+
+ val rule = Gson().fromJson(Gson().toJson(item), RulesBean::class.java) ?: return
+
+ v2rayConfig.routing.rules.add(rule)
+
} catch (e: Exception) {
e.printStackTrace()
}
}
- private fun routingUserRule(userRule: String, tag: String, v2rayConfig: V2rayConfig) {
- try {
- if (!TextUtils.isEmpty(userRule)) {
- //Domain
- val rulesDomain = V2rayConfig.RoutingBean.RulesBean()
- rulesDomain.outboundTag = tag
- rulesDomain.domain = ArrayList()
+ private fun userRule2Domain(tag: String): ArrayList {
+ val domain = ArrayList()
- //IP
- val rulesIP = V2rayConfig.RoutingBean.RulesBean()
- rulesIP.outboundTag = tag
- rulesIP.ip = ArrayList()
-
- userRule.split(",").map { it.trim() }.forEach {
- if (it.startsWith("ext:") && it.contains("geoip")) {
- rulesIP.ip?.add(it)
- } else if (Utils.isIpAddress(it) || it.startsWith("geoip:")) {
- rulesIP.ip?.add(it)
- } else if (it.isNotEmpty()) {
- rulesDomain.domain?.add(it)
+ val rulesetItems = MmkvManager.decodeRoutingRulesets()
+ rulesetItems?.forEach { key ->
+ if (key != null && key.enabled && key.outboundTag == tag && !key.domain.isNullOrEmpty()) {
+ key.domain?.forEach {
+ if (it.startsWith("geosite:") || it.startsWith("domain:")) {
+ domain.add(it)
}
}
- if ((rulesDomain.domain?.size ?: 0) > 0) {
- v2rayConfig.routing.rules.add(rulesDomain)
- }
- if ((rulesIP.ip?.size ?: 0) > 0) {
- v2rayConfig.routing.rules.add(rulesIP)
- }
}
- } catch (e: Exception) {
- e.printStackTrace()
}
- }
- private fun userRule2Domain(userRule: String): ArrayList {
- val domain = ArrayList()
- userRule.split(",").map { it.trim() }.forEach {
- if (it.startsWith("geosite:") || it.startsWith("domain:")) {
- domain.add(it)
- }
- }
return domain
}
@@ -326,14 +218,8 @@ object V2rayConfigUtil {
try {
if (settingsStorage?.decodeBool(AppConfig.PREF_FAKE_DNS_ENABLED) == true) {
val geositeCn = arrayListOf("geosite:cn")
- val proxyDomain = userRule2Domain(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT)
- .orEmpty()
- )
- val directDomain = userRule2Domain(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT)
- .orEmpty()
- )
+ val proxyDomain = userRule2Domain(TAG_PROXY)
+ val directDomain = userRule2Domain(TAG_DIRECT)
// fakedns with all domains to make it always top priority
v2rayConfig.dns.servers?.add(
0,
@@ -404,10 +290,7 @@ object V2rayConfigUtil {
//remote Dns
val remoteDns = Utils.getRemoteDnsServers()
- val proxyDomain = userRule2Domain(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT)
- .orEmpty()
- )
+ val proxyDomain = userRule2Domain(TAG_PROXY)
remoteDns.forEach {
servers.add(it)
}
@@ -424,16 +307,9 @@ object V2rayConfigUtil {
// domestic DNS
val domesticDns = Utils.getDomesticDnsServers()
- val directDomain = userRule2Domain(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT)
- .orEmpty()
- )
- val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE)
- ?: ERoutingMode.BYPASS_LAN_MAINLAND.value
- val isCnRoutingMode =
- (routingMode == ERoutingMode.BYPASS_MAINLAND.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value)
+ val directDomain = userRule2Domain(TAG_DIRECT)
+ val isCnRoutingMode = directDomain.contains("geosite:cn")
val geoipCn = arrayListOf("geoip:cn")
-
if (directDomain.size > 0) {
servers.add(
V2rayConfig.DnsBean.ServersBean(
@@ -444,17 +320,6 @@ object V2rayConfigUtil {
)
)
}
- if (isCnRoutingMode) {
- val geositeCn = arrayListOf("geosite:cn")
- servers.add(
- V2rayConfig.DnsBean.ServersBean(
- domesticDns.first(),
- 53,
- geositeCn,
- geoipCn
- )
- )
- }
if (Utils.isPureIpAddress(domesticDns.first())) {
v2rayConfig.routing.rules.add(
@@ -468,10 +333,7 @@ object V2rayConfigUtil {
}
//block dns
- val blkDomain = userRule2Domain(
- settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_BLOCKED)
- .orEmpty()
- )
+ val blkDomain = userRule2Domain(TAG_BLOCKED)
if (blkDomain.size > 0) {
hosts.putAll(blkDomain.map { it to "127.0.0.1" })
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt
index 13183ec9..75e6fbd1 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt
@@ -39,10 +39,6 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_LANGUAGE,
AppConfig.PREF_UI_MODE_NIGHT,
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
- AppConfig.PREF_ROUTING_MODE,
- AppConfig.PREF_V2RAY_ROUTING_AGENT,
- AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
- AppConfig.PREF_V2RAY_ROUTING_DIRECT,
AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,
AppConfig.PREF_FRAGMENT_PACKETS,
AppConfig.PREF_FRAGMENT_LENGTH,
diff --git a/V2rayNG/app/src/main/res/drawable-night/ic_routing_24dp.xml b/V2rayNG/app/src/main/res/drawable-night/ic_routing_24dp.xml
new file mode 100644
index 00000000..7002c085
--- /dev/null
+++ b/V2rayNG/app/src/main/res/drawable-night/ic_routing_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/V2rayNG/app/src/main/res/drawable/ic_routing_24dp.xml b/V2rayNG/app/src/main/res/drawable/ic_routing_24dp.xml
new file mode 100644
index 00000000..9032a2e6
--- /dev/null
+++ b/V2rayNG/app/src/main/res/drawable/ic_routing_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/V2rayNG/app/src/main/res/layout/activity_routing_edit.xml b/V2rayNG/app/src/main/res/layout/activity_routing_edit.xml
new file mode 100644
index 00000000..68f8d53c
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/activity_routing_edit.xml
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/activity_routing_setting.xml b/V2rayNG/app/src/main/res/layout/activity_routing_setting.xml
new file mode 100644
index 00000000..825c1c50
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/activity_routing_setting.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/activity_routing_settings.xml b/V2rayNG/app/src/main/res/layout/activity_routing_settings.xml
deleted file mode 100644
index a77a8062..00000000
--- a/V2rayNG/app/src/main/res/layout/activity_routing_settings.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml b/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml
index 46c97385..19732a8e 100644
--- a/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml
@@ -80,12 +80,11 @@
android:orientation="horizontal">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_routing_setting.xml b/V2rayNG/app/src/main/res/layout/item_recycler_routing_setting.xml
new file mode 100644
index 00000000..a42362db
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/item_recycler_routing_setting.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml b/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml
index 738a7f5c..e5d8e4c0 100644
--- a/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml
+++ b/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml
@@ -51,7 +51,7 @@
+ android:id="@+id/routing_setting"
+ android:icon="@drawable/ic_routing_24dp"
+ android:title="@string/routing_settings_title" />
diff --git a/V2rayNG/app/src/main/res/menu/menu_routing.xml b/V2rayNG/app/src/main/res/menu/menu_routing.xml
deleted file mode 100644
index 7f40c92a..00000000
--- a/V2rayNG/app/src/main/res/menu/menu_routing.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/menu/menu_routing_setting.xml b/V2rayNG/app/src/main/res/menu/menu_routing_setting.xml
new file mode 100644
index 00000000..afa71bc0
--- /dev/null
+++ b/V2rayNG/app/src/main/res/menu/menu_routing_setting.xml
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/values-ar/strings.xml b/V2rayNG/app/src/main/res/values-ar/strings.xml
index 1ede85b5..22bff425 100644
--- a/V2rayNG/app/src/main/res/values-ar/strings.xml
+++ b/V2rayNG/app/src/main/res/values-ar/strings.xml
@@ -158,11 +158,6 @@
تفضيل IPv6
تفضيل عنوان IPv6 وطرق التوجيه
- التوجيه
- استراتيجية النطاق
- قواعد محددة مسبقًا
- قواعد مخصصة
-
DNS البعيد (udp/tcp/https/quic) (اختياري)
DNS
@@ -251,13 +246,15 @@
بدء الخدمة
تأكيد
+ استراتيجية النطاق
إعدادات التوجيه
مفصولة بفواصل (،)، تذكر الحفظ
حفظ
مسح
- فحص واستبدال
- فحص وإضافة
- تعيين قواعد توجيه افتراضية
+ Routing Rule Settings
+ Add rule
+ Import ruleset
+ Existing rulesets will be deleted, are you sure to continue?
التحقق من الاتصال
يجري الاختبار…
@@ -287,20 +284,6 @@
- تصدير إلى الحافظة
-
- - عنوان URL أو IP الوكيل
- - عنوان URL أو IP المباشر
- - عنوان URL أو IP المحظور
-
-
-
- - وكيل عام
- - تجاوز عنوان الشبكة المحلية ثم الوكيل
- - تجاوز عنوان البر الرئيسي ثم الوكيل
- - تجاوز عنوان الشبكة المحلية والبر الرئيسي ثم الوكيل
- - مباشر عام
-
-
- VPN
- بروكسي فقط
diff --git a/V2rayNG/app/src/main/res/values-bn/strings.xml b/V2rayNG/app/src/main/res/values-bn/strings.xml
index db79075f..86967872 100644
--- a/V2rayNG/app/src/main/res/values-bn/strings.xml
+++ b/V2rayNG/app/src/main/res/values-bn/strings.xml
@@ -157,11 +157,6 @@
IPv6 অগ্রাধিকার দিন
IPv6 ঠিকানা এবং রুটকে অগ্রাধিকার দিন
- রাউটিং
- ডোমেইন কৌশল
- পূর্বনির্ধারিত নিয়ম
- কাস্টম নিয়ম
-
রিমোট DNS (udp/tcp/https/quic)(ঐচ্ছিক)
DNS
@@ -248,13 +243,15 @@
সার্ভিস শুরু করুন
নিশ্চিত করুন
+ ডোমেইন কৌশল
রাউটিং সেটিংস
কমা (,) দ্বারা আলাদা করুন, মনে রাখবেন সেভ করতে
সেভ করুন
মুছে ফেলুন
- স্ক্যান করুন এবং প্রতিস্থাপন করুন
- স্ক্যান করুন এবং যোগ করুন
- ডিফল্ট রাউটিং নিয়ম সেট করুন
+ Routing Rule Settings
+ Add rule
+ Import ruleset
+ Existing rulesets will be deleted, are you sure to continue?
সংযোগ পরীক্ষা করুন
পরীক্ষা চলছে…
@@ -283,20 +280,6 @@
- ক্লিপবোর্ডে রপ্তানি করুন
-
- - প্রক্সি URL বা IP
- - ডাইরেক্ট URL বা IP
- - ব্লকড URL বা IP
-
-
-
- - গ্লোবাল প্রোক্সি
- - LAN ঠিকানা বাইপাস করে তারপর প্রোক্সি
- - মেইনল্যান্ড ঠিকানা বাইপাস করে তারপর প্রোক্সি
- - LAN এবং মেইনল্যান্ড ঠিকানা বাইপাস করে তারপর প্রোক্সি
- - গ্লোবাল ডাইরেক্ট
-
-
- VPN
- শুধুমাত্র প্রোক্সি
diff --git a/V2rayNG/app/src/main/res/values-fa/strings.xml b/V2rayNG/app/src/main/res/values-fa/strings.xml
index da8d52ff..08b5683d 100644
--- a/V2rayNG/app/src/main/res/values-fa/strings.xml
+++ b/V2rayNG/app/src/main/res/values-fa/strings.xml
@@ -155,11 +155,6 @@
ترجیح دادن IPv6
ترجیح دادن نشانی و مسیر های IPv6
- مسیریابی
- استراتژی دامنه
- قوانین از پیش تعریف شده
- قوانین سفارشی
-
DNS از راه دور (اختیاری)
DNS
@@ -247,13 +242,15 @@
شروع خدمات
تایید
+ استراتژی دامنه
تنظیمات مسیریابی
با کاما (,) از هم جدا شوند، ذخیره کردن فراموش نشود
ذخیره
پاک کردن
- اسکن و جایگزین کنید
- اسکن و اضافه کنید
- قوانین مسیریابی پیشفرض را تنظیم کنید
+ Routing Rule Settings
+ Add rule
+ Import ruleset
+ Existing rulesets will be deleted, are you sure to continue?
اتصال را بررسی کنید
در حال آزمایش...
@@ -282,20 +279,6 @@
- خروجی گرفتن در کلیپبورد
-
- - نشانی اینترنتی یا آیپی پروکسی
- - نشانی اینترنتی یا آیپی مستقیم
- - نشانی اینترنتی یا آیپی مسدود شده
-
-
-
- - پروکسی سراسری
- - دور زدن آدرس LAN و سپس پروکسی
- - دور زدن آدرس mainland و سپس پروکسی
- - دور زدن LAN و آدرس mainland و سپس پروکسی
- - مستقیم سراسری
-
-
- VPN
- فقط پروکسی
diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml
index 1798634c..e5d5d42f 100644
--- a/V2rayNG/app/src/main/res/values-ru/strings.xml
+++ b/V2rayNG/app/src/main/res/values-ru/strings.xml
@@ -158,11 +158,6 @@
Предпочитать IPv6
Предпочитать IPv6-адреса и маршрутизацию
- Маршрутизация
- Доменная стратегия
- Режим маршрутизации
- Пользовательские правила
-
Удалённая DNS (UDP/TCP/HTTPS/QUIC) (необязательно)
DNS
@@ -251,13 +246,15 @@
Запуск службы
Подтвердить
+ Доменная стратегия
Настройки маршрутизации
Введите требуемые IP/URL через запятую. Не забудьте сохранить изменения.
Сохранить
Очистить
- Сканировать и заменить
- Сканировать и добавить
- Правила по умолчанию
+ Routing Rule Settings
+ Add rule
+ Import ruleset
+ Existing rulesets will be deleted, are you sure to continue?
Проверить подключение
Проверка…
@@ -287,20 +284,6 @@
- Экспорт в буфер обмена
-
- - Проксируемые
- - Прямые
- - Блокируемые
-
-
-
- - Все через прокси
- - Все, кроме LAN через прокси
- - Все, кроме Китая через прокси
- - Все, кроме LAN и Китая через прокси
- - Все напрямую
-
-
- VPN
- Только прокси
diff --git a/V2rayNG/app/src/main/res/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml
index 4df0766f..38d244fd 100644
--- a/V2rayNG/app/src/main/res/values-vi/strings.xml
+++ b/V2rayNG/app/src/main/res/values-vi/strings.xml
@@ -157,11 +157,6 @@
Ưu tiên IPv6
Ưu tiên sử dụng địa chỉ IPv6 cho kết nối và định tuyến.
- Định tuyến
- Chiến lược tên miền (DomainStrategy)
- Quy tắc được định nghĩa trước
- Quy tắc tùy chỉnh
-
DNS ngoại quốc (UDP / TCP / HTTPS / QUIC) (Không bắt buộc)
DNS
@@ -250,13 +245,15 @@
Khởi động v2rayNG
Xác nhận
+ Chiến lược tên miền (DomainStrategy)
Cài đặt định tuyến
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.
Lưu lại
Xoá
- Quét QR và Thay thế
- Quét QR và Nối thêm
- Tải xuống Rules mặc định cho Trung Quốc
+ Routing Rule Settings
+ Add rule
+ Import ruleset
+ Existing rulesets will be deleted, are you sure to continue?
Kiểm tra kết nối
Đang kiểm tra kết nối mạng...
@@ -281,20 +278,6 @@
- Xuất gói vào Clipboard
-
- - Proxy
- - Direct
- - Blocked
-
-
-
- - Proxy toàn cầu
- - Bỏ qua địa chỉ LAN rồi Proxy
- - Bỏ qua địa chỉ nội địa rồi Proxy
- - Bỏ qua LAN và địa chỉ nội địa rồi Proxy
- - Kết nối trực tiếp toàn cầu
-
-
- Chế độ VPN
- Chế độ Proxy
diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml
index 4eaa1312..f3d12d6c 100644
--- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml
+++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml
@@ -155,11 +155,6 @@
IPv6优先
App优先使用IPv6地址连接服务器,同时开启VPN的IPv6路由
- 路由设置
- 域名策略
- 预定义规则
- 自定义规则
-
远程DNS (udp/tcp/https/quic)(可选)
DNS
@@ -248,13 +243,15 @@
启动服务
确定
+ 域名策略
路由设置
- 用逗号(,)隔开,可以一行多个,记得保存
+ 用逗号(,)隔开,可以一行多个
保存
清空
- 扫描并替换
- 扫描并追加
- 设置默认路由规则
+ 路由规则设置
+ 添加规则
+ 导入预设规则集
+ 将删除现有的规则集,是否确定继续?
"检查网络连接"
"测试中…"
@@ -286,21 +283,6 @@
- 导出至剪贴板
- share_method
-
- - 代理的网址或IP
- - 直连的网址或IP
- - 阻止的网址或IP
-
-
-
- - 全局代理
- - 绕过局域网地址而后代理
- - 绕过大陆地址而后代理
- - 绕过局域网及大陆地址而后代理
- - 全局直连
-
-
- VPN
- 仅代理
diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml
index fa53135f..c80ed2c1 100644
--- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml
+++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml
@@ -156,11 +156,6 @@
IPv6 偏好
App 優先使用 IPv6 位址連線伺服器,同时開啟 VPN 的 IPv6 路由
- 轉送設定
- 網域策略
- 轉送模式
- 自訂轉送
-
遠端DNS (udp/tcp/https/quic)(可選)
DNS
@@ -249,13 +244,15 @@
啟動服務
確定
+ 網域策略
轉送設定
- 以半形逗號「,」分隔,並手動儲存
+ 以半形逗號「,」分隔
儲存
清除
- 掃描並取代
- 掃描並附加
- 設定預設轉送規則
+ 路由規則設定
+ 新增規則
+ 匯入預設規則集
+ 將刪除現有的規則集,是否確定繼續?
"測試連線能力"
"測試中……"
@@ -287,20 +284,6 @@
- 匯出至剪貼簿
-
- - Proxy URL 或 IP
- - 直接連線 URL 或 IP
- - 已封鎖的 URL 或 IP
-
-
-
- - 全域 Proxy
- - 略過區域網路的 Proxy
- - 略過中國大陸的 Proxy
- - 略過區域網路及中國大陸的 Proxy
- - 直接連線
-
-
- VPN
- 僅 Proxy
diff --git a/V2rayNG/app/src/main/res/values/arrays.xml b/V2rayNG/app/src/main/res/values/arrays.xml
index 721aae04..535e6bd7 100644
--- a/V2rayNG/app/src/main/res/values/arrays.xml
+++ b/V2rayNG/app/src/main/res/values/arrays.xml
@@ -99,14 +99,6 @@
- false
-
- - 0
- - 1
- - 2
- - 3
- - 4
-
-
- AsIs
- IPIfNonMatch
@@ -205,4 +197,10 @@
- 1
- 2
+
+
+ - proxy
+ - direct
+ - block
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/values/dimens.xml b/V2rayNG/app/src/main/res/values/dimens.xml
index ab32f209..58510db5 100644
--- a/V2rayNG/app/src/main/res/values/dimens.xml
+++ b/V2rayNG/app/src/main/res/values/dimens.xml
@@ -7,7 +7,7 @@
50dp
24dp
72dp
- 108dp
+ 90dp
60dp
16dp
16dp
diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml
index c9a090a3..fae291f1 100644
--- a/V2rayNG/app/src/main/res/values/strings.xml
+++ b/V2rayNG/app/src/main/res/values/strings.xml
@@ -161,11 +161,6 @@
Prefer IPv6
Prefer IPv6 address and routes
- Routing
- Domain strategy
- Predefined rules
- Custom rules
-
Remote DNS (udp/tcp/https/quic)(Optional)
DNS
@@ -254,13 +249,23 @@
Start Service
Confirm
+ Domain strategy
Routing Settings
- Separated by commas(,),remember to save
+ Separated by commas(,)
Save
Clear
- Scan and replace
- Scan and append
- set default routing rules
+ Routing Rule Settings
+ Add rule
+ Import ruleset
+ Existing rulesets will be deleted, are you sure to continue?
+ domain
+ ip
+ port
+ protocol
+ [http,tls,bittorrent]
+ network"[udp|tcp]"
+ [udp|tcp]
+ outboundTag
Check Connectivity
Testing…
@@ -290,20 +295,6 @@
- Export to clipboard
-
- - proxy URL or IP
- - direct URL or IP
- - blocked URL or IP
-
-
-
- - Global proxy
- - Bypassing the LAN address then proxy
- - Bypass mainland address then proxy
- - Bypassing LAN and mainland address then proxy
- - Global direct
-
-
- VPN
- Proxy only
diff --git a/V2rayNG/app/src/main/res/xml/pref_settings.xml b/V2rayNG/app/src/main/res/xml/pref_settings.xml
index 9f5728de..ca13d534 100644
--- a/V2rayNG/app/src/main/res/xml/pref_settings.xml
+++ b/V2rayNG/app/src/main/res/xml/pref_settings.xml
@@ -42,30 +42,6 @@
android:title="@string/title_pref_vpn_dns" />
-
-
-
-
-
-
-
-
-