mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-20 15:10:05 +08:00
fix
This commit is contained in:
parent
48a2776f9c
commit
fafe14b7c6
@ -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"
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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 ->
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user