mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-19 14:40:06 +08:00
feat: clash api selector callback
This commit is contained in:
parent
46526560d8
commit
dd648447eb
@ -9,4 +9,5 @@ oneway interface ISagerNetServiceCallback {
|
|||||||
void routeAlert(int type, String routeName);
|
void routeAlert(int type, String routeName);
|
||||||
void cbSpeedUpdate(in SpeedDisplayData stats);
|
void cbSpeedUpdate(in SpeedDisplayData stats);
|
||||||
void cbTrafficUpdate(in TrafficData stats);
|
void cbTrafficUpdate(in TrafficData stats);
|
||||||
|
void cbSelectorUpdate(long id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,9 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import go.Seq
|
import go.Seq
|
||||||
import io.nekohasekai.sagernet.bg.SagerConnection
|
import io.nekohasekai.sagernet.bg.SagerConnection
|
||||||
|
import io.nekohasekai.sagernet.bg.ServiceNotification
|
||||||
import io.nekohasekai.sagernet.database.DataStore
|
import io.nekohasekai.sagernet.database.DataStore
|
||||||
|
import io.nekohasekai.sagernet.database.SagerDatabase
|
||||||
import io.nekohasekai.sagernet.ktx.Logs
|
import io.nekohasekai.sagernet.ktx.Logs
|
||||||
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
|
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
|
||||||
import io.nekohasekai.sagernet.ui.MainActivity
|
import io.nekohasekai.sagernet.ui.MainActivity
|
||||||
@ -266,4 +268,22 @@ class SagerNet : Application(),
|
|||||||
return DataStore.rulesProvider == 0
|
return DataStore.rulesProvider == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun selector_OnProxySelected(tag: String) {
|
||||||
|
DataStore.baseService?.apply {
|
||||||
|
runOnDefaultDispatcher {
|
||||||
|
val id = data.proxy!!.config.profileTagMap
|
||||||
|
.filterValues { it == tag }.keys.firstOrNull() ?: -1
|
||||||
|
val ent = SagerDatabase.proxyDao.getById(id) ?: return@runOnDefaultDispatcher
|
||||||
|
// traffic & title
|
||||||
|
data.proxy!!.looper?.selectMain(id)
|
||||||
|
val title = ServiceNotification.genTitle(ent)
|
||||||
|
data.notification?.postNotificationTitle(title)
|
||||||
|
// post MainActivity animation
|
||||||
|
data.binder.broadcast { b ->
|
||||||
|
b.cbSelectorUpdate(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,7 @@ class BaseService {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> service.stopRunner()
|
else -> service.stopRunner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,12 +166,10 @@ class BaseService {
|
|||||||
val ent = SagerDatabase.proxyDao.getById(DataStore.selectedProxy)
|
val ent = SagerDatabase.proxyDao.getById(DataStore.selectedProxy)
|
||||||
val tag = data.proxy!!.config.profileTagMap[ent?.id] ?: ""
|
val tag = data.proxy!!.config.profileTagMap[ent?.id] ?: ""
|
||||||
if (tag.isNotBlank() && ent != null) {
|
if (tag.isNotBlank() && ent != null) {
|
||||||
val success = data.proxy!!.box.selectOutbound(tag)
|
// select from GUI
|
||||||
if (success) runOnDefaultDispatcher {
|
data.proxy!!.box.selectOutbound(tag)
|
||||||
data.proxy!!.looper?.selectMain(ent.id)
|
// or select from webui
|
||||||
val title = ServiceNotification.genTitle(ent)
|
// => selector_OnProxySelected
|
||||||
data.notification?.postNotificationTitle(title)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ class SagerConnection(
|
|||||||
|
|
||||||
fun cbSpeedUpdate(stats: SpeedDisplayData) {}
|
fun cbSpeedUpdate(stats: SpeedDisplayData) {}
|
||||||
fun cbTrafficUpdate(data: TrafficData) {}
|
fun cbTrafficUpdate(data: TrafficData) {}
|
||||||
|
fun cbSelectorUpdate(id: Long) {}
|
||||||
|
|
||||||
fun stateChanged(state: BaseService.State, profileName: String?, msg: String?)
|
fun stateChanged(state: BaseService.State, profileName: String?, msg: String?)
|
||||||
|
|
||||||
@ -83,6 +84,13 @@ class SagerConnection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun cbSelectorUpdate(id: Long) {
|
||||||
|
val callback = callback ?: return
|
||||||
|
runOnMainDispatcher {
|
||||||
|
callback.cbSelectorUpdate(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun missingPlugin(profileName: String, pluginName: String) {
|
override fun missingPlugin(profileName: String, pluginName: String) {
|
||||||
val callback = callback ?: return
|
val callback = callback ?: return
|
||||||
runOnMainDispatcher {
|
runOnMainDispatcher {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import io.nekohasekai.sagernet.database.ProfileManager
|
|||||||
import io.nekohasekai.sagernet.fmt.TAG_BYPASS
|
import io.nekohasekai.sagernet.fmt.TAG_BYPASS
|
||||||
import io.nekohasekai.sagernet.fmt.TAG_PROXY
|
import io.nekohasekai.sagernet.fmt.TAG_PROXY
|
||||||
import io.nekohasekai.sagernet.ktx.Logs
|
import io.nekohasekai.sagernet.ktx.Logs
|
||||||
|
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
class TrafficLooper
|
class TrafficLooper
|
||||||
@ -55,14 +56,22 @@ class TrafficLooper
|
|||||||
fun selectMain(id: Long) {
|
fun selectMain(id: Long) {
|
||||||
Logs.d("select traffic count $TAG_PROXY to $id, old id is $selectorNowId")
|
Logs.d("select traffic count $TAG_PROXY to $id, old id is $selectorNowId")
|
||||||
val oldData = items[selectorNowId]
|
val oldData = items[selectorNowId]
|
||||||
val data = items[id] ?: return
|
val newData = items[id] ?: return
|
||||||
oldData?.apply {
|
oldData?.apply {
|
||||||
tag = selectorNowFakeTag
|
tag = selectorNowFakeTag
|
||||||
ignore = true
|
ignore = true
|
||||||
|
// post traffic when switch
|
||||||
|
data.proxy?.config?.trafficMap?.get(tag)?.firstOrNull()?.let {
|
||||||
|
it.rx = rx
|
||||||
|
it.tx = tx
|
||||||
|
runOnDefaultDispatcher {
|
||||||
|
ProfileManager.updateProfile(it) // update DB
|
||||||
}
|
}
|
||||||
selectorNowFakeTag = data.tag
|
}
|
||||||
|
}
|
||||||
|
selectorNowFakeTag = newData.tag
|
||||||
selectorNowId = id
|
selectorNowId = id
|
||||||
data.apply {
|
newData.apply {
|
||||||
tag = TAG_PROXY
|
tag = TAG_PROXY
|
||||||
ignore = false
|
ignore = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ object ProfileManager {
|
|||||||
interface Listener {
|
interface Listener {
|
||||||
suspend fun onAdd(profile: ProxyEntity)
|
suspend fun onAdd(profile: ProxyEntity)
|
||||||
suspend fun onUpdated(data: TrafficData)
|
suspend fun onUpdated(data: TrafficData)
|
||||||
suspend fun onUpdated(profile: ProxyEntity)
|
suspend fun onUpdated(profile: ProxyEntity, noTraffic: Boolean)
|
||||||
suspend fun onRemoved(groupId: Long, profileId: Long)
|
suspend fun onRemoved(groupId: Long, profileId: Long)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,13 +87,13 @@ object ProfileManager {
|
|||||||
|
|
||||||
suspend fun updateProfile(profile: ProxyEntity) {
|
suspend fun updateProfile(profile: ProxyEntity) {
|
||||||
SagerDatabase.proxyDao.updateProxy(profile)
|
SagerDatabase.proxyDao.updateProxy(profile)
|
||||||
iterator { onUpdated(profile) }
|
iterator { onUpdated(profile, false) }
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateProfile(profiles: List<ProxyEntity>) {
|
suspend fun updateProfile(profiles: List<ProxyEntity>) {
|
||||||
SagerDatabase.proxyDao.updateProxy(profiles)
|
SagerDatabase.proxyDao.updateProxy(profiles)
|
||||||
profiles.forEach {
|
profiles.forEach {
|
||||||
iterator { onUpdated(it) }
|
iterator { onUpdated(it, false) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,12 +141,12 @@ object ProfileManager {
|
|||||||
|
|
||||||
// postUpdate: post to listeners, don't change the DB
|
// postUpdate: post to listeners, don't change the DB
|
||||||
|
|
||||||
suspend fun postUpdate(profileId: Long) {
|
suspend fun postUpdate(profileId: Long, noTraffic: Boolean = false) {
|
||||||
postUpdate(getProfile(profileId) ?: return)
|
postUpdate(getProfile(profileId) ?: return, noTraffic)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun postUpdate(profile: ProxyEntity) {
|
suspend fun postUpdate(profile: ProxyEntity, noTraffic: Boolean = false) {
|
||||||
iterator { onUpdated(profile) }
|
iterator { onUpdated(profile, noTraffic) }
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun postUpdate(data: TrafficData) {
|
suspend fun postUpdate(data: TrafficData) {
|
||||||
|
|||||||
@ -293,6 +293,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
R.id.action_scan_qr_code -> {
|
R.id.action_scan_qr_code -> {
|
||||||
startActivity(Intent(context, ScannerActivity::class.java))
|
startActivity(Intent(context, ScannerActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_import_clipboard -> {
|
R.id.action_import_clipboard -> {
|
||||||
val text = SagerNet.getClipboardText()
|
val text = SagerNet.getClipboardText()
|
||||||
if (text.isBlank()) {
|
if (text.isBlank()) {
|
||||||
@ -314,56 +315,73 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_import_file -> {
|
R.id.action_import_file -> {
|
||||||
startFilesForResult(importFile, "*/*")
|
startFilesForResult(importFile, "*/*")
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_socks -> {
|
R.id.action_new_socks -> {
|
||||||
startActivity(Intent(requireActivity(), SocksSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), SocksSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_http -> {
|
R.id.action_new_http -> {
|
||||||
startActivity(Intent(requireActivity(), HttpSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), HttpSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_ss -> {
|
R.id.action_new_ss -> {
|
||||||
startActivity(Intent(requireActivity(), ShadowsocksSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), ShadowsocksSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_vmess -> {
|
R.id.action_new_vmess -> {
|
||||||
startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_vless -> {
|
R.id.action_new_vless -> {
|
||||||
startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java).apply {
|
startActivity(Intent(requireActivity(), VMessSettingsActivity::class.java).apply {
|
||||||
putExtra("vless", true)
|
putExtra("vless", true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_trojan -> {
|
R.id.action_new_trojan -> {
|
||||||
startActivity(Intent(requireActivity(), TrojanSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), TrojanSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_trojan_go -> {
|
R.id.action_new_trojan_go -> {
|
||||||
startActivity(Intent(requireActivity(), TrojanGoSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), TrojanGoSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_naive -> {
|
R.id.action_new_naive -> {
|
||||||
startActivity(Intent(requireActivity(), NaiveSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), NaiveSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_hysteria -> {
|
R.id.action_new_hysteria -> {
|
||||||
startActivity(Intent(requireActivity(), HysteriaSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), HysteriaSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_tuic -> {
|
R.id.action_new_tuic -> {
|
||||||
startActivity(Intent(requireActivity(), TuicSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), TuicSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_ssh -> {
|
R.id.action_new_ssh -> {
|
||||||
startActivity(Intent(requireActivity(), SSHSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), SSHSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_wg -> {
|
R.id.action_new_wg -> {
|
||||||
startActivity(Intent(requireActivity(), WireGuardSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), WireGuardSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_shadowtls -> {
|
R.id.action_new_shadowtls -> {
|
||||||
startActivity(Intent(requireActivity(), ShadowTLSSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), ShadowTLSSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_config -> {
|
R.id.action_new_config -> {
|
||||||
startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java))
|
startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_chain -> {
|
R.id.action_new_chain -> {
|
||||||
startActivity(Intent(requireActivity(), ChainSettingsActivity::class.java))
|
startActivity(Intent(requireActivity(), ChainSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_new_neko -> {
|
R.id.action_new_neko -> {
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
lateinit var dialog: AlertDialog
|
lateinit var dialog: AlertDialog
|
||||||
@ -395,6 +413,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
.setView(linearLayout)
|
.setView(linearLayout)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_clear_traffic_statistics -> {
|
R.id.action_clear_traffic_statistics -> {
|
||||||
runOnDefaultDispatcher {
|
runOnDefaultDispatcher {
|
||||||
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
||||||
@ -411,6 +430,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_connection_test_clear_results -> {
|
R.id.action_connection_test_clear_results -> {
|
||||||
runOnDefaultDispatcher {
|
runOnDefaultDispatcher {
|
||||||
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
||||||
@ -428,6 +448,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_connection_test_delete_unavailable -> {
|
R.id.action_connection_test_delete_unavailable -> {
|
||||||
runOnDefaultDispatcher {
|
runOnDefaultDispatcher {
|
||||||
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
||||||
@ -466,6 +487,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_remove_duplicate -> {
|
R.id.action_remove_duplicate -> {
|
||||||
runOnDefaultDispatcher {
|
runOnDefaultDispatcher {
|
||||||
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
val profiles = SagerDatabase.proxyDao.getByGroup(DataStore.currentGroupId())
|
||||||
@ -517,9 +539,11 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_connection_tcp_ping -> {
|
R.id.action_connection_tcp_ping -> {
|
||||||
pingTest(false)
|
pingTest(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_connection_url_test -> {
|
R.id.action_connection_url_test -> {
|
||||||
urlTest()
|
urlTest()
|
||||||
}
|
}
|
||||||
@ -561,18 +585,22 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
profileStatusText = profile.error
|
profileStatusText = profile.error
|
||||||
profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary)
|
profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
0 -> {
|
0 -> {
|
||||||
profileStatusText = getString(R.string.connection_test_testing)
|
profileStatusText = getString(R.string.connection_test_testing)
|
||||||
profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary)
|
profileStatusColor = context.getColorAttr(android.R.attr.textColorSecondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
profileStatusText = getString(R.string.available, profile.ping)
|
profileStatusText = getString(R.string.available, profile.ping)
|
||||||
profileStatusColor = context.getColour(R.color.material_green_500)
|
profileStatusColor = context.getColour(R.color.material_green_500)
|
||||||
}
|
}
|
||||||
|
|
||||||
2 -> {
|
2 -> {
|
||||||
profileStatusText = profile.error
|
profileStatusText = profile.error
|
||||||
profileStatusColor = context.getColour(R.color.material_red_500)
|
profileStatusColor = context.getColour(R.color.material_red_500)
|
||||||
}
|
}
|
||||||
|
|
||||||
3 -> {
|
3 -> {
|
||||||
val err = profile.error ?: ""
|
val err = profile.error ?: ""
|
||||||
val msg = Protocols.genFriendlyMsg(err)
|
val msg = Protocols.genFriendlyMsg(err)
|
||||||
@ -705,15 +733,18 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
when {
|
when {
|
||||||
!message.contains("failed:") -> profile.error =
|
!message.contains("failed:") -> profile.error =
|
||||||
getString(R.string.connection_test_timeout)
|
getString(R.string.connection_test_timeout)
|
||||||
|
|
||||||
else -> when {
|
else -> when {
|
||||||
message.contains("ECONNREFUSED") -> {
|
message.contains("ECONNREFUSED") -> {
|
||||||
profile.error =
|
profile.error =
|
||||||
getString(R.string.connection_test_refused)
|
getString(R.string.connection_test_refused)
|
||||||
}
|
}
|
||||||
|
|
||||||
message.contains("ENETUNREACH") -> {
|
message.contains("ENETUNREACH") -> {
|
||||||
profile.error =
|
profile.error =
|
||||||
getString(R.string.connection_test_unreachable)
|
getString(R.string.connection_test_unreachable)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
profile.status = 3
|
profile.status = 3
|
||||||
profile.error = message
|
profile.error = message
|
||||||
@ -939,7 +970,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
|
|
||||||
override suspend fun onUpdated(data: TrafficData) = Unit
|
override suspend fun onUpdated(data: TrafficData) = Unit
|
||||||
|
|
||||||
override suspend fun onUpdated(profile: ProxyEntity) = Unit
|
override suspend fun onUpdated(profile: ProxyEntity, noTraffic: Boolean) = Unit
|
||||||
|
|
||||||
override suspend fun onRemoved(groupId: Long, profileId: Long) {
|
override suspend fun onRemoved(groupId: Long, profileId: Long) {
|
||||||
val group = groupList.find { it.id == groupId } ?: return
|
val group = groupList.find { it.id == groupId } ?: return
|
||||||
@ -1034,9 +1065,11 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
GroupOrder.ORIGIN -> {
|
GroupOrder.ORIGIN -> {
|
||||||
origin.isChecked = true
|
origin.isChecked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupOrder.BY_NAME -> {
|
GroupOrder.BY_NAME -> {
|
||||||
byName.isChecked = true
|
byName.isChecked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupOrder.BY_DELAY -> {
|
GroupOrder.BY_DELAY -> {
|
||||||
byDelay.isChecked = true
|
byDelay.isChecked = true
|
||||||
}
|
}
|
||||||
@ -1267,7 +1300,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onUpdated(profile: ProxyEntity) {
|
override suspend fun onUpdated(profile: ProxyEntity, noTraffic: Boolean) {
|
||||||
if (profile.groupId != proxyGroup.id) return
|
if (profile.groupId != proxyGroup.id) return
|
||||||
val index = configurationIdList.indexOf(profile.id)
|
val index = configurationIdList.indexOf(profile.id)
|
||||||
if (index < 0) return
|
if (index < 0) return
|
||||||
@ -1275,9 +1308,21 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
if (::undoManager.isInitialized) {
|
if (::undoManager.isInitialized) {
|
||||||
undoManager.flush()
|
undoManager.flush()
|
||||||
}
|
}
|
||||||
val oldProfile = configurationList[profile.id]
|
|
||||||
configurationList[profile.id] = profile
|
configurationList[profile.id] = profile
|
||||||
notifyItemChanged(index)
|
notifyItemChanged(index)
|
||||||
|
//
|
||||||
|
val oldProfile = configurationList[profile.id]
|
||||||
|
if (noTraffic && oldProfile != null) {
|
||||||
|
runOnDefaultDispatcher {
|
||||||
|
onUpdated(
|
||||||
|
TrafficData(
|
||||||
|
id = profile.id,
|
||||||
|
rx = oldProfile.rx,
|
||||||
|
tx = oldProfile.tx
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1333,6 +1378,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
newProfiles = newProfiles.sortedBy { it.displayName() }
|
newProfiles = newProfiles.sortedBy { it.displayName() }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupOrder.BY_DELAY -> {
|
GroupOrder.BY_DELAY -> {
|
||||||
newProfiles =
|
newProfiles =
|
||||||
newProfiles.sortedBy { if (it.status == 1) it.ping else 114514 }
|
newProfiles.sortedBy { if (it.status == 1) it.ping else 114514 }
|
||||||
@ -1538,6 +1584,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
R.id.action_standard_clipboard
|
R.id.action_standard_clipboard
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
!proxyEntity.haveLink() -> {
|
!proxyEntity.haveLink() -> {
|
||||||
popup.menu.removeItem(R.id.action_group_qr)
|
popup.menu.removeItem(R.id.action_group_qr)
|
||||||
popup.menu.removeItem(R.id.action_group_clipboard)
|
popup.menu.removeItem(R.id.action_group_clipboard)
|
||||||
@ -1589,6 +1636,7 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
R.id.action_universal_clipboard -> export(
|
R.id.action_universal_clipboard -> export(
|
||||||
entity.requireBean().toUniversalLink()
|
entity.requireBean().toUniversalLink()
|
||||||
)
|
)
|
||||||
|
|
||||||
R.id.action_config_export_clipboard -> export(entity.exportConfig().first)
|
R.id.action_config_export_clipboard -> export(entity.exportConfig().first)
|
||||||
R.id.action_config_export_file -> {
|
R.id.action_config_export_file -> {
|
||||||
val cfg = entity.exportConfig()
|
val cfg = entity.exportConfig()
|
||||||
|
|||||||
@ -300,6 +300,7 @@ class MainActivity : ThemedActivity(),
|
|||||||
R.id.nav_configuration -> {
|
R.id.nav_configuration -> {
|
||||||
displayFragment(ConfigurationFragment())
|
displayFragment(ConfigurationFragment())
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_group -> displayFragment(GroupFragment())
|
R.id.nav_group -> displayFragment(GroupFragment())
|
||||||
R.id.nav_route -> displayFragment(RouteFragment())
|
R.id.nav_route -> displayFragment(RouteFragment())
|
||||||
R.id.nav_settings -> displayFragment(SettingsFragment())
|
R.id.nav_settings -> displayFragment(SettingsFragment())
|
||||||
@ -310,11 +311,13 @@ class MainActivity : ThemedActivity(),
|
|||||||
launchCustomTab("https://matsuridayo.github.io/")
|
launchCustomTab("https://matsuridayo.github.io/")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_about -> displayFragment(AboutFragment())
|
R.id.nav_about -> displayFragment(AboutFragment())
|
||||||
R.id.nav_tuiguang -> {
|
R.id.nav_tuiguang -> {
|
||||||
launchCustomTab("https://matsuricom.github.io/")
|
launchCustomTab("https://matsuricom.github.io/")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return false
|
else -> return false
|
||||||
}
|
}
|
||||||
navigation.menu.findItem(id).isChecked = true
|
navigation.menu.findItem(id).isChecked = true
|
||||||
@ -352,6 +355,7 @@ class MainActivity : ThemedActivity(),
|
|||||||
ProfileManager.postUpdate(DataStore.currentProfile)
|
ProfileManager.postUpdate(DataStore.currentProfile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,6 +416,16 @@ class MainActivity : ThemedActivity(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun cbSelectorUpdate(id: Long) {
|
||||||
|
val old = DataStore.selectedProxy
|
||||||
|
DataStore.selectedProxy = id
|
||||||
|
DataStore.currentProfile = id
|
||||||
|
runOnDefaultDispatcher {
|
||||||
|
ProfileManager.postUpdate(old, true)
|
||||||
|
ProfileManager.postUpdate(id, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) {
|
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String) {
|
||||||
when (key) {
|
when (key) {
|
||||||
Key.SERVICE_MODE -> onBinderDied()
|
Key.SERVICE_MODE -> onBinderDied()
|
||||||
@ -449,6 +463,7 @@ class MainActivity : ThemedActivity(),
|
|||||||
binding.drawerLayout.open()
|
binding.drawerLayout.open()
|
||||||
navigation.requestFocus()
|
navigation.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||||
if (binding.drawerLayout.isOpen) {
|
if (binding.drawerLayout.isOpen) {
|
||||||
binding.drawerLayout.close()
|
binding.drawerLayout.close()
|
||||||
|
|||||||
@ -16,7 +16,10 @@ class SwitchActivity : ThemedActivity(R.layout.layout_empty),
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.replace(R.id.fragment_holder, ConfigurationFragment(true, null, R.string.action_switch))
|
.replace(
|
||||||
|
R.id.fragment_holder,
|
||||||
|
ConfigurationFragment(true, null, R.string.action_switch)
|
||||||
|
)
|
||||||
.commitAllowingStateLoss()
|
.commitAllowingStateLoss()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,8 +27,8 @@ class SwitchActivity : ThemedActivity(R.layout.layout_empty),
|
|||||||
val old = DataStore.selectedProxy
|
val old = DataStore.selectedProxy
|
||||||
DataStore.selectedProxy = profileId
|
DataStore.selectedProxy = profileId
|
||||||
runOnMainDispatcher {
|
runOnMainDispatcher {
|
||||||
ProfileManager.postUpdate(old)
|
ProfileManager.postUpdate(old, true)
|
||||||
ProfileManager.postUpdate(profileId)
|
ProfileManager.postUpdate(profileId, true)
|
||||||
}
|
}
|
||||||
SagerNet.reloadService()
|
SagerNet.reloadService()
|
||||||
finish()
|
finish()
|
||||||
|
|||||||
@ -9,9 +9,9 @@ export PATH=$golang/go/bin:$GOPATH/bin:$PATH
|
|||||||
source buildScript/init/env_ndk.sh
|
source buildScript/init/env_ndk.sh
|
||||||
|
|
||||||
if [[ "$OSTYPE" =~ ^darwin ]]; then
|
if [[ "$OSTYPE" =~ ^darwin ]]; then
|
||||||
export PROJECT=$PWD
|
export SRC_ROOT=$PWD
|
||||||
else
|
else
|
||||||
export PROJECT=$(realpath .)
|
export SRC_ROOT=$(realpath .)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DEPS=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
|
DEPS=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin
|
||||||
|
|||||||
26
buildScript/lib/core/get_source.sh
Executable file
26
buildScript/lib/core/get_source.sh
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
source "buildScript/init/env.sh"
|
||||||
|
ENV_NB4A=1
|
||||||
|
source "buildScript/lib/core/get_source_env.sh"
|
||||||
|
pushd ..
|
||||||
|
|
||||||
|
######
|
||||||
|
## From nekoray/libs/get_source.sh
|
||||||
|
######
|
||||||
|
|
||||||
|
####
|
||||||
|
if [ ! -d "sing-box-extra" ]; then
|
||||||
|
git clone --no-checkout https://github.com/MatsuriDayo/sing-box-extra.git
|
||||||
|
fi
|
||||||
|
pushd sing-box-extra
|
||||||
|
git checkout "$COMMIT_SING_BOX_EXTRA"
|
||||||
|
|
||||||
|
ENV_SING_BOX_EXTRA=1
|
||||||
|
source $SRC_ROOT/buildScript/lib/core/get_source_env.sh
|
||||||
|
NO_ENV=1 ./libs/get_source.sh
|
||||||
|
|
||||||
|
popd
|
||||||
|
|
||||||
|
popd
|
||||||
8
buildScript/lib/core/get_source_env.sh
Normal file
8
buildScript/lib/core/get_source_env.sh
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
if [ ! -z $ENV_NB4A ]; then
|
||||||
|
export COMMIT_SING_BOX_EXTRA="a4eacbd0e54b6ec0a42096c42b6137a5be91a0bc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z $ENV_SING_BOX_EXTRA ]; then
|
||||||
|
source libs/get_source_env.sh
|
||||||
|
export COMMIT_SING_BOX="91495e813068294aae506fdd769437c41dd8d3a3"
|
||||||
|
fi
|
||||||
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
source "buildScript/init/env.sh"
|
source "buildScript/init/env.sh"
|
||||||
|
|
||||||
|
# fetch soucre
|
||||||
|
bash buildScript/lib/core/get_source.sh
|
||||||
|
|
||||||
[ -f libcore/go.mod ] || exit 1
|
[ -f libcore/go.mod ] || exit 1
|
||||||
cd libcore
|
cd libcore
|
||||||
|
|
||||||
|
|||||||
@ -4,12 +4,12 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/codeclysm/extract v2.2.0+incompatible
|
github.com/codeclysm/extract v2.2.0+incompatible
|
||||||
github.com/matsuridayo/libneko v0.0.0-20230315005352-9d7e3f3a79d1
|
github.com/matsuridayo/libneko v1.0.0 // replaced
|
||||||
github.com/matsuridayo/sing-box-extra v0.0.0-20230417014110-39b3adb5f93f
|
github.com/matsuridayo/sing-box-extra v1.0.0 // replaced
|
||||||
github.com/miekg/dns v1.1.53
|
github.com/miekg/dns v1.1.53
|
||||||
github.com/sagernet/sing v0.2.3
|
github.com/sagernet/sing v0.2.3
|
||||||
github.com/sagernet/sing-box v1.2.4
|
github.com/sagernet/sing-box v1.0.0 // replaced
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc
|
github.com/sagernet/sing-dns v1.0.0 // replaced
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
|
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
|
||||||
github.com/ulikunitz/xz v0.5.10
|
github.com/ulikunitz/xz v0.5.10
|
||||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105
|
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105
|
||||||
@ -93,10 +93,10 @@ require (
|
|||||||
lukechampine.com/blake3 v1.1.7 // indirect
|
lukechampine.com/blake3 v1.1.7 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// replace github.com/matsuridayo/libneko => ../../libneko
|
replace github.com/matsuridayo/libneko v1.0.0 => ../../libneko
|
||||||
|
|
||||||
// replace github.com/matsuridayo/sing-box-extra => ../../sing-box-extra
|
replace github.com/matsuridayo/sing-box-extra v1.0.0 => ../../sing-box-extra
|
||||||
|
|
||||||
replace github.com/sagernet/sing-dns => github.com/matsuridayo/sing-dns v0.0.0-20230420050318-63790a1843f8
|
replace github.com/sagernet/sing-box v1.0.0 => ../../sing-box
|
||||||
|
|
||||||
replace github.com/sagernet/sing-box => github.com/matsuridayo/sing-box v0.0.0-20230419123417-eaa058f8a077
|
replace github.com/sagernet/sing-dns v1.0.0 => ../../sing-dns
|
||||||
|
|||||||
@ -76,14 +76,6 @@ github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
|||||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/matsuridayo/libneko v0.0.0-20230315005352-9d7e3f3a79d1 h1:+FflyEuq2hn++MENFuT1/qFHz0KITKK/F6ZHxs23mrg=
|
|
||||||
github.com/matsuridayo/libneko v0.0.0-20230315005352-9d7e3f3a79d1/go.mod h1:IRO07Queptz/rGFvEW+3Hmwpx7MCup6WiDs4p5jMt4g=
|
|
||||||
github.com/matsuridayo/sing-box v0.0.0-20230419123417-eaa058f8a077 h1:k2glJShoEN6l1aBVkxETzlspS9Q+/MEJR9B8z5kirhA=
|
|
||||||
github.com/matsuridayo/sing-box v0.0.0-20230419123417-eaa058f8a077/go.mod h1:LDW5ZOuWURxSWz+auElryalxCBlGbA0zvsC8XSy8Sp0=
|
|
||||||
github.com/matsuridayo/sing-box-extra v0.0.0-20230417014110-39b3adb5f93f h1:x0UjjMoYh5WSDGhIuRkmZUhGoxXnK++wyvuPnURhz6Q=
|
|
||||||
github.com/matsuridayo/sing-box-extra v0.0.0-20230417014110-39b3adb5f93f/go.mod h1:NfCwDELPcVFo8rp0d/P7M2OPmegGCGcwF4GSpgZu8Rs=
|
|
||||||
github.com/matsuridayo/sing-dns v0.0.0-20230420050318-63790a1843f8 h1:eEXScrFlYLiXp2n6G6nnRQVPH81TFF1DGu0xqCFcPHY=
|
|
||||||
github.com/matsuridayo/sing-dns v0.0.0-20230420050318-63790a1843f8/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
|
|
||||||
github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
||||||
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
||||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/matsuridayo/libneko/neko_common"
|
"github.com/matsuridayo/libneko/neko_common"
|
||||||
"github.com/matsuridayo/libneko/neko_log"
|
"github.com/matsuridayo/libneko/neko_log"
|
||||||
"github.com/matsuridayo/sing-box-extra/boxmain"
|
"github.com/matsuridayo/sing-box-extra/boxmain"
|
||||||
|
"github.com/sagernet/sing-box/nekoutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname resourcePaths github.com/sagernet/sing-box/constant.resourcePaths
|
//go:linkname resourcePaths github.com/sagernet/sing-box/constant.resourcePaths
|
||||||
@ -62,6 +63,9 @@ func InitCore(process, cachePath, internalAssets, externalAssets string,
|
|||||||
neko_log.SetupLog(int(maxLogSizeKb)*1024, filepath.Join(cachePath, "neko.log"))
|
neko_log.SetupLog(int(maxLogSizeKb)*1024, filepath.Join(cachePath, "neko.log"))
|
||||||
boxmain.DisableColor()
|
boxmain.DisableColor()
|
||||||
|
|
||||||
|
// nekoutils
|
||||||
|
nekoutils.Selector_OnProxySelected = iif.Selector_OnProxySelected
|
||||||
|
|
||||||
// Set up some component
|
// Set up some component
|
||||||
go func() {
|
go func() {
|
||||||
defer device.DeferPanicToError("InitCore-go", func(err error) { log.Println(err) })
|
defer device.DeferPanicToError("InitCore-go", func(err error) { log.Println(err) })
|
||||||
|
|||||||
@ -7,6 +7,7 @@ var useProcfs bool
|
|||||||
|
|
||||||
type NB4AInterface interface {
|
type NB4AInterface interface {
|
||||||
UseOfficialAssets() bool
|
UseOfficialAssets() bool
|
||||||
|
Selector_OnProxySelected(tag string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalResolver interface {
|
type LocalResolver interface {
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
go get github.com/sagernet/sing-box@"$1"
|
|
||||||
go mod tidy
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
go get github.com/matsuridayo/sing-box-extra@"$1"
|
|
||||||
go mod tidy
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
go get github.com/matsuridayo/libneko@"$1"
|
|
||||||
go mod tidy
|
|
||||||
Loading…
Reference in New Issue
Block a user