feat. Intelligent Selection (#4716)
rename Adds intelligent selection method setting Adds KDoc
This commit is contained in:
@@ -57,6 +57,7 @@ object AppConfig {
|
|||||||
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_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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,6 +16,7 @@ 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.ShadowsocksFmt
|
import com.v2ray.ang.fmt.ShadowsocksFmt
|
||||||
import com.v2ray.ang.fmt.SocksFmt
|
import com.v2ray.ang.fmt.SocksFmt
|
||||||
@@ -52,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.
|
||||||
*
|
*
|
||||||
@@ -142,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.
|
||||||
*
|
*
|
||||||
@@ -741,6 +838,60 @@ 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"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} 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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
AppConfig.PREF_UI_MODE_NIGHT,
|
AppConfig.PREF_UI_MODE_NIGHT,
|
||||||
AppConfig.PREF_LOGLEVEL,
|
AppConfig.PREF_LOGLEVEL,
|
||||||
AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD,
|
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) {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
|||||||
AppConfig.PREF_SOCKS_PORT,
|
AppConfig.PREF_SOCKS_PORT,
|
||||||
AppConfig.PREF_LOGLEVEL,
|
AppConfig.PREF_LOGLEVEL,
|
||||||
AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD,
|
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"
|
||||||
|
|||||||
@@ -98,4 +98,8 @@
|
|||||||
android:id="@+id/sub_update"
|
android:id="@+id/sub_update"
|
||||||
android:title="@string/title_sub_update"
|
android:title="@string/title_sub_update"
|
||||||
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" />
|
||||||
</menu>
|
</menu>
|
||||||
@@ -269,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>
|
||||||
@@ -363,5 +364,12 @@
|
|||||||
<item>Resolve and add to DNS Hosts</item>
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
<item>Resolve and replace domain</item>
|
<item>Resolve and replace domain</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -269,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>
|
||||||
@@ -368,5 +369,12 @@
|
|||||||
<item>Resolve and add to DNS Hosts</item>
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
<item>Resolve and replace domain</item>
|
<item>Resolve and replace domain</item>
|
||||||
</string-array>
|
</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>
|
||||||
@@ -269,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">فایلا بونچک جوقرافیایی</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>
|
||||||
@@ -378,5 +379,12 @@
|
|||||||
<item>هل وو ٱووردن و میزبووݩ یل دامنه DNS</item>
|
<item>هل وو ٱووردن و میزبووݩ یل دامنه DNS</item>
|
||||||
<item>هل وو جایونی دامنه</item>
|
<item>هل وو جایونی دامنه</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -266,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>
|
||||||
@@ -377,5 +378,12 @@
|
|||||||
<item>Resolve and add to DNS Hosts</item>
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
<item>Resolve and replace domain</item>
|
<item>Resolve and replace domain</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -268,6 +268,7 @@
|
|||||||
<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">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>
|
||||||
@@ -377,5 +378,12 @@
|
|||||||
<item>Определять и добавлять к узлам DNS</item>
|
<item>Определять и добавлять к узлам DNS</item>
|
||||||
<item>Определять и заменять домен</item>
|
<item>Определять и заменять домен</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -269,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>
|
||||||
@@ -365,5 +366,12 @@
|
|||||||
<item>Resolve and add to DNS Hosts</item>
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
<item>Resolve and replace domain</item>
|
<item>Resolve and replace domain</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -266,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>
|
||||||
@@ -369,5 +370,12 @@
|
|||||||
<item>解析后添加至 DNS Hosts</item>
|
<item>解析后添加至 DNS Hosts</item>
|
||||||
<item>解析后替换原域名</item>
|
<item>解析后替换原域名</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -267,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>
|
||||||
@@ -369,5 +370,12 @@
|
|||||||
<item>解析後加入 DNS Hosts</item>
|
<item>解析後加入 DNS Hosts</item>
|
||||||
<item>解析後替換原網域名稱</item>
|
<item>解析後替換原網域名稱</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -208,4 +208,9 @@
|
|||||||
<item>2</item>
|
<item>2</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="intelligent_selection_method_value" translatable="false">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -270,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>
|
||||||
@@ -379,5 +380,12 @@
|
|||||||
<item>Resolve and add to DNS Hosts</item>
|
<item>Resolve and add to DNS Hosts</item>
|
||||||
<item>Resolve and replace domain</item>
|
<item>Resolve and replace domain</item>
|
||||||
</string-array>
|
</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>
|
||||||
|
|||||||
@@ -230,6 +230,14 @@
|
|||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/title_outbound_domain_resolve_method" />
|
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>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/title_advanced">
|
<PreferenceCategory android:title="@string/title_advanced">
|
||||||
|
|||||||
Reference in New Issue
Block a user