This commit is contained in:
arm64v8a 2023-03-16 13:41:25 +09:00
parent 48a2776f9c
commit fafe14b7c6
22 changed files with 118 additions and 106 deletions

View File

@ -33,7 +33,7 @@ object Key {
const val RESOLVE_DESTINATION = "resolveDestination" const val RESOLVE_DESTINATION = "resolveDestination"
const val BYPASS_LAN = "bypassLan" const val BYPASS_LAN = "bypassLan"
const val BYPASS_LAN_IN_CORE_ONLY = "bypassLanInCoreOnly" const val BYPASS_LAN_IN_CORE = "bypassLanInCore"
const val MIXED_PORT = "mixedPort" const val MIXED_PORT = "mixedPort"
const val ALLOW_ACCESS = "allowAccess" const val ALLOW_ACCESS = "allowAccess"

View File

@ -42,13 +42,11 @@ class ServiceNotification(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
} }
val trafficStatistics = DataStore.profileTrafficStatistics
val showDirectSpeed = DataStore.showDirectSpeed val showDirectSpeed = DataStore.showDirectSpeed
private val callback: ISagerNetServiceCallback by lazy { private val callback: ISagerNetServiceCallback by lazy {
object : ISagerNetServiceCallback.Stub() { object : ISagerNetServiceCallback.Stub() {
override fun cbSpeedUpdate(stats: SpeedDisplayData) { override fun cbSpeedUpdate(stats: SpeedDisplayData) {
if (!trafficStatistics) return
builder.apply { builder.apply {
if (showDirectSpeed) { if (showDirectSpeed) {
val speedDetail = (service as Context).getString( val speedDetail = (service as Context).getString(
@ -180,7 +178,7 @@ class ServiceNotification(
} }
private fun updateCallback(screenOn: Boolean) { private fun updateCallback(screenOn: Boolean) {
if (!trafficStatistics) return if (DataStore.speedInterval == 0) return
if (screenOn) { if (screenOn) {
service.data.binder.registerCallback(callback) service.data.binder.registerCallback(callback)
callbackRegistered = true callbackRegistered = true

View File

@ -109,7 +109,7 @@ class VpnService : BaseVpnService(),
builder.addDnsServer(PRIVATE_VLAN4_ROUTER) builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
// route // route
if (DataStore.bypassLan && !DataStore.bypassLanInCoreOnly) { if (DataStore.bypassLan) {
resources.getStringArray(R.array.bypass_private_route).forEach { resources.getStringArray(R.array.bypass_private_route).forEach {
val subnet = Subnet.fromString(it)!! val subnet = Subnet.fromString(it)!!
builder.addRoute(subnet.address.hostAddress!!, subnet.prefixSize) builder.addRoute(subnet.address.hostAddress!!, subnet.prefixSize)
@ -142,7 +142,7 @@ class VpnService : BaseVpnService(),
var bypass = DataStore.bypass var bypass = DataStore.bypass
var workaroundSYSTEM = false /* DataStore.tunImplementation == TunImplementation.SYSTEM */ var workaroundSYSTEM = false /* DataStore.tunImplementation == TunImplementation.SYSTEM */
var needBypassRootUid = workaroundSYSTEM || data.proxy!!.config.trafficMap.values.any { var needBypassRootUid = workaroundSYSTEM || data.proxy!!.config.trafficMap.values.any {
it.nekoBean?.needBypassRootUid() == true || it.hysteriaBean?.protocol == HysteriaBean.PROTOCOL_FAKETCP it[0].nekoBean?.needBypassRootUid() == true || it[0].hysteriaBean?.protocol == HysteriaBean.PROTOCOL_FAKETCP
} }
if (proxyApps || needBypassRootUid) { if (proxyApps || needBypassRootUid) {

View File

@ -1,10 +1,12 @@
package io.nekohasekai.sagernet.bg.proto package io.nekohasekai.sagernet.bg.proto
import io.nekohasekai.sagernet.BuildConfig
import io.nekohasekai.sagernet.bg.BaseService import io.nekohasekai.sagernet.bg.BaseService
import io.nekohasekai.sagernet.database.ProxyEntity import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.runOnIoDispatcher import io.nekohasekai.sagernet.ktx.runOnIoDispatcher
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import moe.matsuri.nb4a.utils.JavaUtil
class ProxyInstance(profile: ProxyEntity, val service: BaseService.Interface) : class ProxyInstance(profile: ProxyEntity, val service: BaseService.Interface) :
BoxInstance(profile) { BoxInstance(profile) {
@ -15,6 +17,7 @@ class ProxyInstance(profile: ProxyEntity, val service: BaseService.Interface) :
override fun buildConfig() { override fun buildConfig() {
super.buildConfig() super.buildConfig()
Logs.d(config.config) Logs.d(config.config)
if (BuildConfig.DEBUG) Logs.d(JavaUtil.gson.toJson(config.trafficMap))
} }
override suspend fun init() { override suspend fun init() {

View File

@ -16,14 +16,16 @@ class TrafficLooper
) { ) {
private var job: Job? = null private var job: Job? = null
private val items = mutableMapOf<String, TrafficUpdater.TrafficLooperData>() private val items = mutableMapOf<Long, TrafficUpdater.TrafficLooperData>()
suspend fun stop() { suspend fun stop() {
job?.cancel() job?.cancel()
// finally // finally traffic post
if (!DataStore.profileTrafficStatistics) return
val traffic = mutableMapOf<Long, TrafficData>() val traffic = mutableMapOf<Long, TrafficData>()
data.proxy?.config?.trafficMap?.forEach { (tag, ent) -> data.proxy?.config?.trafficMap?.forEach { (_, ents) ->
val item = items[tag] ?: return@forEach for (ent in ents) {
val item = items[ent.id] ?: return@forEach
ent.rx = item.rx ent.rx = item.rx
ent.tx = item.tx ent.tx = item.tx
ProfileManager.updateProfile(ent) // update DB ProfileManager.updateProfile(ent) // update DB
@ -33,6 +35,7 @@ class TrafficLooper
tx = ent.tx, tx = ent.tx,
) )
} }
}
data.binder.broadcast { b -> data.binder.broadcast { b ->
for (t in traffic) { for (t in traffic) {
b.cbTrafficUpdate(t.value) b.cbTrafficUpdate(t.value)
@ -64,31 +67,35 @@ class TrafficLooper
if (!proxy.isInitialized()) continue if (!proxy.isInitialized()) continue
items.clear() items.clear()
itemBypass = TrafficUpdater.TrafficLooperData(tag = "bypass") itemBypass = TrafficUpdater.TrafficLooperData(tag = "bypass")
items["bypass"] = itemBypass items[-1] = itemBypass
// proxy.config.trafficMap.forEach { (tag, ent) -> //
proxy.config.outboundTags.forEach { tag -> val tags = hashSetOf("bypass")
// TODO g-xx query traffic return 0? proxy.config.trafficMap.forEach { (tag, ents) ->
val ent = proxy.config.trafficMap[tag] ?: return@forEach for (ent in ents) {
val item = TrafficUpdater.TrafficLooperData( val item = TrafficUpdater.TrafficLooperData(
tag = tag, tag = tag,
rx = ent.rx, rx = ent.rx,
tx = ent.tx, tx = ent.tx,
) )
if (tag == proxy.config.outboundTagMain) { if (ent.id == proxy.config.mainEntId) {
itemMain = item itemMain = item
itemMainBase = TrafficUpdater.TrafficLooperData( itemMainBase = TrafficUpdater.TrafficLooperData(
tag = tag, tag = tag,
rx = ent.rx, rx = ent.rx,
tx = ent.tx, tx = ent.tx,
) )
Logs.d("traffic count $tag to main")
} }
items[tag] = item items[ent.id] = item
tags.add(tag)
Logs.d("traffic count $tag to ${ent.id}") Logs.d("traffic count $tag to ${ent.id}")
} }
}
//
trafficUpdater = TrafficUpdater( trafficUpdater = TrafficUpdater(
box = proxy.box, items = items box = proxy.box, items = items.values.toList()
) )
proxy.box.setV2rayStats(items.keys.joinToString("\n")) proxy.box.setV2rayStats(tags.joinToString("\n"))
} }
trafficUpdater.updateAll() trafficUpdater.updateAll()
@ -106,8 +113,10 @@ class TrafficLooper
// traffic // traffic
val traffic = mutableMapOf<Long, TrafficData>() val traffic = mutableMapOf<Long, TrafficData>()
proxy.config.trafficMap.forEach { (tag, ent) -> if (DataStore.profileTrafficStatistics) {
val item = items[tag] ?: return@forEach proxy.config.trafficMap.forEach { (tag, ents) ->
for (ent in ents) {
val item = items[ent.id] ?: return@forEach
ent.rx = item.rx ent.rx = item.rx
ent.tx = item.tx ent.tx = item.tx
// ProfileManager.updateProfile(ent) // update DB // ProfileManager.updateProfile(ent) // update DB
@ -117,6 +126,8 @@ class TrafficLooper
tx = ent.tx, tx = ent.tx,
) // display ) // display
} }
}
}
// broadcast // broadcast
data.binder.broadcast { b -> data.binder.broadcast { b ->

View File

@ -4,10 +4,11 @@ import io.nekohasekai.sagernet.ktx.onIoDispatcher
class TrafficUpdater( class TrafficUpdater(
private val box: libcore.BoxInstance, private val box: libcore.BoxInstance,
val items: Map<String, TrafficLooperData>, // contain "bypass" val items: List<TrafficLooperData>, // contain "bypass"
) { ) {
class TrafficLooperData( class TrafficLooperData(
// Don't associate proxyEntity
var tag: String, var tag: String,
var tx: Long = 0, var tx: Long = 0,
var rx: Long = 0, var rx: Long = 0,
@ -52,12 +53,12 @@ class TrafficUpdater(
suspend fun updateAll() { suspend fun updateAll() {
val updated = mutableMapOf<String, TrafficLooperData>() // diffs val updated = mutableMapOf<String, TrafficLooperData>() // diffs
items.forEach { (tag, item) -> items.forEach { item ->
var diff = updated[tag] var diff = updated[item.tag]
// query a tag only once // query a tag only once
if (diff == null) { if (diff == null) {
diff = updateOne(item) diff = updateOne(item)
updated[tag] = diff updated[item.tag] = diff
} else { } else {
item.rx += diff.rx item.rx += diff.rx
item.tx += diff.tx item.tx += diff.tx

View File

@ -93,7 +93,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var mtu by configurationStore.stringToInt(Key.MTU) { 9000 } var mtu by configurationStore.stringToInt(Key.MTU) { 9000 }
var bypassLan by configurationStore.boolean(Key.BYPASS_LAN) var bypassLan by configurationStore.boolean(Key.BYPASS_LAN)
var bypassLanInCoreOnly by configurationStore.boolean(Key.BYPASS_LAN_IN_CORE_ONLY) var bypassLanInCore by configurationStore.boolean(Key.BYPASS_LAN_IN_CORE)
var allowAccess by configurationStore.boolean(Key.ALLOW_ACCESS) var allowAccess by configurationStore.boolean(Key.ALLOW_ACCESS)
var speedInterval by configurationStore.stringToInt(Key.SPEED_INTERVAL) var speedInterval by configurationStore.stringToInt(Key.SPEED_INTERVAL)

View File

@ -51,16 +51,15 @@ const val LOCAL_DNS_SERVER = "underlying://0.0.0.0"
class ConfigBuildResult( class ConfigBuildResult(
var config: String, var config: String,
var externalIndex: List<IndexEntity>, var externalIndex: List<IndexEntity>,
var outboundTags: List<String>, var mainEntId: Long,
var outboundTagMain: String, var trafficMap: Map<String, List<ProxyEntity>>,
var trafficMap: Map<String, ProxyEntity>,
val alerts: List<Pair<Int, String>>, val alerts: List<Pair<Int, String>>,
) { ) {
data class IndexEntity(var chain: LinkedHashMap<Int, ProxyEntity>) data class IndexEntity(var chain: LinkedHashMap<Int, ProxyEntity>)
} }
fun mergeJSON(j: String, to: MutableMap<String, Any>) { fun mergeJSON(j: String, to: MutableMap<String, Any>) {
if (j.isNullOrBlank()) return if (j.isBlank()) return
val m = gson.fromJson(j, to.javaClass) val m = gson.fromJson(j, to.javaClass)
m.forEach { (k, v) -> m.forEach { (k, v) ->
if (v is Map<*, *> && to[k] is Map<*, *>) { if (v is Map<*, *> && to[k] is Map<*, *>) {
@ -83,19 +82,14 @@ fun buildConfig(
return ConfigBuildResult( return ConfigBuildResult(
bean.config, bean.config,
listOf(), listOf(),
listOf(TAG_PROXY), // proxy.id, //
TAG_PROXY, // mapOf(TAG_PROXY to listOf(proxy)), //
mapOf(
TAG_PROXY to proxy
),
listOf() listOf()
) )
} }
} }
val outboundTags = ArrayList<String>() val trafficMap = HashMap<String, MutableList<ProxyEntity>>()
var outboundTagMain = TAG_BYPASS
val trafficMap = HashMap<String, ProxyEntity>()
val globalOutbounds = ArrayList<Long>() val globalOutbounds = ArrayList<Long>()
fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> { fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> {
@ -141,7 +135,7 @@ fun buildConfig(
val resolveDestination = DataStore.resolveDestination val resolveDestination = DataStore.resolveDestination
val alerts = mutableListOf<Pair<Int, String>>() val alerts = mutableListOf<Pair<Int, String>>()
var optionsToMerge: String = "" var optionsToMerge = ""
return MyOptions().apply { return MyOptions().apply {
if (!forTest && DataStore.enableClashAPI) experimental = ExperimentalOptions().apply { if (!forTest && DataStore.enableClashAPI) experimental = ExperimentalOptions().apply {
@ -254,7 +248,7 @@ fun buildConfig(
// chainTagOut: v2ray outbound tag for this chain // chainTagOut: v2ray outbound tag for this chain
var chainTagOut = "" var chainTagOut = ""
var chainTag = "c-$chainId" val chainTag = "c-$chainId"
var muxApplied = false var muxApplied = false
fun genDomainStrategy(noAsIs: Boolean): String { fun genDomainStrategy(noAsIs: Boolean): String {
@ -307,8 +301,6 @@ fun buildConfig(
} else { } else {
// index == 0 means last profile in chain / not chain // index == 0 means last profile in chain / not chain
chainTagOut = tagOut chainTagOut = tagOut
outboundTags.add(tagOut)
if (chainId == 0L) outboundTagMain = tagOut
} }
if (needGlobal) { if (needGlobal) {
@ -318,8 +310,10 @@ fun buildConfig(
globalOutbounds.add(proxyEntity.id) globalOutbounds.add(proxyEntity.id)
} }
// include g-xx // include g-xx & chain ent
trafficMap[tagOut] = proxyEntity val mapList = mutableListOf(proxyEntity)
if (index == 0 && profileList.size > 1) mapList.add(proxy) // chain ent
trafficMap[tagOut] = mapList
// Chain outbound // Chain outbound
if (proxyEntity.needExternal()) { if (proxyEntity.needExternal()) {
@ -474,10 +468,26 @@ fun buildConfig(
makeSingBoxRule(rule.ip.split("\n"), true) makeSingBoxRule(rule.ip.split("\n"), true)
} }
if (rule.port.isNotBlank()) { if (rule.port.isNotBlank()) {
port = rule.port.split("\n").map { it.toIntOrNull() ?: 0 } port = mutableListOf<Int>()
port_range = mutableListOf<String>()
rule.port.split(",").map {
if (it.contains(":")) {
port_range.add(it)
} else {
it.toIntOrNull()?.apply { port.add(this) }
}
}
} }
if (rule.sourcePort.isNotBlank()) { if (rule.sourcePort.isNotBlank()) {
source_port = rule.sourcePort.split("\n").map { it.toIntOrNull() ?: 0 } source_port = mutableListOf<Int>()
source_port_range = mutableListOf<String>()
rule.sourcePort.split(",").map {
if (it.contains(":")) {
source_port_range.add(it)
} else {
it.toIntOrNull()?.apply { source_port.add(this) }
}
}
} }
if (rule.network.isNotBlank()) { if (rule.network.isNotBlank()) {
network = rule.network network = rule.network
@ -656,15 +666,15 @@ fun buildConfig(
} }
if (!forTest) { if (!forTest) {
route.rules.add(Rule_DefaultOptions().apply { route.rules.add(0, Rule_DefaultOptions().apply {
inbound = listOf(TAG_DNS_IN) inbound = listOf(TAG_DNS_IN)
outbound = TAG_DNS_OUT outbound = TAG_DNS_OUT
}) })
route.rules.add(Rule_DefaultOptions().apply { route.rules.add(0, Rule_DefaultOptions().apply {
port = listOf(53) port = listOf(53)
outbound = TAG_DNS_OUT outbound = TAG_DNS_OUT
}) // TODO new mode use system dns? }) // TODO new mode use system dns?
if (DataStore.bypassLan && DataStore.bypassLanInCoreOnly) { if (DataStore.bypassLanInCore) {
route.rules.add(Rule_DefaultOptions().apply { route.rules.add(Rule_DefaultOptions().apply {
outbound = TAG_BYPASS outbound = TAG_BYPASS
geoip = listOf("private") geoip = listOf("private")
@ -700,8 +710,7 @@ fun buildConfig(
mergeJSON(optionsToMerge, this) mergeJSON(optionsToMerge, this)
}), }),
externalIndexMap, externalIndexMap,
outboundTags, proxy.id,
outboundTagMain,
trafficMap, trafficMap,
alerts alerts
) )

View File

@ -103,7 +103,7 @@ class AssetsActivity : ThemedActivity() {
.substringAfterLast('/') .substringAfterLast('/')
.substringAfter(':') .substringAfter(':')
if (!fileName.endsWith(".dat")) { if (!fileName.endsWith(".db")) {
alert(getString(R.string.route_not_asset, fileName)).show() alert(getString(R.string.route_not_asset, fileName)).show()
return@registerForActivityResult return@registerForActivityResult
} }

View File

@ -264,7 +264,7 @@ class RouteFragment : ToolbarFragment(R.layout.layout_route), Toolbar.OnMenuItem
inner class DocumentHolder(binding: LayoutEmptyRouteBinding) : RecyclerView.ViewHolder(binding.root) { inner class DocumentHolder(binding: LayoutEmptyRouteBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind() { fun bind() {
itemView.setOnClickListener { itemView.setOnClickListener {
it.context.launchCustomTab("https://sing-box.sagernet.org/configuration/route/rule/") it.context.launchCustomTab("https://matsuridayo.github.io/nb4a-route/")
} }
} }
} }

View File

@ -22,7 +22,6 @@ import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.utils.Theme import io.nekohasekai.sagernet.utils.Theme
import io.nekohasekai.sagernet.widget.AppListPreference import io.nekohasekai.sagernet.widget.AppListPreference
import libcore.Libcore
import moe.matsuri.nb4a.Protocols import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.ui.ColorPickerPreference import moe.matsuri.nb4a.ui.ColorPickerPreference
import moe.matsuri.nb4a.ui.LongClickSwitchPreference import moe.matsuri.nb4a.ui.LongClickSwitchPreference
@ -39,7 +38,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
listView.layoutManager = FixedLinearLayoutManager(listView) listView.layoutManager = FixedLinearLayoutManager(listView)
} }
val reloadListener = Preference.OnPreferenceChangeListener { _, _ -> private val reloadListener = Preference.OnPreferenceChangeListener { _, _ ->
needReload() needReload()
true true
} }
@ -50,7 +49,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
addPreferencesFromResource(R.xml.global_preferences) addPreferencesFromResource(R.xml.global_preferences)
DataStore.routePackages = DataStore.nekoPlugins DataStore.routePackages = DataStore.nekoPlugins
nekoPlugins = findPreference<AppListPreference>(Key.NEKO_PLUGIN_MANAGED)!! nekoPlugins = findPreference(Key.NEKO_PLUGIN_MANAGED)!!
nekoPlugins.setOnPreferenceClickListener { nekoPlugins.setOnPreferenceClickListener {
// borrow from route app settings // borrow from route app settings
startActivity(Intent( startActivity(Intent(
@ -80,7 +79,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
true true
} }
val mixedPort = findPreference<EditTextPreference>(Key.MIXED_PORT)!! val mixedPort = findPreference<EditTextPreference>(Key.MIXED_PORT)!!
val speedInterval = findPreference<Preference>(Key.SPEED_INTERVAL)!!
val serviceMode = findPreference<Preference>(Key.SERVICE_MODE)!! val serviceMode = findPreference<Preference>(Key.SERVICE_MODE)!!
val allowAccess = findPreference<Preference>(Key.ALLOW_ACCESS)!! val allowAccess = findPreference<Preference>(Key.ALLOW_ACCESS)!!
val appendHttpProxy = findPreference<SwitchPreference>(Key.APPEND_HTTP_PROXY)!! val appendHttpProxy = findPreference<SwitchPreference>(Key.APPEND_HTTP_PROXY)!!
@ -96,14 +94,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
tcpKeepAliveInterval.isVisible = false tcpKeepAliveInterval.isVisible = false
val bypassLan = findPreference<SwitchPreference>(Key.BYPASS_LAN)!! val bypassLan = findPreference<SwitchPreference>(Key.BYPASS_LAN)!!
val bypassLanInCoreOnly = findPreference<SwitchPreference>(Key.BYPASS_LAN_IN_CORE_ONLY)!! val bypassLanInCore = findPreference<SwitchPreference>(Key.BYPASS_LAN_IN_CORE)!!
bypassLanInCoreOnly.isEnabled = bypassLan.isChecked
bypassLan.setOnPreferenceChangeListener { _, newValue ->
bypassLanInCoreOnly.isEnabled = newValue as Boolean
needReload()
true
}
val remoteDns = findPreference<EditTextPreference>(Key.REMOTE_DNS)!! val remoteDns = findPreference<EditTextPreference>(Key.REMOTE_DNS)!!
val directDns = findPreference<EditTextPreference>(Key.DIRECT_DNS)!! val directDns = findPreference<EditTextPreference>(Key.DIRECT_DNS)!!
@ -192,9 +183,10 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
val profileTrafficStatistics = val profileTrafficStatistics =
findPreference<SwitchPreference>(Key.PROFILE_TRAFFIC_STATISTICS)!! findPreference<SwitchPreference>(Key.PROFILE_TRAFFIC_STATISTICS)!!
speedInterval.isEnabled = profileTrafficStatistics.isChecked val speedInterval = findPreference<SimpleMenuPreference>(Key.SPEED_INTERVAL)!!
profileTrafficStatistics.setOnPreferenceChangeListener { _, newValue -> profileTrafficStatistics.isEnabled = speedInterval.value.toString() != "0"
speedInterval.isEnabled = newValue as Boolean speedInterval.setOnPreferenceChangeListener { _, newValue ->
profileTrafficStatistics.isEnabled = newValue.toString() != "0"
needReload() needReload()
true true
} }
@ -209,7 +201,6 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
val acquireWakeLock = findPreference<SwitchPreference>(Key.ACQUIRE_WAKE_LOCK)!! val acquireWakeLock = findPreference<SwitchPreference>(Key.ACQUIRE_WAKE_LOCK)!!
val enableClashAPI = findPreference<SwitchPreference>(Key.ENABLE_CLASH_API)!! val enableClashAPI = findPreference<SwitchPreference>(Key.ENABLE_CLASH_API)!!
speedInterval.onPreferenceChangeListener = reloadListener
mixedPort.onPreferenceChangeListener = reloadListener mixedPort.onPreferenceChangeListener = reloadListener
appendHttpProxy.onPreferenceChangeListener = reloadListener appendHttpProxy.onPreferenceChangeListener = reloadListener
showDirectSpeed.onPreferenceChangeListener = reloadListener showDirectSpeed.onPreferenceChangeListener = reloadListener
@ -217,7 +208,8 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
trafficSniffing.onPreferenceChangeListener = reloadListener trafficSniffing.onPreferenceChangeListener = reloadListener
muxConcurrency.onPreferenceChangeListener = reloadListener muxConcurrency.onPreferenceChangeListener = reloadListener
tcpKeepAliveInterval.onPreferenceChangeListener = reloadListener tcpKeepAliveInterval.onPreferenceChangeListener = reloadListener
bypassLanInCoreOnly.onPreferenceChangeListener = reloadListener bypassLan.onPreferenceChangeListener = reloadListener
bypassLanInCore.onPreferenceChangeListener = reloadListener
mtu.onPreferenceChangeListener = reloadListener mtu.onPreferenceChangeListener = reloadListener
enableFakeDns.onPreferenceChangeListener = reloadListener enableFakeDns.onPreferenceChangeListener = reloadListener

View File

@ -220,7 +220,7 @@
<string name="domain_strategy">استراتيجية حل المجال</string> <string name="domain_strategy">استراتيجية حل المجال</string>
<string name="route_opt_block_ads">إعلانات كتلة</string> <string name="route_opt_block_ads">إعلانات كتلة</string>
<string name="route_opt_bypass_lan">جانبا LAN</string> <string name="route_opt_bypass_lan">جانبا LAN</string>
<string name="route_not_asset">ليس ملف أصل: استثناء .dat، لكن %s</string> <string name="route_not_asset">ليس ملف أصل: استثناء .db، لكن %s</string>
<string name="hysteria_download_mbps">أقصى سرعة تنزيل (بالميجابت في الثانية)</string> <string name="hysteria_download_mbps">أقصى سرعة تنزيل (بالميجابت في الثانية)</string>
<string name="hysteria_upload_mbps">أقصى سرعة تحميل (بالميجابت في الثانية)</string> <string name="hysteria_upload_mbps">أقصى سرعة تحميل (بالميجابت في الثانية)</string>
<string name="hysteria_auth_payload">حمولة المصادقة</string> <string name="hysteria_auth_payload">حمولة المصادقة</string>

View File

@ -154,7 +154,7 @@
<string name="route_asset_status">Versión local: %s</string> <string name="route_asset_status">Versión local: %s</string>
<string name="route_asset_no_update">Sin actualización</string> <string name="route_asset_no_update">Sin actualización</string>
<string name="route_asset_updated">Actualizado</string> <string name="route_asset_updated">Actualizado</string>
<string name="route_not_asset">No es un archivo de activos: excepto .dat, pero %s</string> <string name="route_not_asset">No es un archivo de activos: excepto .db, pero %s</string>
<string name="route_opt_bypass_lan">Omitir LAN</string> <string name="route_opt_bypass_lan">Omitir LAN</string>
<string name="route_opt_block_ads">Bloquear anuncios</string> <string name="route_opt_block_ads">Bloquear anuncios</string>
<string name="route_opt_block_analysis">Bloquear analítica</string> <string name="route_opt_block_analysis">Bloquear analítica</string>

View File

@ -152,7 +152,7 @@
<string name="route_asset_status">نسخه محلی: %s</string> <string name="route_asset_status">نسخه محلی: %s</string>
<string name="route_asset_no_update">بدون آپدیت</string> <string name="route_asset_no_update">بدون آپدیت</string>
<string name="route_asset_updated">به روز رسانی</string> <string name="route_asset_updated">به روز رسانی</string>
<string name="route_not_asset">نه یک فایل پشتیبان: به جز .dat، اما %s</string> <string name="route_not_asset">نه یک فایل پشتیبان: به جز .db، اما %s</string>
<string name="route_opt_bypass_lan">دور زدن LAN</string> <string name="route_opt_bypass_lan">دور زدن LAN</string>
<string name="route_opt_block_ads">مسدود کردن تبلیغات</string> <string name="route_opt_block_ads">مسدود کردن تبلیغات</string>
<string name="route_opt_block_analysis">بلاک کردن انالیز ها</string> <string name="route_opt_block_analysis">بلاک کردن انالیز ها</string>

View File

@ -181,7 +181,7 @@
<string name="mux_sum">Mux dirancang untuk mengurangi latensi handshake TCP, bukan untuk meningkatkan throughput koneksi. Menggunakan Mux untuk menonton video, mengunduh, atau uji kecepatan biasanya kontra produktif</string> <string name="mux_sum">Mux dirancang untuk mengurangi latensi handshake TCP, bukan untuk meningkatkan throughput koneksi. Menggunakan Mux untuk menonton video, mengunduh, atau uji kecepatan biasanya kontra produktif</string>
<string name="domain_strategy">Strategi Resolusi Domain</string> <string name="domain_strategy">Strategi Resolusi Domain</string>
<string name="route_opt_bypass_lan">Lewati LAN</string> <string name="route_opt_bypass_lan">Lewati LAN</string>
<string name="route_not_asset">Bukan file aset: kecuali .dat, tapi %s</string> <string name="route_not_asset">Bukan file aset: kecuali .db, tapi %s</string>
<string name="route_rules_provider">Penyedia Aset Aturan</string> <string name="route_rules_provider">Penyedia Aset Aturan</string>
<string name="route_reverse_redirect">Pengalihan Terbalik</string> <string name="route_reverse_redirect">Pengalihan Terbalik</string>
<string name="route_bypass_domain">Aturan domain untuk %s</string> <string name="route_bypass_domain">Aturan domain untuk %s</string>

View File

@ -237,7 +237,7 @@
<string name="domain_strategy">Domeneløsningsstrategi</string> <string name="domain_strategy">Domeneløsningsstrategi</string>
<string name="route_opt_block_ads">Blokker annonser</string> <string name="route_opt_block_ads">Blokker annonser</string>
<string name="route_opt_bypass_lan">Omgå LAN</string> <string name="route_opt_bypass_lan">Omgå LAN</string>
<string name="route_not_asset">Ikke en ressursfil: unntatt .dat, men %s</string> <string name="route_not_asset">Ikke en ressursfil: unntatt .db, men %s</string>
<string name="route_asset_updated">Oppdatert</string> <string name="route_asset_updated">Oppdatert</string>
<string name="route_asset_no_update">Ingen oppdatering</string> <string name="route_asset_no_update">Ingen oppdatering</string>
<string name="route_asset_status">Lokal versjon: %s</string> <string name="route_asset_status">Lokal versjon: %s</string>

View File

@ -296,7 +296,7 @@
<string name="domain_strategy">Стратегия разрешения доменов</string> <string name="domain_strategy">Стратегия разрешения доменов</string>
<string name="route_opt_block_ads">Блокировать рекламу</string> <string name="route_opt_block_ads">Блокировать рекламу</string>
<string name="route_opt_bypass_lan">Обход LAN</string> <string name="route_opt_bypass_lan">Обход LAN</string>
<string name="route_not_asset">Не файл ресурса: ожидался .dat, а не %s</string> <string name="route_not_asset">Не файл ресурса: ожидался .db, а не %s</string>
<string name="route_asset_updated">Обновлено</string> <string name="route_asset_updated">Обновлено</string>
<string name="route_asset_no_update">Обновлений нет</string> <string name="route_asset_no_update">Обновлений нет</string>
<string name="route_asset_status">Локальная версия: %s</string> <string name="route_asset_status">Локальная версия: %s</string>

View File

@ -369,7 +369,7 @@
<string name="alter_id">Alternatif ID</string> <string name="alter_id">Alternatif ID</string>
<string name="obfs">Şaşırtmaca</string> <string name="obfs">Şaşırtmaca</string>
<string name="tcp_keep_alive_interval">TCP aktif paket teslim koruma aralığı</string> <string name="tcp_keep_alive_interval">TCP aktif paket teslim koruma aralığı</string>
<string name="route_not_asset">Varlık dosyası değil: .dat beklendi ama %s</string> <string name="route_not_asset">Varlık dosyası değil: .db beklendi ama %s</string>
<string name="route_rules_provider">Rota Varlıkları Sağlayıcısı</string> <string name="route_rules_provider">Rota Varlıkları Sağlayıcısı</string>
<string name="route_assets">Varlıklar</string> <string name="route_assets">Varlıklar</string>
<string name="route_manage_assets">Rota Varlıklarını Yönet</string> <string name="route_manage_assets">Rota Varlıklarını Yönet</string>

View File

@ -262,7 +262,7 @@
<string name="lines">%d 行</string> <string name="lines">%d 行</string>
<string name="only"></string> <string name="only"></string>
<string name="prefer">优先</string> <string name="prefer">优先</string>
<string name="route_not_asset">不是资源文件: 预期 .dat 为扩展名, 但 %s</string> <string name="route_not_asset">不是资源文件: 预期 .db 为扩展名, 但 %s</string>
<string name="route_asset_no_update">已为最新</string> <string name="route_asset_no_update">已为最新</string>
<string name="route_asset_updated">已更新</string> <string name="route_asset_updated">已更新</string>
<string name="route_asset_status">本地版本: %s</string> <string name="route_asset_status">本地版本: %s</string>

View File

@ -234,7 +234,7 @@
<string name="route_asset_status">本地版本:%s</string> <string name="route_asset_status">本地版本:%s</string>
<string name="route_asset_no_update">無更新</string> <string name="route_asset_no_update">無更新</string>
<string name="route_asset_updated">已更新</string> <string name="route_asset_updated">已更新</string>
<string name="route_not_asset">非資源檔案:預期副檔名為 .dat,但 %s</string> <string name="route_not_asset">非資源檔案:預期副檔名為 .db,但 %s</string>
<string name="route_opt_bypass_lan">略過區域網路位址</string> <string name="route_opt_bypass_lan">略過區域網路位址</string>
<string name="route_opt_block_ads">封鎖廣告</string> <string name="route_opt_block_ads">封鎖廣告</string>
<string name="domain_strategy">網域解析策略</string> <string name="domain_strategy">網域解析策略</string>

View File

@ -157,7 +157,7 @@
<string name="route_asset_status">Local version: %s</string> <string name="route_asset_status">Local version: %s</string>
<string name="route_asset_no_update">No update</string> <string name="route_asset_no_update">No update</string>
<string name="route_asset_updated">Updated</string> <string name="route_asset_updated">Updated</string>
<string name="route_not_asset">Not an asset file: excepted .dat, but %s</string> <string name="route_not_asset">Not an asset file: excepted .db, but %s</string>
<string name="route_opt_bypass_lan">Bypass LAN</string> <string name="route_opt_bypass_lan">Bypass LAN</string>
<string name="route_opt_block_ads">Block ADs</string> <string name="route_opt_block_ads">Block ADs</string>
<string name="route_opt_block_analysis">Block analysis</string> <string name="route_opt_block_analysis">Block analysis</string>
@ -331,7 +331,6 @@
<string name="append_http_proxy">Append HTTP Proxy to VPN</string> <string name="append_http_proxy">Append HTTP Proxy to VPN</string>
<string name="append_http_proxy_sum">HTTP proxy will be used directly from (browser/ some supported apps), without going through the virtual NIC device (Android 10+)</string> <string name="append_http_proxy_sum">HTTP proxy will be used directly from (browser/ some supported apps), without going through the virtual NIC device (Android 10+)</string>
<string name="bypass_lan_in_core_only">Bypass LAN in Core Only</string> <string name="bypass_lan_in_core_only">Bypass LAN in Core Only</string>
<string name="bypass_lan_in_core_only_sum">If Lineage\'s "Allow hotspot clients to use VPNs" does not work, try this.</string>
<string name="protocol_settings">Protocol Settings</string> <string name="protocol_settings">Protocol Settings</string>
<string name="trojan_provider">Trojan Provider</string> <string name="trojan_provider">Trojan Provider</string>
<string name="group_basic">Basic</string> <string name="group_basic">Basic</string>

View File

@ -89,8 +89,7 @@
app:key="bypassLan" app:key="bypassLan"
app:title="@string/route_opt_bypass_lan" /> app:title="@string/route_opt_bypass_lan" />
<SwitchPreference <SwitchPreference
android:summary="@string/bypass_lan_in_core_only_sum" app:key="bypassLanInCore"
app:key="bypassLanInCoreOnly"
app:title="@string/bypass_lan_in_core_only" /> app:title="@string/bypass_lan_in_core_only" />
<SwitchPreference <SwitchPreference
app:defaultValue="true" app:defaultValue="true"