Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e041a6e9a | ||
|
|
c78ef380cc | ||
|
|
57362a4bde | ||
|
|
7f24ad534f | ||
|
|
680832614b | ||
|
|
4357abbff4 | ||
|
|
905be66c3f | ||
|
|
318a7b54a5 | ||
|
|
5db2df77a0 | ||
|
|
d039cb9edf | ||
|
|
9a1654bae9 | ||
|
|
3bf911da9c | ||
|
|
3f778a1ea2 | ||
|
|
8e03de8055 | ||
|
|
1f42d7fc07 | ||
|
|
0700e834f1 | ||
|
|
777190e861 | ||
|
|
33572477fc | ||
|
|
2fb6e62e13 | ||
|
|
94cc72d2b9 | ||
|
|
f68c353715 | ||
|
|
e077c18108 | ||
|
|
1a5e105212 | ||
|
|
e0881caab4 | ||
|
|
7219425258 |
Submodule AndroidLibXrayLite updated: 4de15a6c8d...fe7e12eb08
@@ -12,8 +12,8 @@ android {
|
|||||||
applicationId = "com.v2ray.ang"
|
applicationId = "com.v2ray.ang"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 656
|
versionCode = 661
|
||||||
versionName = "1.10.6"
|
versionName = "1.10.11"
|
||||||
multiDexEnabled = true
|
multiDexEnabled = true
|
||||||
|
|
||||||
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
|
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ object AppConfig {
|
|||||||
const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port"
|
const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port"
|
||||||
const val PREF_VPN_DNS = "pref_vpn_dns"
|
const val PREF_VPN_DNS = "pref_vpn_dns"
|
||||||
const val PREF_VPN_BYPASS_LAN = "pref_vpn_bypass_lan"
|
const val PREF_VPN_BYPASS_LAN = "pref_vpn_bypass_lan"
|
||||||
|
const val PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX = "pref_vpn_interface_address_config_index"
|
||||||
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
|
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
|
||||||
const val PREF_ROUTING_RULESET = "pref_routing_ruleset"
|
const val PREF_ROUTING_RULESET = "pref_routing_ruleset"
|
||||||
const val PREF_MUX_ENABLED = "pref_mux_enabled"
|
const val PREF_MUX_ENABLED = "pref_mux_enabled"
|
||||||
@@ -55,6 +56,8 @@ object AppConfig {
|
|||||||
const val PREF_DNS_HOSTS = "pref_dns_hosts"
|
const val PREF_DNS_HOSTS = "pref_dns_hosts"
|
||||||
const val PREF_DELAY_TEST_URL = "pref_delay_test_url"
|
const val PREF_DELAY_TEST_URL = "pref_delay_test_url"
|
||||||
const val PREF_LOGLEVEL = "pref_core_loglevel"
|
const val PREF_LOGLEVEL = "pref_core_loglevel"
|
||||||
|
const val PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD = "pref_outbound_domain_resolve_method"
|
||||||
|
const val PREF_INTELLIGENT_SELECTION_METHOD = "pref_intelligent_selection_method"
|
||||||
const val PREF_MODE = "pref_mode"
|
const val PREF_MODE = "pref_mode"
|
||||||
const val PREF_IS_BOOTED = "pref_is_booted"
|
const val PREF_IS_BOOTED = "pref_is_booted"
|
||||||
const val PREF_CHECK_UPDATE_PRE_RELEASE = "pref_check_update_pre_release"
|
const val PREF_CHECK_UPDATE_PRE_RELEASE = "pref_check_update_pre_release"
|
||||||
@@ -168,7 +171,9 @@ object AppConfig {
|
|||||||
// Android Private DNS constants
|
// Android Private DNS constants
|
||||||
const val DNS_DNSPOD_DOMAIN = "dot.pub"
|
const val DNS_DNSPOD_DOMAIN = "dot.pub"
|
||||||
const val DNS_ALIDNS_DOMAIN = "dns.alidns.com"
|
const val DNS_ALIDNS_DOMAIN = "dns.alidns.com"
|
||||||
const val DNS_CLOUDFLARE_DOMAIN = "one.one.one.one"
|
const val DNS_CLOUDFLARE_ONE_DOMAIN = "one.one.one.one"
|
||||||
|
const val DNS_CLOUDFLARE_DNS_COM_DOMAIN = "dns.cloudflare.com"
|
||||||
|
const val DNS_CLOUDFLARE_DNS_DOMAIN = "cloudflare-dns.com"
|
||||||
const val DNS_GOOGLE_DOMAIN = "dns.google"
|
const val DNS_GOOGLE_DOMAIN = "dns.google"
|
||||||
const val DNS_QUAD9_DOMAIN = "dns.quad9.net"
|
const val DNS_QUAD9_DOMAIN = "dns.quad9.net"
|
||||||
const val DNS_YANDEX_DOMAIN = "common.dot.dns.yandex.net"
|
const val DNS_YANDEX_DOMAIN = "common.dot.dns.yandex.net"
|
||||||
@@ -182,7 +187,9 @@ object AppConfig {
|
|||||||
const val HEADER_TYPE_HTTP = "http"
|
const val HEADER_TYPE_HTTP = "http"
|
||||||
|
|
||||||
val DNS_ALIDNS_ADDRESSES = arrayListOf("223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1")
|
val DNS_ALIDNS_ADDRESSES = arrayListOf("223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1")
|
||||||
val DNS_CLOUDFLARE_ADDRESSES = arrayListOf("1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001")
|
val DNS_CLOUDFLARE_ONE_ADDRESSES = arrayListOf("1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001")
|
||||||
|
val DNS_CLOUDFLARE_DNS_COM_ADDRESSES = arrayListOf("104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5")
|
||||||
|
val DNS_CLOUDFLARE_DNS_ADDRESSES = arrayListOf("104.16.248.249", "104.16.249.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9")
|
||||||
val DNS_DNSPOD_ADDRESSES = arrayListOf("1.12.12.12", "120.53.53.53")
|
val DNS_DNSPOD_ADDRESSES = arrayListOf("1.12.12.12", "120.53.53.53")
|
||||||
val DNS_GOOGLE_ADDRESSES = arrayListOf("8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844")
|
val DNS_GOOGLE_ADDRESSES = arrayListOf("8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844")
|
||||||
val DNS_QUAD9_ADDRESSES = arrayListOf("9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9")
|
val DNS_QUAD9_ADDRESSES = arrayListOf("9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9")
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ data class SubscriptionItem(
|
|||||||
var prevProfile: String? = null,
|
var prevProfile: String? = null,
|
||||||
var nextProfile: String? = null,
|
var nextProfile: String? = null,
|
||||||
var filter: String? = null,
|
var filter: String? = null,
|
||||||
|
var intelligentSelectionFilter: String? = null,
|
||||||
var allowInsecureUrl: Boolean = false,
|
var allowInsecureUrl: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -496,14 +496,14 @@ data class V2rayConfig(
|
|||||||
var domainStrategy: String,
|
var domainStrategy: String,
|
||||||
var domainMatcher: String? = null,
|
var domainMatcher: String? = null,
|
||||||
var rules: ArrayList<RulesBean>,
|
var rules: ArrayList<RulesBean>,
|
||||||
val balancers: List<Any>? = null
|
var balancers: List<BalancerBean>? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
data class RulesBean(
|
data class RulesBean(
|
||||||
var type: String = "field",
|
var type: String = "field",
|
||||||
var ip: ArrayList<String>? = null,
|
var ip: ArrayList<String>? = null,
|
||||||
var domain: ArrayList<String>? = null,
|
var domain: ArrayList<String>? = null,
|
||||||
var outboundTag: String = "",
|
var outboundTag: String? = null,
|
||||||
var balancerTag: String? = null,
|
var balancerTag: String? = null,
|
||||||
var port: String? = null,
|
var port: String? = null,
|
||||||
val sourcePort: String? = null,
|
val sourcePort: String? = null,
|
||||||
@@ -515,6 +515,32 @@ data class V2rayConfig(
|
|||||||
val attrs: String? = null,
|
val attrs: String? = null,
|
||||||
val domainMatcher: String? = null
|
val domainMatcher: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class BalancerBean(
|
||||||
|
val tag: String,
|
||||||
|
val selector: List<String>,
|
||||||
|
val fallbackTag: String? = null,
|
||||||
|
val strategy: StrategyObject? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
data class StrategyObject(
|
||||||
|
val type: String = "random", // "random" | "roundRobin" | "leastPing" | "leastLoad"
|
||||||
|
val settings: StrategySettingsObject? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
data class StrategySettingsObject(
|
||||||
|
val expected: Int? = null,
|
||||||
|
val maxRTT: String? = null,
|
||||||
|
val tolerance: Double? = null,
|
||||||
|
val baselines: List<String>? = null,
|
||||||
|
val costs: List<CostObject>? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CostObject(
|
||||||
|
val regexp: Boolean = false,
|
||||||
|
val match: String,
|
||||||
|
val value: Double
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PolicyBean(
|
data class PolicyBean(
|
||||||
@@ -532,6 +558,26 @@ data class V2rayConfig(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ObservatoryObject(
|
||||||
|
val subjectSelector: List<String>,
|
||||||
|
val probeUrl: String,
|
||||||
|
val probeInterval: String,
|
||||||
|
val enableConcurrency: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
data class BurstObservatoryObject(
|
||||||
|
val subjectSelector: List<String>,
|
||||||
|
val pingConfig: PingConfigObject
|
||||||
|
) {
|
||||||
|
data class PingConfigObject(
|
||||||
|
val destination: String,
|
||||||
|
val connectivity: String? = null,
|
||||||
|
val interval: String,
|
||||||
|
val sampling: Int,
|
||||||
|
val timeout: String? = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
data class FakednsBean(
|
data class FakednsBean(
|
||||||
var ipPool: String = "198.18.0.0/15",
|
var ipPool: String = "198.18.0.0/15",
|
||||||
var poolSize: Int = 10000
|
var poolSize: Int = 10000
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.v2ray.ang.dto
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VPN interface address configuration enum class
|
||||||
|
* Defines predefined IPv4 and IPv6 address pairs for VPN TUN interface configuration.
|
||||||
|
* Each option provides client and router addresses to establish point-to-point VPN tunnels.
|
||||||
|
*/
|
||||||
|
enum class VpnInterfaceAddressConfig(
|
||||||
|
val displayName: String,
|
||||||
|
val ipv4Client: String,
|
||||||
|
val ipv4Router: String,
|
||||||
|
val ipv6Client: String,
|
||||||
|
val ipv6Router: String
|
||||||
|
) {
|
||||||
|
OPTION_1("10.10.14.x", "10.10.14.1", "10.10.14.2", "fc00::10:10:14:1", "fc00::10:10:14:2"),
|
||||||
|
OPTION_2("10.1.0.x", "10.1.0.1", "10.1.0.2", "fc00::10:1:0:1", "fc00::10:1:0:2"),
|
||||||
|
OPTION_3("10.0.0.x", "10.0.0.1", "10.0.0.2", "fc00::10:0:0:1", "fc00::10:0:0:2"),
|
||||||
|
OPTION_4("172.31.0.x", "172.31.0.1", "172.31.0.2", "fc00::172:31:0:1", "fc00::172:31:0:2"),
|
||||||
|
OPTION_5("172.20.0.x", "172.20.0.1", "172.20.0.2", "fc00::172:20:0:1", "fc00::172:20:0:2"),
|
||||||
|
OPTION_6("172.16.0.x", "172.16.0.1", "172.16.0.2", "fc00::172:16:0:1", "fc00::172:16:0:2"),
|
||||||
|
OPTION_7("192.168.100.x", "192.168.100.1", "192.168.100.2", "fc00::192:168:100:1", "fc00::192:168:100:2");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Retrieves the VPN interface address configuration based on the specified index.
|
||||||
|
*
|
||||||
|
* @param index The configuration index (0-based) corresponding to user selection
|
||||||
|
* @return The VpnInterfaceAddressConfig instance at the specified index,
|
||||||
|
* or OPTION_1 (default) if the index is out of bounds
|
||||||
|
*/
|
||||||
|
fun getConfigByIndex(index: Int): VpnInterfaceAddressConfig {
|
||||||
|
return if (index in values().indices) {
|
||||||
|
values()[index]
|
||||||
|
} else {
|
||||||
|
OPTION_1 // Default to the first configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import com.v2ray.ang.AppConfig
|
|||||||
import com.v2ray.ang.dto.NetworkType
|
import com.v2ray.ang.dto.NetworkType
|
||||||
import com.v2ray.ang.dto.ProfileItem
|
import com.v2ray.ang.dto.ProfileItem
|
||||||
import com.v2ray.ang.extension.isNotNullEmpty
|
import com.v2ray.ang.extension.isNotNullEmpty
|
||||||
|
import com.v2ray.ang.handler.MmkvManager
|
||||||
import com.v2ray.ang.util.HttpUtil
|
import com.v2ray.ang.util.HttpUtil
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
@@ -151,7 +152,19 @@ open class FmtBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getServerAddress(profileItem: ProfileItem): String {
|
fun getServerAddress(profileItem: ProfileItem): String {
|
||||||
return HttpUtil.toIdnDomain(profileItem.server.orEmpty())
|
if (Utils.isPureIpAddress(profileItem.server.orEmpty())) {
|
||||||
}
|
return profileItem.server.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
val domain = HttpUtil.toIdnDomain(profileItem.server.orEmpty())
|
||||||
|
if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") != "2") {
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
//Resolve and replace domain
|
||||||
|
val resolvedIps = HttpUtil.resolveHostToIP(domain, MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6))
|
||||||
|
if (resolvedIps.isNullOrEmpty()) {
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
return resolvedIps.first()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ object AngConfigManager {
|
|||||||
if (sb.count() > 0) {
|
if (sb.count() > 0) {
|
||||||
Utils.setClipboard(context, sb.toString())
|
Utils.setClipboard(context, sb.toString())
|
||||||
}
|
}
|
||||||
return sb.lines().count()
|
return sb.lines().count() - 1
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(AppConfig.TAG, "Failed to share non-custom configs to clipboard", e)
|
Log.e(AppConfig.TAG, "Failed to share non-custom configs to clipboard", e)
|
||||||
return -1
|
return -1
|
||||||
@@ -490,4 +490,31 @@ object AngConfigManager {
|
|||||||
MmkvManager.encodeSubscription("", subItem)
|
MmkvManager.encodeSubscription("", subItem)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an intelligent selection configuration based on multiple server configurations.
|
||||||
|
*
|
||||||
|
* @param context The application context used for configuration generation.
|
||||||
|
* @param guidList The list of server GUIDs to be included in the intelligent selection.
|
||||||
|
* Each GUID represents a server configuration that will be combined.
|
||||||
|
* @param subid The subscription ID to associate with the generated configuration.
|
||||||
|
* This helps organize the configuration under a specific subscription.
|
||||||
|
* @return The GUID key of the newly created intelligent selection configuration,
|
||||||
|
* or null if the operation fails (e.g., empty guidList or configuration parsing error).
|
||||||
|
*/
|
||||||
|
fun createIntelligentSelection(
|
||||||
|
context: Context,
|
||||||
|
guidList: List<String>,
|
||||||
|
subid: String
|
||||||
|
): String? {
|
||||||
|
if (guidList.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val result = V2rayConfigManager.genV2rayConfig(context, guidList) ?: return null
|
||||||
|
val config = CustomFmt.parse(JsonUtil.toJson(result)) ?: return null
|
||||||
|
config.subscriptionId = subid
|
||||||
|
val key = MmkvManager.encodeServerConfig("", config)
|
||||||
|
MmkvManager.encodeServerRaw(key, JsonUtil.toJsonPretty(result) ?: "")
|
||||||
|
return key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.v2ray.ang.dto.ProfileItem
|
|||||||
import com.v2ray.ang.dto.RoutingType
|
import com.v2ray.ang.dto.RoutingType
|
||||||
import com.v2ray.ang.dto.RulesetItem
|
import com.v2ray.ang.dto.RulesetItem
|
||||||
import com.v2ray.ang.dto.V2rayConfig
|
import com.v2ray.ang.dto.V2rayConfig
|
||||||
|
import com.v2ray.ang.dto.VpnInterfaceAddressConfig
|
||||||
import com.v2ray.ang.handler.MmkvManager.decodeServerConfig
|
import com.v2ray.ang.handler.MmkvManager.decodeServerConfig
|
||||||
import com.v2ray.ang.handler.MmkvManager.decodeServerList
|
import com.v2ray.ang.handler.MmkvManager.decodeServerList
|
||||||
import com.v2ray.ang.util.JsonUtil
|
import com.v2ray.ang.util.JsonUtil
|
||||||
@@ -356,4 +357,17 @@ object SettingsManager {
|
|||||||
"2" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
"2" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the currently selected VPN interface address configuration.
|
||||||
|
* This method reads the user's preference for VPN interface addressing and returns
|
||||||
|
* the corresponding configuration containing IPv4 and IPv6 addresses.
|
||||||
|
*
|
||||||
|
* @return The selected VpnInterfaceAddressConfig instance, or the default configuration
|
||||||
|
* if no valid selection is found or if the stored index is invalid.
|
||||||
|
*/
|
||||||
|
fun getCurrentVpnInterfaceAddressConfig(): VpnInterfaceAddressConfig {
|
||||||
|
val selectedIndex = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX, "0")?.toInt()
|
||||||
|
return VpnInterfaceAddressConfig.getConfigByIndex(selectedIndex ?: 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import java.io.FileOutputStream
|
|||||||
|
|
||||||
object UpdateCheckerManager {
|
object UpdateCheckerManager {
|
||||||
suspend fun checkForUpdate(includePreRelease: Boolean = false): CheckUpdateResult = withContext(Dispatchers.IO) {
|
suspend fun checkForUpdate(includePreRelease: Boolean = false): CheckUpdateResult = withContext(Dispatchers.IO) {
|
||||||
try {
|
|
||||||
val url = if (includePreRelease) {
|
val url = if (includePreRelease) {
|
||||||
AppConfig.APP_API_URL
|
AppConfig.APP_API_URL
|
||||||
} else {
|
} else {
|
||||||
@@ -53,10 +52,6 @@ object UpdateCheckerManager {
|
|||||||
} else {
|
} else {
|
||||||
CheckUpdateResult(hasUpdate = false)
|
CheckUpdateResult(hasUpdate = false)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(AppConfig.TAG, "Failed to check for updates: ${e.message}")
|
|
||||||
return@withContext CheckUpdateResult(hasUpdate = false, error = e.message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun downloadApk(context: Context, downloadUrl: String): File? = withContext(Dispatchers.IO) {
|
suspend fun downloadApk(context: Context, downloadUrl: String): File? = withContext(Dispatchers.IO) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.dto.ConfigResult
|
import com.v2ray.ang.dto.ConfigResult
|
||||||
import com.v2ray.ang.dto.EConfigType
|
import com.v2ray.ang.dto.EConfigType
|
||||||
import com.v2ray.ang.dto.NetworkType
|
import com.v2ray.ang.dto.NetworkType
|
||||||
@@ -15,8 +16,8 @@ import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean
|
|||||||
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean
|
import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean
|
||||||
import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean
|
import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean
|
||||||
import com.v2ray.ang.extension.isNotNullEmpty
|
import com.v2ray.ang.extension.isNotNullEmpty
|
||||||
|
import com.v2ray.ang.fmt.CustomFmt
|
||||||
import com.v2ray.ang.fmt.HttpFmt
|
import com.v2ray.ang.fmt.HttpFmt
|
||||||
import com.v2ray.ang.fmt.Hysteria2Fmt
|
|
||||||
import com.v2ray.ang.fmt.ShadowsocksFmt
|
import com.v2ray.ang.fmt.ShadowsocksFmt
|
||||||
import com.v2ray.ang.fmt.SocksFmt
|
import com.v2ray.ang.fmt.SocksFmt
|
||||||
import com.v2ray.ang.fmt.TrojanFmt
|
import com.v2ray.ang.fmt.TrojanFmt
|
||||||
@@ -53,6 +54,27 @@ object V2rayConfigManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a V2ray configuration from multiple server profiles.
|
||||||
|
*
|
||||||
|
* @param context The context of the caller.
|
||||||
|
* @param guidList A list of server GUIDs to be included in the generated configuration.
|
||||||
|
* Each GUID represents a unique server profile stored in the system.
|
||||||
|
* @return A V2rayConfig object containing the combined configuration of all specified servers,
|
||||||
|
* or null if the operation fails (e.g., no valid configurations found, parsing errors)
|
||||||
|
*/
|
||||||
|
fun genV2rayConfig(context: Context, guidList: List<String>): V2rayConfig? {
|
||||||
|
try {
|
||||||
|
val configList = guidList.mapNotNull { guid ->
|
||||||
|
MmkvManager.decodeServerConfig(guid)
|
||||||
|
}
|
||||||
|
return genV2rayMultipleConfig(context, configList)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(AppConfig.TAG, "Failed to generate V2ray config", e)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the speedtest V2ray configuration for the given GUID.
|
* Retrieves the speedtest V2ray configuration for the given GUID.
|
||||||
*
|
*
|
||||||
@@ -98,7 +120,7 @@ object V2rayConfigManager {
|
|||||||
val result = ConfigResult(false)
|
val result = ConfigResult(false)
|
||||||
|
|
||||||
val address = config.server ?: return result
|
val address = config.server ?: return result
|
||||||
if (!Utils.isIpAddress(address)) {
|
if (!Utils.isPureIpAddress(address)) {
|
||||||
if (!Utils.isValidUrl(address)) {
|
if (!Utils.isValidUrl(address)) {
|
||||||
Log.w(AppConfig.TAG, "$address is an invalid ip or domain")
|
Log.w(AppConfig.TAG, "$address is an invalid ip or domain")
|
||||||
return result
|
return result
|
||||||
@@ -132,7 +154,10 @@ object V2rayConfigManager {
|
|||||||
v2rayConfig.policy = null
|
v2rayConfig.policy = null
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveOutboundDomainsToHosts(v2rayConfig)
|
//Resolve and add to DNS Hosts
|
||||||
|
if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") == "1") {
|
||||||
|
resolveOutboundDomainsToHosts(v2rayConfig)
|
||||||
|
}
|
||||||
|
|
||||||
result.status = true
|
result.status = true
|
||||||
result.content = JsonUtil.toJsonPretty(v2rayConfig) ?: ""
|
result.content = JsonUtil.toJsonPretty(v2rayConfig) ?: ""
|
||||||
@@ -140,6 +165,80 @@ object V2rayConfigManager {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun genV2rayMultipleConfig(context: Context, configList: List<ProfileItem>): V2rayConfig? {
|
||||||
|
val validConfigs = configList.asSequence().filter { it.server.isNotNullEmpty() }
|
||||||
|
.filter { !Utils.isPureIpAddress(it.server!!) || Utils.isValidUrl(it.server!!) }
|
||||||
|
.filter { it.configType != EConfigType.CUSTOM }
|
||||||
|
.filter { it.configType != EConfigType.HYSTERIA2 }
|
||||||
|
.filter { config ->
|
||||||
|
if (config.subscriptionId.isEmpty()) {
|
||||||
|
return@filter true
|
||||||
|
}
|
||||||
|
val subItem = MmkvManager.decodeSubscription(config.subscriptionId)
|
||||||
|
if (subItem?.intelligentSelectionFilter.isNullOrEmpty() || config.remarks.isEmpty()) {
|
||||||
|
return@filter true
|
||||||
|
}
|
||||||
|
Regex(pattern = subItem?.intelligentSelectionFilter!!).containsMatchIn(input = config.remarks)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
if (validConfigs.isEmpty()) {
|
||||||
|
Log.w(AppConfig.TAG, "All configs are invalid")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val v2rayConfig = initV2rayConfig(context) ?: return null
|
||||||
|
v2rayConfig.log.loglevel = MmkvManager.decodeSettingsString(AppConfig.PREF_LOGLEVEL) ?: "warning"
|
||||||
|
|
||||||
|
val subIds = configList.map { it.subscriptionId }.toHashSet()
|
||||||
|
val remarks = if (subIds.size == 1 && subIds.first().isNotEmpty()) {
|
||||||
|
val sub = MmkvManager.decodeSubscription(subIds.first())
|
||||||
|
(sub?.remarks ?: "") + context.getString(R.string.intelligent_selection)
|
||||||
|
} else {
|
||||||
|
context.getString(R.string.intelligent_selection)
|
||||||
|
}
|
||||||
|
|
||||||
|
v2rayConfig.remarks = remarks
|
||||||
|
|
||||||
|
getInbounds(v2rayConfig)
|
||||||
|
|
||||||
|
v2rayConfig.outbounds.removeAt(0)
|
||||||
|
val outboundsList = mutableListOf<V2rayConfig.OutboundBean>()
|
||||||
|
var index = 0
|
||||||
|
for (config in validConfigs) {
|
||||||
|
index++
|
||||||
|
val outbound = convertProfile2Outbound(config) ?: continue
|
||||||
|
val ret = updateOutboundWithGlobalSettings(outbound)
|
||||||
|
if (!ret) continue
|
||||||
|
outbound.tag = "proxy-$index"
|
||||||
|
outboundsList.add(outbound)
|
||||||
|
}
|
||||||
|
outboundsList.addAll(v2rayConfig.outbounds)
|
||||||
|
v2rayConfig.outbounds = ArrayList(outboundsList)
|
||||||
|
|
||||||
|
getRouting(v2rayConfig)
|
||||||
|
|
||||||
|
getFakeDns(v2rayConfig)
|
||||||
|
|
||||||
|
getDns(v2rayConfig)
|
||||||
|
|
||||||
|
getBalance(v2rayConfig)
|
||||||
|
|
||||||
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) {
|
||||||
|
getCustomLocalDns(v2rayConfig)
|
||||||
|
}
|
||||||
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_SPEED_ENABLED) != true) {
|
||||||
|
v2rayConfig.stats = null
|
||||||
|
v2rayConfig.policy = null
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resolve and add to DNS Hosts
|
||||||
|
if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") == "1") {
|
||||||
|
resolveOutboundDomainsToHosts(v2rayConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v2rayConfig
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the normal V2ray configuration for speedtest.
|
* Retrieves the normal V2ray configuration for speedtest.
|
||||||
*
|
*
|
||||||
@@ -152,7 +251,7 @@ object V2rayConfigManager {
|
|||||||
val result = ConfigResult(false)
|
val result = ConfigResult(false)
|
||||||
|
|
||||||
val address = config.server ?: return result
|
val address = config.server ?: return result
|
||||||
if (!Utils.isIpAddress(address)) {
|
if (!Utils.isPureIpAddress(address)) {
|
||||||
if (!Utils.isValidUrl(address)) {
|
if (!Utils.isValidUrl(address)) {
|
||||||
Log.w(AppConfig.TAG, "$address is an invalid ip or domain")
|
Log.w(AppConfig.TAG, "$address is an invalid ip or domain")
|
||||||
return result
|
return result
|
||||||
@@ -479,6 +578,25 @@ object V2rayConfigManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//block dns
|
||||||
|
val blkDomain = getUserRule2Domain(AppConfig.TAG_BLOCKED)
|
||||||
|
if (blkDomain.isNotEmpty()) {
|
||||||
|
hosts.putAll(blkDomain.map { it to AppConfig.LOOPBACK })
|
||||||
|
}
|
||||||
|
|
||||||
|
// hardcode googleapi rule to fix play store problems
|
||||||
|
hosts[AppConfig.GOOGLEAPIS_CN_DOMAIN] = AppConfig.GOOGLEAPIS_COM_DOMAIN
|
||||||
|
|
||||||
|
// hardcode popular Android Private DNS rule to fix localhost DNS problem
|
||||||
|
hosts[AppConfig.DNS_ALIDNS_DOMAIN] = AppConfig.DNS_ALIDNS_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_CLOUDFLARE_ONE_DOMAIN] = AppConfig.DNS_CLOUDFLARE_ONE_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_CLOUDFLARE_DNS_COM_DOMAIN] = AppConfig.DNS_CLOUDFLARE_DNS_COM_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_CLOUDFLARE_DNS_DOMAIN] = AppConfig.DNS_CLOUDFLARE_DNS_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_DNSPOD_DOMAIN] = AppConfig.DNS_DNSPOD_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_GOOGLE_DOMAIN] = AppConfig.DNS_GOOGLE_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_QUAD9_DOMAIN] = AppConfig.DNS_QUAD9_ADDRESSES
|
||||||
|
hosts[AppConfig.DNS_YANDEX_DOMAIN] = AppConfig.DNS_YANDEX_ADDRESSES
|
||||||
|
|
||||||
//User DNS hosts
|
//User DNS hosts
|
||||||
try {
|
try {
|
||||||
val userHosts = MmkvManager.decodeSettingsString(AppConfig.PREF_DNS_HOSTS)
|
val userHosts = MmkvManager.decodeSettingsString(AppConfig.PREF_DNS_HOSTS)
|
||||||
@@ -493,24 +611,6 @@ object V2rayConfigManager {
|
|||||||
Log.e(AppConfig.TAG, "Failed to configure user DNS hosts", e)
|
Log.e(AppConfig.TAG, "Failed to configure user DNS hosts", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
//block dns
|
|
||||||
val blkDomain = getUserRule2Domain(AppConfig.TAG_BLOCKED)
|
|
||||||
if (blkDomain.isNotEmpty()) {
|
|
||||||
hosts.putAll(blkDomain.map { it to AppConfig.LOOPBACK })
|
|
||||||
}
|
|
||||||
|
|
||||||
// hardcode googleapi rule to fix play store problems
|
|
||||||
hosts[AppConfig.GOOGLEAPIS_CN_DOMAIN] = AppConfig.GOOGLEAPIS_COM_DOMAIN
|
|
||||||
|
|
||||||
// hardcode popular Android Private DNS rule to fix localhost DNS problem
|
|
||||||
hosts[AppConfig.DNS_ALIDNS_DOMAIN] = AppConfig.DNS_ALIDNS_ADDRESSES
|
|
||||||
hosts[AppConfig.DNS_CLOUDFLARE_DOMAIN] = AppConfig.DNS_CLOUDFLARE_ADDRESSES
|
|
||||||
hosts[AppConfig.DNS_DNSPOD_DOMAIN] = AppConfig.DNS_DNSPOD_ADDRESSES
|
|
||||||
hosts[AppConfig.DNS_GOOGLE_DOMAIN] = AppConfig.DNS_GOOGLE_ADDRESSES
|
|
||||||
hosts[AppConfig.DNS_QUAD9_DOMAIN] = AppConfig.DNS_QUAD9_ADDRESSES
|
|
||||||
hosts[AppConfig.DNS_YANDEX_DOMAIN] = AppConfig.DNS_YANDEX_ADDRESSES
|
|
||||||
|
|
||||||
|
|
||||||
// DNS dns
|
// DNS dns
|
||||||
v2rayConfig.dns = V2rayConfig.DnsBean(
|
v2rayConfig.dns = V2rayConfig.DnsBean(
|
||||||
servers = servers,
|
servers = servers,
|
||||||
@@ -738,6 +838,78 @@ object V2rayConfigManager {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures load balancing settings for the V2ray configuration.
|
||||||
|
*
|
||||||
|
* @param v2rayConfig The V2ray configuration object to be modified with balancing settings
|
||||||
|
*/
|
||||||
|
private fun getBalance(v2rayConfig: V2rayConfig)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
v2rayConfig.routing.rules.forEach { rule ->
|
||||||
|
if (rule.outboundTag == "proxy") {
|
||||||
|
rule.outboundTag = null
|
||||||
|
rule.balancerTag = "proxy-round"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MmkvManager.decodeSettingsString(AppConfig.PREF_INTELLIGENT_SELECTION_METHOD, "0") == "0") {
|
||||||
|
val balancer = V2rayConfig.RoutingBean.BalancerBean(
|
||||||
|
tag = "proxy-round",
|
||||||
|
selector = listOf("proxy-"),
|
||||||
|
strategy = V2rayConfig.RoutingBean.StrategyObject(
|
||||||
|
type = "leastPing"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
v2rayConfig.routing.balancers = listOf(balancer)
|
||||||
|
v2rayConfig.observatory = V2rayConfig.ObservatoryObject(
|
||||||
|
subjectSelector = listOf("proxy-"),
|
||||||
|
probeUrl = MmkvManager.decodeSettingsString(AppConfig.PREF_DELAY_TEST_URL) ?: AppConfig.DELAY_TEST_URL,
|
||||||
|
probeInterval = "3m",
|
||||||
|
enableConcurrency = true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val balancer = V2rayConfig.RoutingBean.BalancerBean(
|
||||||
|
tag = "proxy-round",
|
||||||
|
selector = listOf("proxy-"),
|
||||||
|
strategy = V2rayConfig.RoutingBean.StrategyObject(
|
||||||
|
type = "leastLoad"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
v2rayConfig.routing.balancers = listOf(balancer)
|
||||||
|
v2rayConfig.burstObservatory = V2rayConfig.BurstObservatoryObject(
|
||||||
|
subjectSelector = listOf("proxy-"),
|
||||||
|
pingConfig = V2rayConfig.BurstObservatoryObject.PingConfigObject(
|
||||||
|
destination = MmkvManager.decodeSettingsString(AppConfig.PREF_DELAY_TEST_URL) ?: AppConfig.DELAY_TEST_URL,
|
||||||
|
interval = "5m",
|
||||||
|
sampling = 2,
|
||||||
|
timeout = "30s"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v2rayConfig.routing.domainStrategy == "IPIfNonMatch") {
|
||||||
|
v2rayConfig.routing.rules.add(
|
||||||
|
RulesBean(
|
||||||
|
ip = arrayListOf("0.0.0.0/0", "::/0"),
|
||||||
|
balancerTag = "proxy-round",
|
||||||
|
type = "field"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
v2rayConfig.routing.rules.add(
|
||||||
|
RulesBean(
|
||||||
|
network = "tcp,udp",
|
||||||
|
balancerTag = "proxy-round",
|
||||||
|
type = "field"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(AppConfig.TAG, "Failed to configure balance", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the outbound with fragment settings for traffic optimization.
|
* Updates the outbound with fragment settings for traffic optimization.
|
||||||
*
|
*
|
||||||
@@ -828,7 +1000,11 @@ object V2rayConfigManager {
|
|||||||
for (item in proxyOutboundList) {
|
for (item in proxyOutboundList) {
|
||||||
val domain = item.getServerAddress()
|
val domain = item.getServerAddress()
|
||||||
if (domain.isNullOrEmpty()) continue
|
if (domain.isNullOrEmpty()) continue
|
||||||
if (newHosts.containsKey(domain)) continue
|
|
||||||
|
if (newHosts.containsKey(domain)) {
|
||||||
|
item.ensureSockopt().domainStrategy = if (preferIpv6) "UseIPv6v4" else "UseIPv4v6"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
val resolvedIps = HttpUtil.resolveHostToIP(domain, preferIpv6)
|
val resolvedIps = HttpUtil.resolveHostToIP(domain, preferIpv6)
|
||||||
if (resolvedIps.isNullOrEmpty()) continue
|
if (resolvedIps.isNullOrEmpty()) continue
|
||||||
@@ -1045,7 +1221,15 @@ object V2rayConfigManager {
|
|||||||
fun populateTlsSettings(streamSettings: StreamSettingsBean, profileItem: ProfileItem, sniExt: String?) {
|
fun populateTlsSettings(streamSettings: StreamSettingsBean, profileItem: ProfileItem, sniExt: String?) {
|
||||||
val streamSecurity = profileItem.security.orEmpty()
|
val streamSecurity = profileItem.security.orEmpty()
|
||||||
val allowInsecure = profileItem.insecure == true
|
val allowInsecure = profileItem.insecure == true
|
||||||
val sni = if (profileItem.sni.isNullOrEmpty()) sniExt else profileItem.sni
|
val sni = if (profileItem.sni.isNullOrEmpty()) {
|
||||||
|
when {
|
||||||
|
sniExt.isNotNullEmpty() && Utils.isDomainName(sniExt) -> sniExt
|
||||||
|
profileItem.server.isNotNullEmpty() && Utils.isDomainName(profileItem.server) -> profileItem.server
|
||||||
|
else -> sniExt
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
profileItem.sni
|
||||||
|
}
|
||||||
val fingerprint = profileItem.fingerPrint
|
val fingerprint = profileItem.fingerPrint
|
||||||
val alpns = profileItem.alpn
|
val alpns = profileItem.alpn
|
||||||
val publicKey = profileItem.publicKey
|
val publicKey = profileItem.publicKey
|
||||||
|
|||||||
@@ -25,14 +25,13 @@ class QSTileService : TileService() {
|
|||||||
* @param state The state to set.
|
* @param state The state to set.
|
||||||
*/
|
*/
|
||||||
fun setState(state: Int) {
|
fun setState(state: Int) {
|
||||||
|
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
|
||||||
if (state == Tile.STATE_INACTIVE) {
|
if (state == Tile.STATE_INACTIVE) {
|
||||||
qsTile?.state = Tile.STATE_INACTIVE
|
qsTile?.state = Tile.STATE_INACTIVE
|
||||||
qsTile?.label = getString(R.string.app_name)
|
qsTile?.label = getString(R.string.app_name)
|
||||||
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
|
|
||||||
} else if (state == Tile.STATE_ACTIVE) {
|
} else if (state == Tile.STATE_ACTIVE) {
|
||||||
qsTile?.state = Tile.STATE_ACTIVE
|
qsTile?.state = Tile.STATE_ACTIVE
|
||||||
qsTile?.label = V2RayServiceManager.getRunningServerName()
|
qsTile?.label = V2RayServiceManager.getRunningServerName()
|
||||||
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qsTile?.updateTile()
|
qsTile?.updateTile()
|
||||||
@@ -45,7 +44,11 @@ class QSTileService : TileService() {
|
|||||||
override fun onStartListening() {
|
override fun onStartListening() {
|
||||||
super.onStartListening()
|
super.onStartListening()
|
||||||
|
|
||||||
setState(Tile.STATE_INACTIVE)
|
if (V2RayServiceManager.isRunning()) {
|
||||||
|
setState(Tile.STATE_ACTIVE)
|
||||||
|
} else {
|
||||||
|
setState(Tile.STATE_INACTIVE)
|
||||||
|
}
|
||||||
mMsgReceive = ReceiveMessageHandler(this)
|
mMsgReceive = ReceiveMessageHandler(this)
|
||||||
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
|
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
|
||||||
ContextCompat.registerReceiver(applicationContext, mMsgReceive, mFilter, Utils.receiverFlags())
|
ContextCompat.registerReceiver(applicationContext, mMsgReceive, mFilter, Utils.receiverFlags())
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ object V2RayServiceManager {
|
|||||||
val config = MmkvManager.decodeServerConfig(guid) ?: return
|
val config = MmkvManager.decodeServerConfig(guid) ?: return
|
||||||
if (config.configType != EConfigType.CUSTOM
|
if (config.configType != EConfigType.CUSTOM
|
||||||
&& !Utils.isValidUrl(config.server)
|
&& !Utils.isValidUrl(config.server)
|
||||||
&& !Utils.isIpAddress(config.server)
|
&& !Utils.isPureIpAddress(config.server.orEmpty())
|
||||||
) return
|
) return
|
||||||
// val result = V2rayConfigUtil.getV2rayConfig(context, guid)
|
// val result = V2rayConfigUtil.getV2rayConfig(context, guid)
|
||||||
// if (!result.status) return
|
// if (!result.status) return
|
||||||
|
|||||||
@@ -33,12 +33,7 @@ import java.lang.ref.SoftReference
|
|||||||
class V2RayVpnService : VpnService(), ServiceControl {
|
class V2RayVpnService : VpnService(), ServiceControl {
|
||||||
companion object {
|
companion object {
|
||||||
private const val VPN_MTU = 1500
|
private const val VPN_MTU = 1500
|
||||||
private const val PRIVATE_VLAN4_CLIENT = "10.10.14.1"
|
|
||||||
private const val PRIVATE_VLAN4_ROUTER = "10.10.14.2"
|
|
||||||
private const val PRIVATE_VLAN6_CLIENT = "fc00::10:10:14:1"
|
|
||||||
private const val PRIVATE_VLAN6_ROUTER = "fc00::10:10:14:2"
|
|
||||||
private const val TUN2SOCKS = "libtun2socks.so"
|
private const val TUN2SOCKS = "libtun2socks.so"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var mInterface: ParcelFileDescriptor
|
private lateinit var mInterface: ParcelFileDescriptor
|
||||||
@@ -160,10 +155,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
// If the old interface has exactly the same parameters, use it!
|
// If the old interface has exactly the same parameters, use it!
|
||||||
// Configure a builder while parsing the parameters.
|
// Configure a builder while parsing the parameters.
|
||||||
val builder = Builder()
|
val builder = Builder()
|
||||||
|
val vpnConfig = SettingsManager.getCurrentVpnInterfaceAddressConfig()
|
||||||
//val enableLocalDns = defaultDPreference.getPrefBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
|
//val enableLocalDns = defaultDPreference.getPrefBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
|
||||||
|
|
||||||
builder.setMtu(VPN_MTU)
|
builder.setMtu(VPN_MTU)
|
||||||
builder.addAddress(PRIVATE_VLAN4_CLIENT, 30)
|
builder.addAddress(vpnConfig.ipv4Client, 30)
|
||||||
//builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
|
//builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
|
||||||
val bypassLan = SettingsManager.routingRulesetsBypassLan()
|
val bypassLan = SettingsManager.routingRulesetsBypassLan()
|
||||||
if (bypassLan) {
|
if (bypassLan) {
|
||||||
@@ -176,7 +172,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) {
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) {
|
||||||
builder.addAddress(PRIVATE_VLAN6_CLIENT, 126)
|
builder.addAddress(vpnConfig.ipv6Client, 126)
|
||||||
if (bypassLan) {
|
if (bypassLan) {
|
||||||
builder.addRoute("2000::", 3) //currently only 1/8 of total ipV6 is in use
|
builder.addRoute("2000::", 3) //currently only 1/8 of total ipV6 is in use
|
||||||
builder.addRoute("fc00::", 18) //Xray-core default FakeIPv6 Pool
|
builder.addRoute("fc00::", 18) //Xray-core default FakeIPv6 Pool
|
||||||
@@ -198,25 +194,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
|
|
||||||
builder.setSession(V2RayServiceManager.getRunningServerName())
|
builder.setSession(V2RayServiceManager.getRunningServerName())
|
||||||
|
|
||||||
val selfPackageName = BuildConfig.APPLICATION_ID
|
configurePerAppProxy(builder)
|
||||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY)) {
|
|
||||||
val apps = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
|
||||||
val bypassApps = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS)
|
|
||||||
//process self package
|
|
||||||
if (bypassApps) apps?.add(selfPackageName) else apps?.remove(selfPackageName)
|
|
||||||
apps?.forEach {
|
|
||||||
try {
|
|
||||||
if (bypassApps)
|
|
||||||
builder.addDisallowedApplication(it)
|
|
||||||
else
|
|
||||||
builder.addAllowedApplication(it)
|
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
|
||||||
Log.e(AppConfig.TAG, "Failed to configure app in VPN: ${e.localizedMessage}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
builder.addDisallowedApplication(selfPackageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the old interface since the parameters have been changed.
|
// Close the old interface since the parameters have been changed.
|
||||||
try {
|
try {
|
||||||
@@ -253,6 +231,51 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures per-app proxy rules for the VPN builder.
|
||||||
|
*
|
||||||
|
* - If per-app proxy is not enabled, disallow the VPN service's own package.
|
||||||
|
* - If no apps are selected, disallow the VPN service's own package.
|
||||||
|
* - If bypass mode is enabled, disallow all selected apps (including self).
|
||||||
|
* - If proxy mode is enabled, only allow the selected apps (excluding self).
|
||||||
|
*
|
||||||
|
* @param builder The VPN Builder to configure.
|
||||||
|
*/
|
||||||
|
private fun configurePerAppProxy(builder: Builder) {
|
||||||
|
val selfPackageName = BuildConfig.APPLICATION_ID
|
||||||
|
|
||||||
|
// If per-app proxy is not enabled, disallow the VPN service's own package and return
|
||||||
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY) == false) {
|
||||||
|
builder.addDisallowedApplication(selfPackageName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no apps are selected, disallow the VPN service's own package and return
|
||||||
|
val apps = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
||||||
|
if (apps.isNullOrEmpty()) {
|
||||||
|
builder.addDisallowedApplication(selfPackageName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val bypassApps = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS)
|
||||||
|
// Handle the VPN service's own package according to the mode
|
||||||
|
if (bypassApps) apps.add(selfPackageName) else apps.remove(selfPackageName)
|
||||||
|
|
||||||
|
apps.forEach {
|
||||||
|
try {
|
||||||
|
if (bypassApps) {
|
||||||
|
// In bypass mode, disallow the selected apps
|
||||||
|
builder.addDisallowedApplication(it)
|
||||||
|
} else {
|
||||||
|
// In proxy mode, only allow the selected apps
|
||||||
|
builder.addAllowedApplication(it)
|
||||||
|
}
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
Log.e(AppConfig.TAG, "Failed to configure app in VPN: ${e.localizedMessage}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the tun2socks process.
|
* Runs the tun2socks process.
|
||||||
* Starts the tun2socks process with the appropriate parameters.
|
* Starts the tun2socks process with the appropriate parameters.
|
||||||
@@ -260,9 +283,10 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
private fun runTun2socks() {
|
private fun runTun2socks() {
|
||||||
Log.i(AppConfig.TAG, "Start run $TUN2SOCKS")
|
Log.i(AppConfig.TAG, "Start run $TUN2SOCKS")
|
||||||
val socksPort = SettingsManager.getSocksPort()
|
val socksPort = SettingsManager.getSocksPort()
|
||||||
|
val vpnConfig = SettingsManager.getCurrentVpnInterfaceAddressConfig()
|
||||||
val cmd = arrayListOf(
|
val cmd = arrayListOf(
|
||||||
File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
|
File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
|
||||||
"--netif-ipaddr", PRIVATE_VLAN4_ROUTER,
|
"--netif-ipaddr", vpnConfig.ipv4Router,
|
||||||
"--netif-netmask", "255.255.255.252",
|
"--netif-netmask", "255.255.255.252",
|
||||||
"--socks-server-addr", "$LOOPBACK:${socksPort}",
|
"--socks-server-addr", "$LOOPBACK:${socksPort}",
|
||||||
"--tunmtu", VPN_MTU.toString(),
|
"--tunmtu", VPN_MTU.toString(),
|
||||||
@@ -273,7 +297,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
|
|
||||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6)) {
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6)) {
|
||||||
cmd.add("--netif-ip6addr")
|
cmd.add("--netif-ip6addr")
|
||||||
cmd.add(PRIVATE_VLAN6_ROUTER)
|
cmd.add(vpnConfig.ipv6Router)
|
||||||
}
|
}
|
||||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED)) {
|
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED)) {
|
||||||
val localDnsPort = Utils.parseInt(MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt())
|
val localDnsPort = Utils.parseInt(MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt())
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.v2ray.ang.ui
|
package com.v2ray.ang.ui
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
@@ -9,6 +10,7 @@ import com.v2ray.ang.R
|
|||||||
import com.v2ray.ang.databinding.ActivityCheckUpdateBinding
|
import com.v2ray.ang.databinding.ActivityCheckUpdateBinding
|
||||||
import com.v2ray.ang.dto.CheckUpdateResult
|
import com.v2ray.ang.dto.CheckUpdateResult
|
||||||
import com.v2ray.ang.extension.toast
|
import com.v2ray.ang.extension.toast
|
||||||
|
import com.v2ray.ang.extension.toastError
|
||||||
import com.v2ray.ang.extension.toastSuccess
|
import com.v2ray.ang.extension.toastSuccess
|
||||||
import com.v2ray.ang.handler.MmkvManager
|
import com.v2ray.ang.handler.MmkvManager
|
||||||
import com.v2ray.ang.handler.SpeedtestManager
|
import com.v2ray.ang.handler.SpeedtestManager
|
||||||
@@ -46,11 +48,16 @@ class CheckUpdateActivity : BaseActivity() {
|
|||||||
toast(R.string.update_checking_for_update)
|
toast(R.string.update_checking_for_update)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val result = UpdateCheckerManager.checkForUpdate(includePreRelease)
|
try {
|
||||||
if (result.hasUpdate) {
|
val result = UpdateCheckerManager.checkForUpdate(includePreRelease)
|
||||||
showUpdateDialog(result)
|
if (result.hasUpdate) {
|
||||||
} else {
|
showUpdateDialog(result)
|
||||||
toastSuccess(R.string.update_already_latest_version)
|
} else {
|
||||||
|
toastSuccess(R.string.update_already_latest_version)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(AppConfig.TAG, "Failed to check for updates: ${e.message}")
|
||||||
|
toastError(e.message ?: getString(R.string.toast_failure))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,6 +385,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.intelligent_selection_all -> {
|
||||||
|
mainViewModel.createIntelligentSelectionAll()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
R.id.service_restart -> {
|
R.id.service_restart -> {
|
||||||
restartV2Ray()
|
restartV2Ray()
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
private val localDnsPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_LOCAL_DNS_PORT) }
|
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 vpnDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_VPN_DNS) }
|
||||||
private val vpnBypassLan by lazy { findPreference<ListPreference>(AppConfig.PREF_VPN_BYPASS_LAN) }
|
private val vpnBypassLan by lazy { findPreference<ListPreference>(AppConfig.PREF_VPN_BYPASS_LAN) }
|
||||||
|
private val vpnInterfaceAddress by lazy { findPreference<ListPreference>(AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX) }
|
||||||
|
|
||||||
private val mux by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_MUX_ENABLED) }
|
private val mux by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_MUX_ENABLED) }
|
||||||
private val muxConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_CONCURRENCY) }
|
private val muxConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_CONCURRENCY) }
|
||||||
@@ -249,12 +250,15 @@ class SettingsActivity : BaseActivity() {
|
|||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
AppConfig.PREF_VPN_BYPASS_LAN,
|
AppConfig.PREF_VPN_BYPASS_LAN,
|
||||||
|
AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX,
|
||||||
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||||
AppConfig.PREF_MUX_XUDP_QUIC,
|
AppConfig.PREF_MUX_XUDP_QUIC,
|
||||||
AppConfig.PREF_FRAGMENT_PACKETS,
|
AppConfig.PREF_FRAGMENT_PACKETS,
|
||||||
AppConfig.PREF_LANGUAGE,
|
AppConfig.PREF_LANGUAGE,
|
||||||
AppConfig.PREF_UI_MODE_NIGHT,
|
AppConfig.PREF_UI_MODE_NIGHT,
|
||||||
AppConfig.PREF_LOGLEVEL,
|
AppConfig.PREF_LOGLEVEL,
|
||||||
|
AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD,
|
||||||
|
AppConfig.PREF_INTELLIGENT_SELECTION_METHOD,
|
||||||
AppConfig.PREF_MODE
|
AppConfig.PREF_MODE
|
||||||
).forEach { key ->
|
).forEach { key ->
|
||||||
if (MmkvManager.decodeSettingsString(key) != null) {
|
if (MmkvManager.decodeSettingsString(key) != null) {
|
||||||
@@ -273,7 +277,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
localDnsPort?.isEnabled = vpn
|
localDnsPort?.isEnabled = vpn
|
||||||
vpnDns?.isEnabled = vpn
|
vpnDns?.isEnabled = vpn
|
||||||
vpnBypassLan?.isEnabled = vpn
|
vpnBypassLan?.isEnabled = vpn
|
||||||
vpn
|
vpnInterfaceAddress?.isEnabled = vpn
|
||||||
if (vpn) {
|
if (vpn) {
|
||||||
updateLocalDns(
|
updateLocalDns(
|
||||||
MmkvManager.decodeSettingsBool(
|
MmkvManager.decodeSettingsBool(
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class SubEditActivity : BaseActivity() {
|
|||||||
binding.etRemarks.text = Utils.getEditable(subItem.remarks)
|
binding.etRemarks.text = Utils.getEditable(subItem.remarks)
|
||||||
binding.etUrl.text = Utils.getEditable(subItem.url)
|
binding.etUrl.text = Utils.getEditable(subItem.url)
|
||||||
binding.etFilter.text = Utils.getEditable(subItem.filter)
|
binding.etFilter.text = Utils.getEditable(subItem.filter)
|
||||||
|
binding.etIntelligentSelectionFilter.text = Utils.getEditable(subItem.intelligentSelectionFilter)
|
||||||
binding.chkEnable.isChecked = subItem.enabled
|
binding.chkEnable.isChecked = subItem.enabled
|
||||||
binding.autoUpdateCheck.isChecked = subItem.autoUpdate
|
binding.autoUpdateCheck.isChecked = subItem.autoUpdate
|
||||||
binding.allowInsecureUrl.isChecked = subItem.allowInsecureUrl
|
binding.allowInsecureUrl.isChecked = subItem.allowInsecureUrl
|
||||||
@@ -60,6 +61,7 @@ class SubEditActivity : BaseActivity() {
|
|||||||
binding.etRemarks.text = null
|
binding.etRemarks.text = null
|
||||||
binding.etUrl.text = null
|
binding.etUrl.text = null
|
||||||
binding.etFilter.text = null
|
binding.etFilter.text = null
|
||||||
|
binding.etIntelligentSelectionFilter.text = null
|
||||||
binding.chkEnable.isChecked = true
|
binding.chkEnable.isChecked = true
|
||||||
binding.etPreProfile.text = null
|
binding.etPreProfile.text = null
|
||||||
binding.etNextProfile.text = null
|
binding.etNextProfile.text = null
|
||||||
@@ -75,6 +77,7 @@ class SubEditActivity : BaseActivity() {
|
|||||||
subItem.remarks = binding.etRemarks.text.toString()
|
subItem.remarks = binding.etRemarks.text.toString()
|
||||||
subItem.url = binding.etUrl.text.toString()
|
subItem.url = binding.etUrl.text.toString()
|
||||||
subItem.filter = binding.etFilter.text.toString()
|
subItem.filter = binding.etFilter.text.toString()
|
||||||
|
subItem.intelligentSelectionFilter = binding.etIntelligentSelectionFilter.text.toString()
|
||||||
subItem.enabled = binding.chkEnable.isChecked
|
subItem.enabled = binding.chkEnable.isChecked
|
||||||
subItem.autoUpdate = binding.autoUpdateCheck.isChecked
|
subItem.autoUpdate = binding.autoUpdateCheck.isChecked
|
||||||
subItem.prevProfile = binding.etPreProfile.text.toString()
|
subItem.prevProfile = binding.etPreProfile.text.toString()
|
||||||
|
|||||||
@@ -198,6 +198,21 @@ object Utils {
|
|||||||
return isIpv4Address(value) || isIpv6Address(value)
|
return isIpv4Address(value) || isIpv6Address(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a string is a valid domain name.
|
||||||
|
*
|
||||||
|
* A valid domain name must not be an IP address and must be a valid URL format.
|
||||||
|
*
|
||||||
|
* @param input The string to check.
|
||||||
|
* @return True if the string is a valid domain name, false otherwise.
|
||||||
|
*/
|
||||||
|
fun isDomainName(input: String?): Boolean {
|
||||||
|
if (input.isNullOrEmpty()) return false
|
||||||
|
|
||||||
|
// Must not be an IP address and must be a valid URL format
|
||||||
|
return !isPureIpAddress(input) && isValidUrl(input)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a string is a valid IPv4 address.
|
* Check if a string is a valid IPv4 address.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -384,6 +384,29 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
MmkvManager.encodeServerList(serverList)
|
MmkvManager.encodeServerList(serverList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an intelligent selection configuration containing all currently filtered servers.
|
||||||
|
*/
|
||||||
|
fun createIntelligentSelectionAll() {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val key = AngConfigManager.createIntelligentSelection(
|
||||||
|
getApplication<AngApplication>(),
|
||||||
|
serversCache.map { it.guid }.toList(),
|
||||||
|
subscriptionId
|
||||||
|
)
|
||||||
|
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
if (key.isNullOrEmpty()) {
|
||||||
|
getApplication<AngApplication>().toastError(R.string.toast_failure)
|
||||||
|
} else {
|
||||||
|
getApplication<AngApplication>().toastSuccess(R.string.toast_success)
|
||||||
|
MmkvManager.setSelectServer(key)
|
||||||
|
reloadServerList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes assets.
|
* Initializes assets.
|
||||||
* @param assets The asset manager.
|
* @param assets The asset manager.
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
|||||||
AppConfig.PREF_MODE,
|
AppConfig.PREF_MODE,
|
||||||
AppConfig.PREF_VPN_DNS,
|
AppConfig.PREF_VPN_DNS,
|
||||||
AppConfig.PREF_VPN_BYPASS_LAN,
|
AppConfig.PREF_VPN_BYPASS_LAN,
|
||||||
|
AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX,
|
||||||
AppConfig.PREF_REMOTE_DNS,
|
AppConfig.PREF_REMOTE_DNS,
|
||||||
AppConfig.PREF_DOMESTIC_DNS,
|
AppConfig.PREF_DOMESTIC_DNS,
|
||||||
AppConfig.PREF_DNS_HOSTS,
|
AppConfig.PREF_DNS_HOSTS,
|
||||||
@@ -48,6 +49,8 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
|||||||
AppConfig.PREF_LOCAL_DNS_PORT,
|
AppConfig.PREF_LOCAL_DNS_PORT,
|
||||||
AppConfig.PREF_SOCKS_PORT,
|
AppConfig.PREF_SOCKS_PORT,
|
||||||
AppConfig.PREF_LOGLEVEL,
|
AppConfig.PREF_LOGLEVEL,
|
||||||
|
AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD,
|
||||||
|
AppConfig.PREF_INTELLIGENT_SELECTION_METHOD,
|
||||||
AppConfig.PREF_LANGUAGE,
|
AppConfig.PREF_LANGUAGE,
|
||||||
AppConfig.PREF_UI_MODE_NIGHT,
|
AppConfig.PREF_UI_MODE_NIGHT,
|
||||||
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||||
|
|||||||
@@ -93,6 +93,25 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/padding_spacing_dp16"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sub_setting_intelligent_selection_filter" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/et_intelligent_selection_filter"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
@@ -82,6 +82,10 @@
|
|||||||
android:icon="@drawable/ic_share_24dp"
|
android:icon="@drawable/ic_share_24dp"
|
||||||
android:title="@string/title_export_all"
|
android:title="@string/title_export_all"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/intelligent_selection_all"
|
||||||
|
android:title="@string/title_create_intelligent_selection_all_server"
|
||||||
|
app:showAsAction="never" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/ping_all"
|
android:id="@+id/ping_all"
|
||||||
android:title="@string/title_ping_all_server"
|
android:title="@string/title_ping_all_server"
|
||||||
|
|||||||
@@ -141,6 +141,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">الإعدادات</string>
|
<string name="title_settings">الإعدادات</string>
|
||||||
<string name="title_advanced">إعدادات متقدمة</string>
|
<string name="title_advanced">إعدادات متقدمة</string>
|
||||||
|
<string name="title_core_settings">إعدادات النواة</string>
|
||||||
<string name="title_vpn_settings">إعدادات VPN</string>
|
<string name="title_vpn_settings">إعدادات VPN</string>
|
||||||
<string name="title_pref_per_app_proxy">الوكيل لكل تطبيق</string>
|
<string name="title_pref_per_app_proxy">الوكيل لكل تطبيق</string>
|
||||||
<string name="summary_pref_per_app_proxy">عام: التطبيق المحدد هو وكيل، غير المحدد اتصال مباشر؛ \nوضع التجاوز: التطبيق المحدد متصل مباشرة، غير المحدد وكيل. \nخيار تحديد تطبيق الوكيل تلقائيًا في القائمة</string>
|
<string name="summary_pref_per_app_proxy">عام: التطبيق المحدد هو وكيل، غير المحدد اتصال مباشر؛ \nوضع التجاوز: التطبيق المحدد متصل مباشرة، غير المحدد وكيل. \nخيار تحديد تطبيق الوكيل تلقائيًا في القائمة</string>
|
||||||
@@ -181,6 +182,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (IPv4/v6 فقط)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (IPv4/v6 فقط)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">DNS المحلي (اختياري)</string>
|
<string name="title_pref_domestic_dns">DNS المحلي (اختياري)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -238,6 +241,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">فاصل التحديث التلقائي (بالدقائق، الحد الأدنى للقيمة 15)</string>
|
<string name="title_pref_auto_update_interval">فاصل التحديث التلقائي (بالدقائق، الحد الأدنى للقيمة 15)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">مستوى السجل</string>
|
<string name="title_core_loglevel">مستوى السجل</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound domain pre-resolve method</string>
|
||||||
<string name="title_mode">الوضع</string>
|
<string name="title_mode">الوضع</string>
|
||||||
<string name="title_mode_help">انقر هنا للحصول على مزيد من المساعدة</string>
|
<string name="title_mode_help">انقر هنا للحصول على مزيد من المساعدة</string>
|
||||||
<string name="title_language">اللغة</string>
|
<string name="title_language">اللغة</string>
|
||||||
@@ -265,6 +269,7 @@
|
|||||||
<string name="title_sub_update">تحديث الاشتراك (أول خطوة)</string>
|
<string name="title_sub_update">تحديث الاشتراك (أول خطوة)</string>
|
||||||
<string name="title_ping_all_server">Tcping لجميع الإعدادات</string>
|
<string name="title_ping_all_server">Tcping لجميع الإعدادات</string>
|
||||||
<string name="title_real_ping_all_server"> اختبر جميع الإعدادات (3)</string>
|
<string name="title_real_ping_all_server"> اختبر جميع الإعدادات (3)</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
|
||||||
<string name="title_user_asset_setting">Asset files</string>
|
<string name="title_user_asset_setting">Asset files</string>
|
||||||
<string name="title_sort_by_test_results">الفرز حسب نتائج الاختبار (5)</string>
|
<string name="title_sort_by_test_results">الفرز حسب نتائج الاختبار (5)</string>
|
||||||
<string name="title_filter_config">تصفية ملف التكوين</string>
|
<string name="title_filter_config">تصفية ملف التكوين</string>
|
||||||
@@ -354,4 +359,17 @@
|
|||||||
<item>Not Bypass</item>
|
<item>Not Bypass</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>Do not resolve</item>
|
||||||
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
|
<item>Resolve and replace domain</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Intelligent Selection</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Remarks Intelligent Selection regular filter</string>
|
||||||
|
<string name="title_intelligent_selection_method">Intelligent Selection Method</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Least Ping</item>
|
||||||
|
<item>Least Load</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -139,6 +139,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">সেটিংস</string>
|
<string name="title_settings">সেটিংস</string>
|
||||||
<string name="title_advanced">এডভান্সড সেটিংস</string>
|
<string name="title_advanced">এডভান্সড সেটিংস</string>
|
||||||
|
<string name="title_core_settings">কোর সেটিংস</string>
|
||||||
<string name="title_vpn_settings">VPN সেটিংস</string>
|
<string name="title_vpn_settings">VPN সেটিংস</string>
|
||||||
<string name="title_pref_per_app_proxy">প্রতি-অ্যাপ প্রক্সি</string>
|
<string name="title_pref_per_app_proxy">প্রতি-অ্যাপ প্রক্সি</string>
|
||||||
<string name="summary_pref_per_app_proxy">সাধারণ: চেকড অ্যাপ প্রক্সি, আনচেকড সরাসরি সংযোগ; \nবাইপাস মোড: চেকড অ্যাপ সরাসরি সংযুক্ত, আনচেকড প্রক্সি। \nমেনুতে প্রক্সি অ্যাপ্লিকেশন স্বয়ংক্রিয়ভাবে নির্বাচন করার বিকল্প</string>
|
<string name="summary_pref_per_app_proxy">সাধারণ: চেকড অ্যাপ প্রক্সি, আনচেকড সরাসরি সংযোগ; \nবাইপাস মোড: চেকড অ্যাপ সরাসরি সংযুক্ত, আনচেকড প্রক্সি। \nমেনুতে প্রক্সি অ্যাপ্লিকেশন স্বয়ংক্রিয়ভাবে নির্বাচন করার বিকল্প</string>
|
||||||
@@ -181,6 +182,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (শুধুমাত্র IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (শুধুমাত্র IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">ঘরোয়া DNS (ঐচ্ছিক)</string>
|
<string name="title_pref_domestic_dns">ঘরোয়া DNS (ঐচ্ছিক)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -238,6 +241,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">অটো আপডেট ইন্টারভ্যাল (মিনিট, সর্বনিম্ন মান ১৫)</string>
|
<string name="title_pref_auto_update_interval">অটো আপডেট ইন্টারভ্যাল (মিনিট, সর্বনিম্ন মান ১৫)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">লগ স্তর</string>
|
<string name="title_core_loglevel">লগ স্তর</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound domain pre-resolve method</string>
|
||||||
<string name="title_mode">মোড</string>
|
<string name="title_mode">মোড</string>
|
||||||
<string name="title_mode_help">আরো সাহায্যের জন্য ক্লিক করুন</string>
|
<string name="title_mode_help">আরো সাহায্যের জন্য ক্লিক করুন</string>
|
||||||
<string name="title_language">ভাষা</string>
|
<string name="title_language">ভাষা</string>
|
||||||
@@ -265,6 +269,7 @@
|
|||||||
<string name="title_sub_update">সাবস্ক্রিপশন আপডেট</string>
|
<string name="title_sub_update">সাবস্ক্রিপশন আপডেট</string>
|
||||||
<string name="title_ping_all_server">সব কনফিগারেশন TCPing</string>
|
<string name="title_ping_all_server">সব কনফিগারেশন TCPing</string>
|
||||||
<string name="title_real_ping_all_server">সব কনফিগারেশন প্রকৃত বিলম্ব</string>
|
<string name="title_real_ping_all_server">সব কনফিগারেশন প্রকৃত বিলম্ব</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
|
||||||
<string name="title_user_asset_setting">Asset files</string>
|
<string name="title_user_asset_setting">Asset files</string>
|
||||||
<string name="title_sort_by_test_results">টেস্ট ফলাফল দ্বারা সাজানো</string>
|
<string name="title_sort_by_test_results">টেস্ট ফলাফল দ্বারা সাজানো</string>
|
||||||
<string name="title_filter_config">কনফিগারেশন ফাইল ফিল্টার করুন</string>
|
<string name="title_filter_config">কনফিগারেশন ফাইল ফিল্টার করুন</string>
|
||||||
@@ -359,4 +364,17 @@
|
|||||||
<item>Not Bypass</item>
|
<item>Not Bypass</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>Do not resolve</item>
|
||||||
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
|
<item>Resolve and replace domain</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Intelligent Selection</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Remarks Intelligent Selection regular filter</string>
|
||||||
|
<string name="title_intelligent_selection_method">Intelligent Selection Method</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Least Ping</item>
|
||||||
|
<item>Least Load</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -140,6 +140,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">سامووا</string>
|
<string name="title_settings">سامووا</string>
|
||||||
<string name="title_advanced">سامووا پؽش رئڌه</string>
|
<string name="title_advanced">سامووا پؽش رئڌه</string>
|
||||||
|
<string name="title_core_settings">سامووا هسته</string>
|
||||||
<string name="title_vpn_settings">سامووا VPN</string>
|
<string name="title_vpn_settings">سامووا VPN</string>
|
||||||
<string name="title_pref_per_app_proxy">پروکسی و ری برنومه</string>
|
<string name="title_pref_per_app_proxy">پروکسی و ری برنومه</string>
|
||||||
<string name="summary_pref_per_app_proxy">پوی وولاتی: برنومه واجۊری بیڌه پروکسی هڌ، منپیز موستقیم بؽ نشووه هڌ. هالت دور زیڌن: برنومه نشووک ناڌه موستقیمن منپیز هڌ، پروکسی نشووک زیڌه نؽڌ. گۊزینه پسند خوتکار برنومه پروکسی من نومگه</string>
|
<string name="summary_pref_per_app_proxy">پوی وولاتی: برنومه واجۊری بیڌه پروکسی هڌ، منپیز موستقیم بؽ نشووه هڌ. هالت دور زیڌن: برنومه نشووک ناڌه موستقیمن منپیز هڌ، پروکسی نشووک زیڌه نؽڌ. گۊزینه پسند خوتکار برنومه پروکسی من نومگه</string>
|
||||||
@@ -158,16 +159,16 @@
|
|||||||
<item>گوم زیڌن</item>
|
<item>گوم زیڌن</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="title_pref_speed_enabled">ر وندن نشۉݩ داڌن سورعت</string>
|
<string name="title_pref_speed_enabled">ر وندن نشووݩ داڌن سورعت</string>
|
||||||
<string name="summary_pref_speed_enabled">نشۉݩ داڌن سورعت هیم سکویی من وارسۊویا. نماڌ وارسۊوی و ری و کار گرؽڌن آلشت ابۊ.</string>
|
<string name="summary_pref_speed_enabled">نشووݩ داڌن سورعت هیم سکویی من وارسۊویا. نماڌ وارسۊوی و ری و کار گرؽڌن آلشت ابۊ.</string>
|
||||||
|
|
||||||
<string name="title_pref_sniffing_enabled">ر وندن Sniffing</string>
|
<string name="title_pref_sniffing_enabled">ر وندن Sniffing</string>
|
||||||
<string name="summary_pref_sniffing_enabled">دامنه sniff ن ز کتن امتهۉݩ کۊنین (پؽش فرز رۊشن)</string>
|
<string name="summary_pref_sniffing_enabled">دامنه sniff ن ز کتن امتهووݩ کۊنین (پؽش فرز رۊشن)</string>
|
||||||
<string name="title_pref_route_only_enabled">ر وندن routeOnly</string>
|
<string name="title_pref_route_only_enabled">ر وندن routeOnly</string>
|
||||||
<string name="summary_pref_route_only_enabled">ز نوم دامنه sniffed تینا سی تور جوستن استفاڌه کۊنین وو نشۊوی مۉرد نزرن و عونوان نشۊوی IP ووردارین.</string>
|
<string name="summary_pref_route_only_enabled">ز نوم دامنه sniffed تینا سی تور جوستن استفاڌه کۊنین وو نشۊوی موورد نزرن و عونوان نشۊوی IP ووردارین.</string>
|
||||||
|
|
||||||
<string name="title_pref_local_dns_enabled">ر وندن DNS مهلی</string>
|
<string name="title_pref_local_dns_enabled">ر وندن DNS مهلی</string>
|
||||||
<string name="summary_pref_local_dns_enabled">DNS پردازشت وابیڌه و دس هسته ماژول DNS (پؽشنهاڌ ابۊ، ٱر نیاز هڌ ک جوستن تور وو ولات ٱسلین دور زنی)</string>
|
<string name="summary_pref_local_dns_enabled">درخاستا DNS و هسته و من ایان وو و دست ماژول DNS پردازشت ابۊن (پؽشنهاڌ ابۊ ٱر لنگ تور جوستن سی دور زیڌن نشۊویا LAN وو وولات ٱسلی هڌین فعال بۊ)</string>
|
||||||
|
|
||||||
<string name="title_pref_fake_dns_enabled">ر وندن DNS جئلی</string>
|
<string name="title_pref_fake_dns_enabled">ر وندن DNS جئلی</string>
|
||||||
<string name="summary_pref_fake_dns_enabled">DNS مهلی نشۊویا IP جئلی ن وورگنه (زل تر، ٱما گاشڌ من یقرد ز برنومه یل کار نکونه)</string>
|
<string name="summary_pref_fake_dns_enabled">DNS مهلی نشۊویا IP جئلی ن وورگنه (زل تر، ٱما گاشڌ من یقرد ز برنومه یل کار نکونه)</string>
|
||||||
@@ -181,6 +182,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (تینا IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (تینا IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">VPN ز شبکه مهلی اگوڌرته؟</string>
|
<string name="title_pref_vpn_bypass_lan">VPN ز شبکه مهلی اگوڌرته؟</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">نشۊوی رابت VPN</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">DNS منی (اختیاری)</string>
|
<string name="title_pref_domestic_dns">DNS منی (اختیاری)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -204,20 +207,20 @@
|
|||||||
<string name="summary_pref_local_dns_port">پورت DNS مهلی</string>
|
<string name="summary_pref_local_dns_port">پورت DNS مهلی</string>
|
||||||
|
|
||||||
<string name="title_pref_confirm_remove">قوۊل کردن پاک کردن کانفیگ</string>
|
<string name="title_pref_confirm_remove">قوۊل کردن پاک کردن کانفیگ</string>
|
||||||
<string name="summary_pref_confirm_remove">سی پاک وابیڌن فایل کانفیگ نیاز به قوۊل کردن دووارته ز سمت منتور هڌ</string>
|
<string name="summary_pref_confirm_remove">سی پاک وابیڌن فایل کانفیگ نیاز به قوۊل کردن دووارته ز سمت منتور هڌ.</string>
|
||||||
|
|
||||||
<string name="title_pref_start_scan_immediate">زی اسکنن ر ون</string>
|
<string name="title_pref_start_scan_immediate">زی اسکنن ر ون</string>
|
||||||
<string name="summary_pref_start_scan_immediate">شؽواتگرن سی اسکن، زی مجال ر وندن بۊگۊشین، اندی ترین کودن اسکن کۊنین یا شؽواتی ن منه نوار ٱوزار پسند کۊنین.</string>
|
<string name="summary_pref_start_scan_immediate">شؽواتگرن سی اسکن، زی مجال ر وندن بۊگۊشین، ٱندی ترین کودن اسکن کۊنین یا شؽواتی ن منه نوار ٱوزار پسند کۊنین.</string>
|
||||||
|
|
||||||
<string name="title_pref_append_http_proxy">پروکسی HTTP ن و VPN ازاف کۊنین</string>
|
<string name="title_pref_append_http_proxy">پروکسی HTTP ن و VPN ازاف کۊنین</string>
|
||||||
<string name="summary_pref_append_http_proxy">پروکسی HTTP ن موسقیمن ز (مۊرۊرگر/ی قرد ز برنومه یل لادراری بیڌه)، بؽ استفاڌه ز دسگا NIC مجازی (Android 10+) استفاڌه ابۊ.</string>
|
<string name="summary_pref_append_http_proxy">پروکسی HTTP ن موسقیمن ز (مۊرۊرگر/ی قرد ز برنومه یل لادراری بیڌه)، بؽ استفاڌه ز دسگا NIC مجازی (Android 10+) استفاڌه ابۊ.</string>
|
||||||
|
|
||||||
<string name="title_pref_double_column_display">ر وندن نشۉݩ داڌن دو سۊتۊنی</string>
|
<string name="title_pref_double_column_display">ر وندن نشووݩ داڌن دو سۊتۊنی</string>
|
||||||
<string name="summary_pref_double_column_display">نومگه نمایه یل من دو سۊتۊن نشۉݩ داڌه ابۊن وو چینۉ ترین موئتوا بیشتری ن سیل کۊنین. سی ر وستن وا برنومه ن ز نۊ ر ونین.</string>
|
<string name="summary_pref_double_column_display">نومگه نمایه یل من دو سۊتۊن نشووݩ داڌه ابۊن وو چینۉ ترین موئتوا بیشتری ن سیل کۊنین. سی ر وستن، وا برنومه ن ز نۊ ر ونین.</string>
|
||||||
|
|
||||||
<!-- AboutActivity -->
|
<!-- AboutActivity -->
|
||||||
<string name="title_pref_feedback">فشناڌن منشڌ</string>
|
<string name="title_pref_feedback">فشناڌن منشڌ</string>
|
||||||
<string name="summary_pref_feedback">فشناڌن منشڌ یا داسوو موشکلا من Github</string>
|
<string name="summary_pref_feedback">فشناڌن منشڌ یا داسووݩ موشکلا من Github</string>
|
||||||
<string name="summary_pref_tg_group">ٱووڌن من جرگه تلگرام</string>
|
<string name="summary_pref_tg_group">ٱووڌن من جرگه تلگرام</string>
|
||||||
<string name="toast_tg_app_not_found">برنومه تلگرامن نجوست</string>
|
<string name="toast_tg_app_not_found">برنومه تلگرامن نجوست</string>
|
||||||
<string name="title_privacy_policy">هریم سیخومی</string>
|
<string name="title_privacy_policy">هریم سیخومی</string>
|
||||||
@@ -238,9 +241,10 @@
|
|||||||
<string name="title_pref_auto_update_interval">فاسله ورۊ کردن خوتکار (اقلن وا 15 دؽقه بۊ)</string>
|
<string name="title_pref_auto_update_interval">فاسله ورۊ کردن خوتکار (اقلن وا 15 دؽقه بۊ)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">سئت داسووا</string>
|
<string name="title_core_loglevel">سئت داسووا</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">بارت پؽش هل دامنه دری</string>
|
||||||
<string name="title_mode">هالت</string>
|
<string name="title_mode">هالت</string>
|
||||||
<string name="title_mode_help">سی دووسمندیا وو هیاری بیشتر، ری ای هؽل بزݩ</string>
|
<string name="title_mode_help">سی دووسمندیا وو هیاری بیشتر، ری ای هؽل بزݩ</string>
|
||||||
<string name="title_language">زۉݩ</string>
|
<string name="title_language">زووݩ</string>
|
||||||
<string name="title_ui_settings">سامووا رابت منتوری</string>
|
<string name="title_ui_settings">سامووا رابت منتوری</string>
|
||||||
<string name="title_pref_ui_mode_night">سامووا هالت رابت منتوری</string>
|
<string name="title_pref_ui_mode_night">سامووا هالت رابت منتوری</string>
|
||||||
|
|
||||||
@@ -265,6 +269,7 @@
|
|||||||
<string name="title_sub_update">ورۊ کردن اشتراک جرگه سکویی</string>
|
<string name="title_sub_update">ورۊ کردن اشتراک جرگه سکویی</string>
|
||||||
<string name="title_ping_all_server">Tcping کانفیگا جرگه سکویی</string>
|
<string name="title_ping_all_server">Tcping کانفیگا جرگه سکویی</string>
|
||||||
<string name="title_real_ping_all_server">تئخیر واقعی کانفیگا جرگه سکویی</string>
|
<string name="title_real_ping_all_server">تئخیر واقعی کانفیگا جرگه سکویی</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">وورکل پسند هۊشمند کانفیگ جرگه سکویی</string>
|
||||||
<string name="title_user_asset_setting">فایلا بونچک جوقرافیایی</string>
|
<string name="title_user_asset_setting">فایلا بونچک جوقرافیایی</string>
|
||||||
<string name="title_sort_by_test_results">ترتیب و ری نتیجه یل آزمایش</string>
|
<string name="title_sort_by_test_results">ترتیب و ری نتیجه یل آزمایش</string>
|
||||||
<string name="title_filter_config">فیلتر کردن کانفیگا</string>
|
<string name="title_filter_config">فیلتر کردن کانفیگا</string>
|
||||||
@@ -369,4 +374,17 @@
|
|||||||
<item>دور زیڌه نبۊ</item>
|
<item>دور زیڌه نبۊ</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>هل وو فسل مکۊنین</item>
|
||||||
|
<item>هل وو ٱووردن و میزبووݩ یل دامنه DNS</item>
|
||||||
|
<item>هل وو جایونی دامنه</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">پسند هۊشمند</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">گوڌنا دیاری پسند هۊشمند فیلتر مئمۊلی</string>
|
||||||
|
<string name="title_intelligent_selection_method">بارت پسند هۊشمند</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>بلم ترین پینگ</item>
|
||||||
|
<item>هدقل بار</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -137,6 +137,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">تنظیمات</string>
|
<string name="title_settings">تنظیمات</string>
|
||||||
<string name="title_advanced">تنظیمات پیشرفته</string>
|
<string name="title_advanced">تنظیمات پیشرفته</string>
|
||||||
|
<string name="title_core_settings">تنظیمات هسته</string>
|
||||||
<string name="title_vpn_settings">تنظیمات VPN</string>
|
<string name="title_vpn_settings">تنظیمات VPN</string>
|
||||||
<string name="title_pref_per_app_proxy">پروکسی به تفکیک برنامه</string>
|
<string name="title_pref_per_app_proxy">پروکسی به تفکیک برنامه</string>
|
||||||
<string name="summary_pref_per_app_proxy">عمومی: برنامه انتخاب شده از طریق یک پروکسی متصل می شود، برنامه انتخاب نشده مستقیماً متصل می شود. \nحالت دور زدن: برنامه انتخاب شده مستقیماً متصل می شود، برنامه انتخاب نشده از طریق یک پروکسی متصل می شود. \nانتخاب خودکار برنامه های پراکسی در منو امکان پذیر است.</string>
|
<string name="summary_pref_per_app_proxy">عمومی: برنامه انتخاب شده از طریق یک پروکسی متصل می شود، برنامه انتخاب نشده مستقیماً متصل می شود. \nحالت دور زدن: برنامه انتخاب شده مستقیماً متصل می شود، برنامه انتخاب نشده از طریق یک پروکسی متصل می شود. \nانتخاب خودکار برنامه های پراکسی در منو امکان پذیر است.</string>
|
||||||
@@ -179,6 +180,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (فقط IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (فقط IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">آیا VPN از شبکه محلی عبور می کند؟</string>
|
<string name="title_pref_vpn_bypass_lan">آیا VPN از شبکه محلی عبور می کند؟</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">DNS داخلی (اختیاری)</string>
|
<string name="title_pref_domestic_dns">DNS داخلی (اختیاری)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -235,6 +238,7 @@
|
|||||||
<string name="summary_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_pref_auto_update_interval">فاصله به روزرسانی خودکار ( حداقل مقدار ، 15 دقیقه )</string>
|
||||||
<string name="title_core_loglevel">سطح گزارشات</string>
|
<string name="title_core_loglevel">سطح گزارشات</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound domain pre-resolve method</string>
|
||||||
<string name="title_mode">حالت</string>
|
<string name="title_mode">حالت</string>
|
||||||
<string name="title_mode_help">برای اطلاعات و راهنمایی بیشتر، روی این متن کلیک کنید</string>
|
<string name="title_mode_help">برای اطلاعات و راهنمایی بیشتر، روی این متن کلیک کنید</string>
|
||||||
<string name="title_language">زبان</string>
|
<string name="title_language">زبان</string>
|
||||||
@@ -262,6 +266,7 @@
|
|||||||
<string name="title_sub_update">بهروزرسانی گروه فعلی اشتراک</string>
|
<string name="title_sub_update">بهروزرسانی گروه فعلی اشتراک</string>
|
||||||
<string name="title_ping_all_server">TCPING کانفیگ های گروه فعلی</string>
|
<string name="title_ping_all_server">TCPING کانفیگ های گروه فعلی</string>
|
||||||
<string name="title_real_ping_all_server">تاخیر واقعی کانفیگ های گروه فعلی</string>
|
<string name="title_real_ping_all_server">تاخیر واقعی کانفیگ های گروه فعلی</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
|
||||||
<string name="title_user_asset_setting">فایل های منبع جغرافیایی</string>
|
<string name="title_user_asset_setting">فایل های منبع جغرافیایی</string>
|
||||||
<string name="title_sort_by_test_results">مرتب سازی بر اساس نتایج آزمایش</string>
|
<string name="title_sort_by_test_results">مرتب سازی بر اساس نتایج آزمایش</string>
|
||||||
<string name="title_filter_config">فیلتر کردن کانفیگها</string>
|
<string name="title_filter_config">فیلتر کردن کانفیگها</string>
|
||||||
@@ -368,4 +373,17 @@
|
|||||||
<item>دور زده نشود</item>
|
<item>دور زده نشود</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>Do not resolve</item>
|
||||||
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
|
<item>Resolve and replace domain</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Intelligent Selection</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Remarks Intelligent Selection regular filter</string>
|
||||||
|
<string name="title_intelligent_selection_method">Intelligent Selection Method</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Least Ping</item>
|
||||||
|
<item>Least Load</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -139,6 +139,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">Настройки</string>
|
<string name="title_settings">Настройки</string>
|
||||||
<string name="title_advanced">Расширенные настройки</string>
|
<string name="title_advanced">Расширенные настройки</string>
|
||||||
|
<string name="title_core_settings">Настройки ядра</string>
|
||||||
<string name="title_vpn_settings">Настройки VPN</string>
|
<string name="title_vpn_settings">Настройки VPN</string>
|
||||||
<string name="title_pref_per_app_proxy">Прокси для выбранных приложений</string>
|
<string name="title_pref_per_app_proxy">Прокси для выбранных приложений</string>
|
||||||
<string name="summary_pref_per_app_proxy">Основной: выбранное приложение соединяется через прокси, не выбранное — напрямую;\nРежим обхода: выбранное приложение соединяется напрямую, не выбранное — через прокси.\nЕсть возможность автоматического выбора проксируемых приложений в меню.</string>
|
<string name="summary_pref_per_app_proxy">Основной: выбранное приложение соединяется через прокси, не выбранное — напрямую;\nРежим обхода: выбранное приложение соединяется напрямую, не выбранное — через прокси.\nЕсть возможность автоматического выбора проксируемых приложений в меню.</string>
|
||||||
@@ -152,9 +153,9 @@
|
|||||||
<string name="title_pref_mux_xudp_concurency">XUDP-соединения (диапазон от 1 до 1024)</string>
|
<string name="title_pref_mux_xudp_concurency">XUDP-соединения (диапазон от 1 до 1024)</string>
|
||||||
<string name="title_pref_mux_xudp_quic">Обработка QUIC в мультиплексном туннеле</string>
|
<string name="title_pref_mux_xudp_quic">Обработка QUIC в мультиплексном туннеле</string>
|
||||||
<string-array name="mux_xudp_quic_entries">
|
<string-array name="mux_xudp_quic_entries">
|
||||||
<item>отклонять</item>
|
<item>Отклонять</item>
|
||||||
<item>разрешать</item>
|
<item>Разрешать</item>
|
||||||
<item>пропускать</item>
|
<item>Пропускать</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="title_pref_speed_enabled">Отображение скорости</string>
|
<string name="title_pref_speed_enabled">Отображение скорости</string>
|
||||||
@@ -178,7 +179,9 @@
|
|||||||
<string name="summary_pref_remote_dns">DNS</string>
|
<string name="summary_pref_remote_dns">DNS</string>
|
||||||
|
|
||||||
<string name="title_pref_vpn_dns">VPN DNS (только IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (только IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">VPN пропускает LAN</string>
|
<string name="title_pref_vpn_bypass_lan">VPN обходит LAN</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN частный IP</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">Внутренняя DNS (необязательно)</string>
|
<string name="title_pref_domestic_dns">Внутренняя DNS (необязательно)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
@@ -237,6 +240,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">Интервал автообновления (минут, не менее 15)</string>
|
<string name="title_pref_auto_update_interval">Интервал автообновления (минут, не менее 15)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">Подробность ведения журнала</string>
|
<string name="title_core_loglevel">Подробность ведения журнала</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Предварительное определение исходящего домена</string>
|
||||||
<string name="title_mode">Режим</string>
|
<string name="title_mode">Режим</string>
|
||||||
<string name="title_mode_help">Нажмите для получения дополнительной информации</string>
|
<string name="title_mode_help">Нажмите для получения дополнительной информации</string>
|
||||||
<string name="title_language">Язык</string>
|
<string name="title_language">Язык</string>
|
||||||
@@ -262,10 +266,11 @@
|
|||||||
<string name="sub_setting_next_profile">Следующая конфигурация прокси</string>
|
<string name="sub_setting_next_profile">Следующая конфигурация прокси</string>
|
||||||
<string name="sub_setting_pre_profile_tip">Конфигурация должна быть уникальной</string>
|
<string name="sub_setting_pre_profile_tip">Конфигурация должна быть уникальной</string>
|
||||||
<string name="title_sub_update">Обновить подписку группы</string>
|
<string name="title_sub_update">Обновить подписку группы</string>
|
||||||
<string name="title_ping_all_server">Проверка профилей группы</string>
|
<string name="title_ping_all_server">Проверить профили группы</string>
|
||||||
<string name="title_real_ping_all_server">Время отклика профилей группы</string>
|
<string name="title_real_ping_all_server">Время отклика профилей группы</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Создать конфигурацию умного выбора</string>
|
||||||
<string name="title_user_asset_setting">Файлы ресурсов</string>
|
<string name="title_user_asset_setting">Файлы ресурсов</string>
|
||||||
<string name="title_sort_by_test_results">Сортировка по результатам теста</string>
|
<string name="title_sort_by_test_results">Сортировать по результатам теста</string>
|
||||||
<string name="title_filter_config">Фильтр групп</string>
|
<string name="title_filter_config">Фильтр групп</string>
|
||||||
<string name="filter_config_all">Все группы</string>
|
<string name="filter_config_all">Все группы</string>
|
||||||
<string name="title_del_duplicate_config_count">Удалено дубликатов профилей: %d</string>
|
<string name="title_del_duplicate_config_count">Удалено дубликатов профилей: %d</string>
|
||||||
@@ -364,8 +369,21 @@
|
|||||||
|
|
||||||
<string-array name="vpn_bypass_lan">
|
<string-array name="vpn_bypass_lan">
|
||||||
<item>Как в профиле</item>
|
<item>Как в профиле</item>
|
||||||
<item>Пропускает</item>
|
<item>Обходит</item>
|
||||||
<item>Не пропускает</item>
|
<item>Не обходит</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>Не определять</item>
|
||||||
|
<item>Определять и добавлять к узлам DNS</item>
|
||||||
|
<item>Определять и заменять домен</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Умный выбор</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Название фильтра умного выбора</string>
|
||||||
|
<string name="title_intelligent_selection_method">Принцип умного выбора</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Наименьшая задержка</item>
|
||||||
|
<item>Наименьшая нагрузка</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -138,6 +138,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">Cài đặt</string>
|
<string name="title_settings">Cài đặt</string>
|
||||||
<string name="title_advanced">Cài đặt nâng cao</string>
|
<string name="title_advanced">Cài đặt nâng cao</string>
|
||||||
|
<string name="title_core_settings">Cài đặt lõi</string>
|
||||||
<string name="title_vpn_settings">Cài đặt VPN</string>
|
<string name="title_vpn_settings">Cài đặt VPN</string>
|
||||||
<string name="title_pref_per_app_proxy">Proxy theo Ứng dụng</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 chọn sẽ kết nối trực tiếp. \n- Chế độ Bypass: Ứng dụng đã chọn sẽ kết nối trực tiếp, chưa chọn sẽ kết nối qua Proxy. \n- Nếu bạn đang ở Trung Quốc thì vào Menu, chọn Tự động chọn ứng dụng Proxy.</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 chọn sẽ kết nối trực tiếp. \n- Chế độ Bypass: Ứng dụng đã chọn sẽ kết nối trực tiếp, chưa chọn sẽ kết nối qua Proxy. \n- Nếu bạn đang ở Trung Quốc thì vào Menu, chọn Tự động chọn ứng dụng Proxy.</string>
|
||||||
@@ -181,6 +182,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (Chỉ IPv4 / IPv6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (Chỉ IPv4 / IPv6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">DNS nội địa (Không bắt buộc)</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="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -238,6 +241,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">Thời gian cập nhật tự động (Phút, giá trị tối thiểu là 15)</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 là 15)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">Cấp độ nhật ký</string>
|
<string name="title_core_loglevel">Cấp độ nhật ký</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound domain pre-resolve method</string>
|
||||||
<string name="title_mode">Chế độ kết nối</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_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_language">Ngôn ngữ</string>
|
||||||
@@ -265,6 +269,7 @@
|
|||||||
<string name="title_sub_update">Cập nhật các gói đăng ký</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_ping_all_server">Ping tất cả máy chủ</string>
|
||||||
<string name="title_real_ping_all_server">Kiểm tra HTTP tất cả máy chủ</string>
|
<string name="title_real_ping_all_server">Kiểm tra HTTP tất cả máy chủ</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
|
||||||
<string name="title_user_asset_setting">Asset files</string>
|
<string name="title_user_asset_setting">Asset files</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_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="title_filter_config">Lọc cấu hình theo các gói đăng ký</string>
|
||||||
@@ -356,4 +361,17 @@
|
|||||||
<item>Not Bypass</item>
|
<item>Not Bypass</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>Do not resolve</item>
|
||||||
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
|
<item>Resolve and replace domain</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Intelligent Selection</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Remarks Intelligent Selection regular filter</string>
|
||||||
|
<string name="title_intelligent_selection_method">Intelligent Selection Method</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Least Ping</item>
|
||||||
|
<item>Least Load</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -137,6 +137,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">设置</string>
|
<string name="title_settings">设置</string>
|
||||||
<string name="title_advanced">进阶设置</string>
|
<string name="title_advanced">进阶设置</string>
|
||||||
|
<string name="title_core_settings">核心设置</string>
|
||||||
<string name="title_vpn_settings">VPN 设置</string>
|
<string name="title_vpn_settings">VPN 设置</string>
|
||||||
<string name="title_pref_per_app_proxy">分应用</string>
|
<string name="title_pref_per_app_proxy">分应用</string>
|
||||||
<string name="summary_pref_per_app_proxy">常规: 勾选的 App 被代理, 未勾选的直连;\n绕行模式: 勾选的 App 直连, 未勾选的被代理.\n不明白者在菜单中选择自动选中需代理应用</string>
|
<string name="summary_pref_per_app_proxy">常规: 勾选的 App 被代理, 未勾选的直连;\n绕行模式: 勾选的 App 直连, 未勾选的被代理.\n不明白者在菜单中选择自动选中需代理应用</string>
|
||||||
@@ -178,6 +179,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (仅支持 IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (仅支持 IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">VPN 是否绕过局域网</string>
|
<string name="title_pref_vpn_bypass_lan">VPN 是否绕过局域网</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN 接口地址</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">境内 DNS (可选)</string>
|
<string name="title_pref_domestic_dns">境内 DNS (可选)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -235,6 +238,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">自动更新间隔(分钟,最小值 15)</string>
|
<string name="title_pref_auto_update_interval">自动更新间隔(分钟,最小值 15)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">日志级别</string>
|
<string name="title_core_loglevel">日志级别</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound 域名预解析方式</string>
|
||||||
<string name="title_mode">模式</string>
|
<string name="title_mode">模式</string>
|
||||||
<string name="title_mode_help">点此查看更多帮助</string>
|
<string name="title_mode_help">点此查看更多帮助</string>
|
||||||
<string name="title_language">语言</string>
|
<string name="title_language">语言</string>
|
||||||
@@ -262,6 +266,7 @@
|
|||||||
<string name="title_sub_update">更新当前组订阅</string>
|
<string name="title_sub_update">更新当前组订阅</string>
|
||||||
<string name="title_ping_all_server">测试当前组配置 Tcping</string>
|
<string name="title_ping_all_server">测试当前组配置 Tcping</string>
|
||||||
<string name="title_real_ping_all_server">测试当前组配置真连接</string>
|
<string name="title_real_ping_all_server">测试当前组配置真连接</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">生成当前组智能选择配置</string>
|
||||||
<string name="title_user_asset_setting">资源文件</string>
|
<string name="title_user_asset_setting">资源文件</string>
|
||||||
<string name="title_sort_by_test_results">按测试结果排序</string>
|
<string name="title_sort_by_test_results">按测试结果排序</string>
|
||||||
<string name="title_filter_config">过滤配置文件</string>
|
<string name="title_filter_config">过滤配置文件</string>
|
||||||
@@ -360,4 +365,17 @@
|
|||||||
<item>不绕过</item>
|
<item>不绕过</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>不解析</item>
|
||||||
|
<item>解析后添加至 DNS Hosts</item>
|
||||||
|
<item>解析后替换原域名</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">智能选择</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">别名智能选择正则过滤</string>
|
||||||
|
<string name="title_intelligent_selection_method">智能选择方式</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>最低延迟</item>
|
||||||
|
<item>最稳定</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -138,6 +138,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">設定</string>
|
<string name="title_settings">設定</string>
|
||||||
<string name="title_advanced">進階</string>
|
<string name="title_advanced">進階</string>
|
||||||
|
<string name="title_core_settings">核心設定</string>
|
||||||
<string name="title_vpn_settings">VPN 設定</string>
|
<string name="title_vpn_settings">VPN 設定</string>
|
||||||
<string name="title_pref_per_app_proxy">Proxy 個別應用程式</string>
|
<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="summary_pref_per_app_proxy">常規:勾選的 App 啟用 Proxy,未勾選的直接連線;\n繞行模式:勾選的 App 直接連線,未勾選的啟用 Proxy。\n可在選單中選擇自動選中需 Proxy 應用</string>
|
||||||
@@ -180,6 +181,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (僅支援 IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (僅支援 IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">VPN 是否繞過區域網</string>
|
<string name="title_pref_vpn_bypass_lan">VPN 是否繞過區域網</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN 介面位址</string>
|
||||||
|
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
<string name="title_pref_domestic_dns">境内 DNS (可选)</string>
|
<string name="title_pref_domestic_dns">境内 DNS (可选)</string>
|
||||||
<string name="title_pref_dns_hosts">DNS hosts (格式: 網域:位址,…)</string>
|
<string name="title_pref_dns_hosts">DNS hosts (格式: 網域:位址,…)</string>
|
||||||
@@ -236,6 +239,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">自動更新間隔(分鐘,最小值 15)</string>
|
<string name="title_pref_auto_update_interval">自動更新間隔(分鐘,最小值 15)</string>
|
||||||
|
|
||||||
<string name="title_core_loglevel">記錄層級</string>
|
<string name="title_core_loglevel">記錄層級</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound 網域預解析方式</string>
|
||||||
<string name="title_mode">模式</string>
|
<string name="title_mode">模式</string>
|
||||||
<string name="title_mode_help">輕觸以檢視說明</string>
|
<string name="title_mode_help">輕觸以檢視說明</string>
|
||||||
<string name="title_language">語言</string>
|
<string name="title_language">語言</string>
|
||||||
@@ -263,6 +267,7 @@
|
|||||||
<string name="title_sub_update">更新目前群組訂閱</string>
|
<string name="title_sub_update">更新目前群組訂閱</string>
|
||||||
<string name="title_ping_all_server">偵測目前群組設定 Tcping</string>
|
<string name="title_ping_all_server">偵測目前群組設定 Tcping</string>
|
||||||
<string name="title_real_ping_all_server">偵測目前群組設定真延遲</string>
|
<string name="title_real_ping_all_server">偵測目前群組設定真延遲</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
|
||||||
<string name="title_user_asset_setting">資源檔案</string>
|
<string name="title_user_asset_setting">資源檔案</string>
|
||||||
<string name="title_sort_by_test_results">依偵測結果排序</string>
|
<string name="title_sort_by_test_results">依偵測結果排序</string>
|
||||||
<string name="title_filter_config">過濾設定</string>
|
<string name="title_filter_config">過濾設定</string>
|
||||||
@@ -360,4 +365,17 @@
|
|||||||
<item>不繞過</item>
|
<item>不繞過</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>不解析</item>
|
||||||
|
<item>解析後加入 DNS Hosts</item>
|
||||||
|
<item>解析後替換原網域名稱</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Intelligent Selection</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Remarks Intelligent Selection regular filter</string>
|
||||||
|
<string name="title_intelligent_selection_method">Intelligent Selection Method</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Least Ping</item>
|
||||||
|
<item>Least Load</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -182,4 +182,35 @@
|
|||||||
<item>2</item>
|
<item>2</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="vpn_interface_address_value" translatable="false">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>6</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="vpn_interface_address">
|
||||||
|
<item>10.10.14.x</item>
|
||||||
|
<item>10.1.0.x</item>
|
||||||
|
<item>10.0.0.x</item>
|
||||||
|
<item>172.31.0.x</item>
|
||||||
|
<item>172.20.0.x</item>
|
||||||
|
<item>172.16.0.x</item>
|
||||||
|
<item>192.168.100.x</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method_value" translatable="false">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="intelligent_selection_method_value" translatable="false">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -140,6 +140,7 @@
|
|||||||
<!-- Preferences -->
|
<!-- Preferences -->
|
||||||
<string name="title_settings">Settings</string>
|
<string name="title_settings">Settings</string>
|
||||||
<string name="title_advanced">Advanced Settings</string>
|
<string name="title_advanced">Advanced Settings</string>
|
||||||
|
<string name="title_core_settings">Core Settings</string>
|
||||||
<string name="title_vpn_settings">VPN Settings</string>
|
<string name="title_vpn_settings">VPN Settings</string>
|
||||||
<string name="title_pref_per_app_proxy">Per-app proxy</string>
|
<string name="title_pref_per_app_proxy">Per-app proxy</string>
|
||||||
<string name="summary_pref_per_app_proxy">General: Checked apps use proxy, unchecked apps connect directly; \nBypass mode: checked apps connect directly, unchecked apps use proxy. \nThe option to automatically select proxy applications is in the menu</string>
|
<string name="summary_pref_per_app_proxy">General: Checked apps use proxy, unchecked apps connect directly; \nBypass mode: checked apps connect directly, unchecked apps use proxy. \nThe option to automatically select proxy applications is in the menu</string>
|
||||||
@@ -182,6 +183,8 @@
|
|||||||
<string name="title_pref_vpn_dns">VPN DNS (only IPv4/v6)</string>
|
<string name="title_pref_vpn_dns">VPN DNS (only IPv4/v6)</string>
|
||||||
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
|
||||||
|
|
||||||
<string name="title_pref_domestic_dns">Domestic DNS (Optional)</string>
|
<string name="title_pref_domestic_dns">Domestic DNS (Optional)</string>
|
||||||
<string name="summary_pref_domestic_dns">DNS</string>
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
@@ -239,6 +242,7 @@
|
|||||||
<string name="title_pref_auto_update_interval">Auto Update Interval (Minutes, Min value 15)</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_core_loglevel">Log Level</string>
|
||||||
|
<string name="title_outbound_domain_resolve_method">Outbound domain pre-resolve method</string>
|
||||||
<string name="title_mode">Mode</string>
|
<string name="title_mode">Mode</string>
|
||||||
<string name="title_mode_help">Click me for more help</string>
|
<string name="title_mode_help">Click me for more help</string>
|
||||||
<string name="title_language">Language</string>
|
<string name="title_language">Language</string>
|
||||||
@@ -266,6 +270,7 @@
|
|||||||
<string name="title_sub_update">Update current group subscription</string>
|
<string name="title_sub_update">Update current group subscription</string>
|
||||||
<string name="title_ping_all_server">Tcping current group configuration</string>
|
<string name="title_ping_all_server">Tcping current group configuration</string>
|
||||||
<string name="title_real_ping_all_server">Real delay current group configuration</string>
|
<string name="title_real_ping_all_server">Real delay current group configuration</string>
|
||||||
|
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
|
||||||
<string name="title_user_asset_setting">Asset files</string>
|
<string name="title_user_asset_setting">Asset files</string>
|
||||||
<string name="title_sort_by_test_results">Sorting by test results</string>
|
<string name="title_sort_by_test_results">Sorting by test results</string>
|
||||||
<string name="title_filter_config">Filter configuration file</string>
|
<string name="title_filter_config">Filter configuration file</string>
|
||||||
@@ -370,4 +375,17 @@
|
|||||||
<item>Not Bypass</item>
|
<item>Not Bypass</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="outbound_domain_resolve_method">
|
||||||
|
<item>Do not resolve</item>
|
||||||
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
|
<item>Resolve and replace domain</item>
|
||||||
|
</string-array>
|
||||||
|
<string name="intelligent_selection">Intelligent Selection</string>
|
||||||
|
<string name="sub_setting_intelligent_selection_filter">Remarks Intelligent Selection regular filter</string>
|
||||||
|
<string name="title_intelligent_selection_method">Intelligent Selection Method</string>
|
||||||
|
<string-array name="intelligent_selection_method">
|
||||||
|
<item>Least Ping</item>
|
||||||
|
<item>Least Load</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
<PreferenceCategory android:title="@string/title_vpn_settings">
|
<PreferenceCategory android:title="@string/title_vpn_settings">
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="pref_prefer_ipv6"
|
android:key="pref_prefer_ipv6"
|
||||||
android:summary="@string/summary_pref_prefer_ipv6"
|
android:summary="@string/summary_pref_prefer_ipv6"
|
||||||
android:title="@string/title_pref_prefer_ipv6" />
|
android:title="@string/title_pref_prefer_ipv6" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="pref_per_app_proxy"
|
android:key="pref_per_app_proxy"
|
||||||
@@ -62,6 +62,14 @@
|
|||||||
android:key="pref_vpn_bypass_lan"
|
android:key="pref_vpn_bypass_lan"
|
||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/title_pref_vpn_bypass_lan" />
|
android:title="@string/title_pref_vpn_bypass_lan" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:entries="@array/vpn_interface_address"
|
||||||
|
android:entryValues="@array/vpn_interface_address_value"
|
||||||
|
android:key="pref_vpn_interface_address_config_index"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/title_pref_vpn_interface_address" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/title_ui_settings">
|
<PreferenceCategory android:title="@string/title_ui_settings">
|
||||||
@@ -171,9 +179,7 @@
|
|||||||
android:title="@string/title_pref_auto_update_interval" />
|
android:title="@string/title_pref_auto_update_interval" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory android:title="@string/title_core_settings">
|
||||||
android:title="@string/title_advanced"
|
|
||||||
app:initialExpandedChildrenCount="0">
|
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
@@ -208,11 +214,6 @@
|
|||||||
android:summary="@string/summary_pref_dns_hosts"
|
android:summary="@string/summary_pref_dns_hosts"
|
||||||
android:title="@string/title_pref_dns_hosts" />
|
android:title="@string/title_pref_dns_hosts" />
|
||||||
|
|
||||||
<EditTextPreference
|
|
||||||
android:key="pref_delay_test_url"
|
|
||||||
android:summary="@string/summary_pref_delay_test_url"
|
|
||||||
android:title="@string/title_pref_delay_test_url" />
|
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="warning"
|
android:defaultValue="warning"
|
||||||
android:entries="@array/core_loglevel"
|
android:entries="@array/core_loglevel"
|
||||||
@@ -221,6 +222,31 @@
|
|||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/title_core_loglevel" />
|
android:title="@string/title_core_loglevel" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="1"
|
||||||
|
android:entries="@array/outbound_domain_resolve_method"
|
||||||
|
android:entryValues="@array/outbound_domain_resolve_method_value"
|
||||||
|
android:key="pref_outbound_domain_resolve_method"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/title_outbound_domain_resolve_method" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="0"
|
||||||
|
android:entries="@array/intelligent_selection_method"
|
||||||
|
android:entryValues="@array/intelligent_selection_method_value"
|
||||||
|
android:key="pref_intelligent_selection_method"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/title_intelligent_selection_method" />
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/title_advanced">
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="pref_delay_test_url"
|
||||||
|
android:summary="@string/summary_pref_delay_test_url"
|
||||||
|
android:title="@string/title_pref_delay_test_url" />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="VPN"
|
android:defaultValue="VPN"
|
||||||
android:entries="@array/mode_entries"
|
android:entries="@array/mode_entries"
|
||||||
@@ -228,6 +254,7 @@
|
|||||||
android:key="pref_mode"
|
android:key="pref_mode"
|
||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/title_mode" />
|
android:title="@string/title_mode" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
@@ -20,8 +20,8 @@ swiperefreshlayout = "1.1.0"
|
|||||||
toasty = "1.5.2"
|
toasty = "1.5.2"
|
||||||
editorkit = "2.9.0"
|
editorkit = "2.9.0"
|
||||||
core = "3.5.3"
|
core = "3.5.3"
|
||||||
workRuntimeKtx = "2.10.1"
|
workRuntimeKtx = "2.10.2"
|
||||||
lifecycleViewmodelKtx = "2.9.1"
|
lifecycleViewmodelKtx = "2.9.2"
|
||||||
multidex = "2.0.1"
|
multidex = "2.0.1"
|
||||||
mockitoMockitoInline = "5.2.0"
|
mockitoMockitoInline = "5.2.0"
|
||||||
flexbox = "3.0.0"
|
flexbox = "3.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user