mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-19 22:50:05 +08:00
implement front proxy & landing proxy
This commit is contained in:
parent
eec96213aa
commit
bb51a38474
@ -2,11 +2,11 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"identityHash": "062104587ad7088bb9926683389e995d",
|
"identityHash": "937a517378a0cb35dc1f8bd181683882",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "proxy_groups",
|
"tableName": "proxy_groups",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL)",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
@ -61,13 +61,19 @@
|
|||||||
"columnName": "frontProxy",
|
"columnName": "frontProxy",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "landingProxy",
|
||||||
|
"columnName": "landingProxy",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
]
|
||||||
"autoGenerate": true
|
|
||||||
},
|
},
|
||||||
"indices": [],
|
"indices": [],
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
@ -222,10 +228,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
]
|
||||||
"autoGenerate": true
|
|
||||||
},
|
},
|
||||||
"indices": [
|
"indices": [
|
||||||
{
|
{
|
||||||
@ -324,10 +330,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
]
|
||||||
"autoGenerate": true
|
|
||||||
},
|
},
|
||||||
"indices": [],
|
"indices": [],
|
||||||
"foreignKeys": []
|
"foreignKeys": []
|
||||||
@ -336,7 +342,7 @@
|
|||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '062104587ad7088bb9926683389e995d')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '937a517378a0cb35dc1f8bd181683882')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,13 +127,14 @@ object Key {
|
|||||||
const val ROUTE_SOURCE = "routeSource"
|
const val ROUTE_SOURCE = "routeSource"
|
||||||
const val ROUTE_PROTOCOL = "routeProtocol"
|
const val ROUTE_PROTOCOL = "routeProtocol"
|
||||||
const val ROUTE_OUTBOUND = "routeOutbound"
|
const val ROUTE_OUTBOUND = "routeOutbound"
|
||||||
const val ROUTE_OUTBOUND_RULE = "routeOutboundRule"
|
|
||||||
const val ROUTE_PACKAGES = "routePackages"
|
const val ROUTE_PACKAGES = "routePackages"
|
||||||
|
|
||||||
const val GROUP_NAME = "groupName"
|
const val GROUP_NAME = "groupName"
|
||||||
const val GROUP_TYPE = "groupType"
|
const val GROUP_TYPE = "groupType"
|
||||||
const val GROUP_ORDER = "groupOrder"
|
const val GROUP_ORDER = "groupOrder"
|
||||||
const val GROUP_IS_SELECTOR = "groupIsSelector"
|
const val GROUP_IS_SELECTOR = "groupIsSelector"
|
||||||
|
const val GROUP_FRONT_PROXY = "groupFrontProxy"
|
||||||
|
const val GROUP_LANDING_PROXY = "groupLandingProxy"
|
||||||
|
|
||||||
const val GROUP_SUBSCRIPTION = "groupSubscription"
|
const val GROUP_SUBSCRIPTION = "groupSubscription"
|
||||||
const val SUBSCRIPTION_LINK = "subscriptionLink"
|
const val SUBSCRIPTION_LINK = "subscriptionLink"
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import io.nekohasekai.sagernet.aidl.ISagerNetService
|
|||||||
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
|
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
|
||||||
import io.nekohasekai.sagernet.bg.proto.ProxyInstance
|
import io.nekohasekai.sagernet.bg.proto.ProxyInstance
|
||||||
import io.nekohasekai.sagernet.database.DataStore
|
import io.nekohasekai.sagernet.database.DataStore
|
||||||
|
import io.nekohasekai.sagernet.database.ProxyEntity
|
||||||
import io.nekohasekai.sagernet.database.SagerDatabase
|
import io.nekohasekai.sagernet.database.SagerDatabase
|
||||||
import io.nekohasekai.sagernet.ktx.*
|
import io.nekohasekai.sagernet.ktx.*
|
||||||
import io.nekohasekai.sagernet.plugin.PluginManager
|
import io.nekohasekai.sagernet.plugin.PluginManager
|
||||||
@ -149,14 +150,24 @@ class BaseService {
|
|||||||
}
|
}
|
||||||
if (canReloadSelector()) {
|
if (canReloadSelector()) {
|
||||||
var tag = ""
|
var tag = ""
|
||||||
|
var ent: ProxyEntity? = null
|
||||||
data.proxy!!.config.trafficMap.forEach { (t, list) ->
|
data.proxy!!.config.trafficMap.forEach { (t, list) ->
|
||||||
if (list.map { it.id }.contains(DataStore.selectedProxy)) {
|
for (it in list) {
|
||||||
|
if (it.id == DataStore.selectedProxy) {
|
||||||
|
ent = it
|
||||||
tag = t
|
tag = t
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tag.isNotBlank()) {
|
}
|
||||||
|
if (tag.isNotBlank() && ent != null) {
|
||||||
val success = data.proxy!!.box.selectOutbound(tag)
|
val success = data.proxy!!.box.selectOutbound(tag)
|
||||||
Logs.d("selectOutbound $tag $success")
|
Logs.d("selectOutbound $tag $success")
|
||||||
|
runOnDefaultDispatcher {
|
||||||
|
data.binder.broadcast {
|
||||||
|
it.stateChanged(-1, ent!!.displayName(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ class SagerConnection(private var listenForDeath: Boolean = false) : ServiceConn
|
|||||||
private val serviceCallback = object : ISagerNetServiceCallback.Stub() {
|
private val serviceCallback = object : ISagerNetServiceCallback.Stub() {
|
||||||
|
|
||||||
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
|
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
|
||||||
|
if (state < 0) return // skip private
|
||||||
val s = BaseService.State.values()[state]
|
val s = BaseService.State.values()[state]
|
||||||
DataStore.serviceState = s
|
DataStore.serviceState = s
|
||||||
val callback = callback ?: return
|
val callback = callback ?: return
|
||||||
|
|||||||
@ -89,6 +89,9 @@ class ServiceNotification(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
|
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
|
||||||
|
if (state == -1) {
|
||||||
|
builder.setContentTitle(profileName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun missingPlugin(profileName: String?, pluginName: String?) {
|
override fun missingPlugin(profileName: String?, pluginName: String?) {
|
||||||
|
|||||||
@ -225,9 +225,13 @@ object DataStore : OnPreferenceDataStoreChangeListener {
|
|||||||
var routeSource by profileCacheStore.string(Key.ROUTE_SOURCE)
|
var routeSource by profileCacheStore.string(Key.ROUTE_SOURCE)
|
||||||
var routeProtocol by profileCacheStore.string(Key.ROUTE_PROTOCOL)
|
var routeProtocol by profileCacheStore.string(Key.ROUTE_PROTOCOL)
|
||||||
var routeOutbound by profileCacheStore.stringToInt(Key.ROUTE_OUTBOUND)
|
var routeOutbound by profileCacheStore.stringToInt(Key.ROUTE_OUTBOUND)
|
||||||
var routeOutboundRule by profileCacheStore.long(Key.ROUTE_OUTBOUND_RULE)
|
var routeOutboundRule by profileCacheStore.long(Key.ROUTE_OUTBOUND + "Long")
|
||||||
var routePackages by profileCacheStore.string(Key.ROUTE_PACKAGES)
|
var routePackages by profileCacheStore.string(Key.ROUTE_PACKAGES)
|
||||||
|
|
||||||
|
var frontProxy by profileCacheStore.long(Key.GROUP_FRONT_PROXY + "Long")
|
||||||
|
var landingProxy by profileCacheStore.long(Key.GROUP_LANDING_PROXY + "Long")
|
||||||
|
var frontProxyTmp by profileCacheStore.stringToInt(Key.GROUP_FRONT_PROXY)
|
||||||
|
var landingProxyTmp by profileCacheStore.stringToInt(Key.GROUP_LANDING_PROXY)
|
||||||
|
|
||||||
var serverConfig by profileCacheStore.string(Key.SERVER_CONFIG)
|
var serverConfig by profileCacheStore.string(Key.SERVER_CONFIG)
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,8 @@ data class ProxyGroup(
|
|||||||
var subscription: SubscriptionBean? = null,
|
var subscription: SubscriptionBean? = null,
|
||||||
var order: Int = GroupOrder.ORIGIN,
|
var order: Int = GroupOrder.ORIGIN,
|
||||||
var isSelector: Boolean = false,
|
var isSelector: Boolean = false,
|
||||||
var frontProxy: Long = 0L
|
var frontProxy: Long = -1L,
|
||||||
|
var landingProxy: Long = -1L
|
||||||
) : Serializable() {
|
) : Serializable() {
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
|
|||||||
@ -96,8 +96,7 @@ fun buildConfig(
|
|||||||
val group = SagerDatabase.groupDao.getById(proxy.groupId)
|
val group = SagerDatabase.groupDao.getById(proxy.groupId)
|
||||||
var optionsToMerge = ""
|
var optionsToMerge = ""
|
||||||
|
|
||||||
fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> {
|
fun ProxyEntity.resolveChainInternal(): MutableList<ProxyEntity> {
|
||||||
val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
|
||||||
val bean = requireBean()
|
val bean = requireBean()
|
||||||
if (bean is ChainBean) {
|
if (bean is ChainBean) {
|
||||||
val beans = SagerDatabase.proxyDao.getEntities(bean.proxies)
|
val beans = SagerDatabase.proxyDao.getEntities(bean.proxies)
|
||||||
@ -105,20 +104,24 @@ fun buildConfig(
|
|||||||
val beanList = ArrayList<ProxyEntity>()
|
val beanList = ArrayList<ProxyEntity>()
|
||||||
for (proxyId in bean.proxies) {
|
for (proxyId in bean.proxies) {
|
||||||
val item = beansMap[proxyId] ?: continue
|
val item = beansMap[proxyId] ?: continue
|
||||||
beanList.addAll(item.resolveChain())
|
beanList.addAll(item.resolveChainInternal())
|
||||||
}
|
}
|
||||||
return if (frontProxy == null) {
|
return beanList.asReversed()
|
||||||
beanList.asReversed()
|
|
||||||
} else {
|
|
||||||
beanList.add(0, frontProxy)
|
|
||||||
beanList.asReversed()
|
|
||||||
}
|
}
|
||||||
|
return mutableListOf(this)
|
||||||
}
|
}
|
||||||
return if (frontProxy == null) {
|
|
||||||
mutableListOf(this)
|
fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> {
|
||||||
} else {
|
val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
||||||
mutableListOf(this, frontProxy)
|
val landingProxy = group?.landingProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
||||||
|
val list = resolveChainInternal()
|
||||||
|
if (frontProxy != null) {
|
||||||
|
list.add(frontProxy)
|
||||||
}
|
}
|
||||||
|
if (landingProxy != null) {
|
||||||
|
list.add(0, landingProxy)
|
||||||
|
}
|
||||||
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
val extraRules = if (forTest) listOf() else SagerDatabase.rulesDao.enabledRules()
|
val extraRules = if (forTest) listOf() else SagerDatabase.rulesDao.enabledRules()
|
||||||
|
|||||||
@ -37,14 +37,18 @@ class GroupSettingsActivity(
|
|||||||
OnPreferenceDataStoreChangeListener {
|
OnPreferenceDataStoreChangeListener {
|
||||||
|
|
||||||
private lateinit var frontProxyPreference: OutboundPreference
|
private lateinit var frontProxyPreference: OutboundPreference
|
||||||
|
private lateinit var landingProxyPreference: OutboundPreference
|
||||||
|
|
||||||
fun ProxyGroup.init() {
|
fun ProxyGroup.init() {
|
||||||
DataStore.groupName = name ?: ""
|
DataStore.groupName = name ?: ""
|
||||||
DataStore.groupType = type
|
DataStore.groupType = type
|
||||||
DataStore.groupOrder = order
|
DataStore.groupOrder = order
|
||||||
DataStore.groupIsSelector = isSelector
|
DataStore.groupIsSelector = isSelector
|
||||||
DataStore.routeOutboundRule = frontProxy
|
|
||||||
DataStore.routeOutbound = if (frontProxy >= 0) 3 else 0
|
DataStore.frontProxy = frontProxy
|
||||||
|
DataStore.landingProxy = landingProxy
|
||||||
|
DataStore.frontProxyTmp = if (frontProxy >= 0) 3 else 0
|
||||||
|
DataStore.landingProxyTmp = if (landingProxy >= 0) 3 else 0
|
||||||
|
|
||||||
val subscription = subscription ?: SubscriptionBean().applyDefaultValues()
|
val subscription = subscription ?: SubscriptionBean().applyDefaultValues()
|
||||||
DataStore.subscriptionLink = subscription.link
|
DataStore.subscriptionLink = subscription.link
|
||||||
@ -61,7 +65,9 @@ class GroupSettingsActivity(
|
|||||||
type = DataStore.groupType
|
type = DataStore.groupType
|
||||||
order = DataStore.groupOrder
|
order = DataStore.groupOrder
|
||||||
isSelector = DataStore.groupIsSelector
|
isSelector = DataStore.groupIsSelector
|
||||||
frontProxy = if (DataStore.routeOutbound == 3) DataStore.routeOutboundRule else -1
|
|
||||||
|
frontProxy = if (DataStore.frontProxyTmp == 3) DataStore.frontProxy else -1
|
||||||
|
landingProxy = if (DataStore.landingProxyTmp == 3) DataStore.landingProxy else -1
|
||||||
|
|
||||||
val isSubscription = type == GroupType.SUBSCRIPTION
|
val isSubscription = type == GroupType.SUBSCRIPTION
|
||||||
if (isSubscription) {
|
if (isSubscription) {
|
||||||
@ -88,13 +94,28 @@ class GroupSettingsActivity(
|
|||||||
) {
|
) {
|
||||||
addPreferencesFromResource(R.xml.group_preferences)
|
addPreferencesFromResource(R.xml.group_preferences)
|
||||||
|
|
||||||
frontProxyPreference = findPreference(Key.ROUTE_OUTBOUND)!!
|
frontProxyPreference = findPreference(Key.GROUP_FRONT_PROXY)!!
|
||||||
frontProxyPreference.apply {
|
frontProxyPreference.apply {
|
||||||
entries = listOf("None", "Select...").toTypedArray()
|
setEntries(R.array.front_proxy_entry)
|
||||||
entryValues = listOf("0", "3").toTypedArray()
|
setEntryValues(R.array.front_proxy_value)
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
if (newValue.toString() == "3") {
|
if (newValue.toString() == "3") {
|
||||||
selectProfileForAdd.launch(
|
selectProfileForAddFront.launch(
|
||||||
|
Intent(this@GroupSettingsActivity, ProfileSelectActivity::class.java)
|
||||||
|
)
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
landingProxyPreference = findPreference(Key.GROUP_LANDING_PROXY)!!
|
||||||
|
landingProxyPreference.apply {
|
||||||
|
setEntries(R.array.front_proxy_entry)
|
||||||
|
setEntryValues(R.array.front_proxy_value)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
if (newValue.toString() == "3") {
|
||||||
|
selectProfileForAddLanding.launch(
|
||||||
Intent(this@GroupSettingsActivity, ProfileSelectActivity::class.java)
|
Intent(this@GroupSettingsActivity, ProfileSelectActivity::class.java)
|
||||||
)
|
)
|
||||||
false
|
false
|
||||||
@ -119,8 +140,6 @@ class GroupSettingsActivity(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
val subscriptionUserAgent =
|
|
||||||
findPreference<UserAgentPreference>(Key.SUBSCRIPTION_USER_AGENT)!!
|
|
||||||
val subscriptionAutoUpdate =
|
val subscriptionAutoUpdate =
|
||||||
findPreference<SwitchPreference>(Key.SUBSCRIPTION_AUTO_UPDATE)!!
|
findPreference<SwitchPreference>(Key.SUBSCRIPTION_AUTO_UPDATE)!!
|
||||||
val subscriptionAutoUpdateDelay =
|
val subscriptionAutoUpdateDelay =
|
||||||
@ -339,20 +358,32 @@ class GroupSettingsActivity(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectProfileForAdd = registerForActivityResult(
|
val selectProfileForAddFront = registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()
|
ActivityResultContracts.StartActivityForResult()
|
||||||
) {
|
) {
|
||||||
if (it.resultCode == Activity.RESULT_OK) runOnDefaultDispatcher {
|
if (it.resultCode == Activity.RESULT_OK) runOnDefaultDispatcher {
|
||||||
val profile = ProfileManager.getProfile(
|
val profile = ProfileManager.getProfile(
|
||||||
it.data!!.getLongExtra(
|
it.data!!.getLongExtra(ProfileSelectActivity.EXTRA_PROFILE_ID, 0)
|
||||||
ProfileSelectActivity.EXTRA_PROFILE_ID, 0
|
|
||||||
)
|
|
||||||
) ?: return@runOnDefaultDispatcher
|
) ?: return@runOnDefaultDispatcher
|
||||||
DataStore.routeOutboundRule = profile.id
|
DataStore.frontProxy = profile.id
|
||||||
onMainDispatcher {
|
onMainDispatcher {
|
||||||
frontProxyPreference.value = "3"
|
frontProxyPreference.value = "3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val selectProfileForAddLanding = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) runOnDefaultDispatcher {
|
||||||
|
val profile = ProfileManager.getProfile(
|
||||||
|
it.data!!.getLongExtra(ProfileSelectActivity.EXTRA_PROFILE_ID, 0)
|
||||||
|
) ?: return@runOnDefaultDispatcher
|
||||||
|
DataStore.landingProxy = profile.id
|
||||||
|
onMainDispatcher {
|
||||||
|
landingProxyPreference.value = "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ class OutboundPreference
|
|||||||
|
|
||||||
override fun getSummary(): CharSequence? {
|
override fun getSummary(): CharSequence? {
|
||||||
if (value == "3") {
|
if (value == "3") {
|
||||||
val routeOutbound = DataStore.routeOutboundRule
|
val routeOutbound = DataStore.profileCacheStore.getLong(key + "Long") ?: 0
|
||||||
if (routeOutbound > 0) {
|
if (routeOutbound > 0) {
|
||||||
ProfileManager.getProfile(routeOutbound)?.displayName()?.let {
|
ProfileManager.getProfile(routeOutbound)?.displayName()?.let {
|
||||||
return it
|
return it
|
||||||
|
|||||||
@ -247,6 +247,16 @@
|
|||||||
<item>3</item>
|
<item>3</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="front_proxy_entry">
|
||||||
|
<item>@string/ssh_auth_type_none</item>
|
||||||
|
<item>@string/route_profile</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="front_proxy_value">
|
||||||
|
<item>0</item>
|
||||||
|
<item>3</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="networks_value">
|
<string-array name="networks_value">
|
||||||
<item>tcp</item>
|
<item>tcp</item>
|
||||||
<item>ws</item>
|
<item>ws</item>
|
||||||
|
|||||||
@ -504,5 +504,6 @@ Anyone can write advanced plugins, which can control NekoBox. please download an
|
|||||||
<string name="need_restart">Restart APP to apply changes</string>
|
<string name="need_restart">Restart APP to apply changes</string>
|
||||||
<string name="use_selector">Use selector</string>
|
<string name="use_selector">Use selector</string>
|
||||||
<string name="front_proxy">Front proxy</string>
|
<string name="front_proxy">Front proxy</string>
|
||||||
|
<string name="landing_proxy">Landing Proxy</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@ -22,10 +22,16 @@
|
|||||||
|
|
||||||
<io.nekohasekai.sagernet.widget.OutboundPreference
|
<io.nekohasekai.sagernet.widget.OutboundPreference
|
||||||
app:icon="@drawable/ic_hardware_router"
|
app:icon="@drawable/ic_hardware_router"
|
||||||
app:key="routeOutbound"
|
app:key="groupFrontProxy"
|
||||||
app:title="@string/front_proxy"
|
app:title="@string/front_proxy"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<io.nekohasekai.sagernet.widget.OutboundPreference
|
||||||
|
app:icon="@drawable/baseline_public_24"
|
||||||
|
app:key="groupLandingProxy"
|
||||||
|
app:title="@string/landing_proxy"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
app:key="groupSubscription"
|
app:key="groupSubscription"
|
||||||
app:title="@string/subscription_settings">
|
app:title="@string/subscription_settings">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user