Skip to content

Commit 835fcca

Browse files
committed
dev global custom config
1 parent 7c46729 commit 835fcca

File tree

15 files changed

+134
-63
lines changed

15 files changed

+134
-63
lines changed

app/src/main/java/io/nekohasekai/sagernet/Constants.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ object Key {
1616
const val MODE_VPN = "vpn"
1717
const val MODE_PROXY = "proxy"
1818

19+
const val GLOBAL_CUSTOM_CONFIG = "globalCustomConfig"
20+
1921
const val REMOTE_DNS = "remoteDns"
2022
const val DIRECT_DNS = "directDns"
2123
const val ENABLE_DNS_ROUTING = "enableDnsRouting"

app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ object DataStore : OnPreferenceDataStoreChangeListener {
108108
var speedInterval by configurationStore.stringToInt(Key.SPEED_INTERVAL)
109109
var showGroupInNotification by configurationStore.boolean("showGroupInNotification")
110110

111+
var globalCustomConfig by configurationStore.string(Key.GLOBAL_CUSTOM_CONFIG) { "" }
112+
111113
var remoteDns by configurationStore.string(Key.REMOTE_DNS) { "https://dns.google/dns-query" }
112114
var directDns by configurationStore.string(Key.DIRECT_DNS) { "https://223.5.5.5/dns-query" }
113115
var enableDnsRouting by configurationStore.boolean(Key.ENABLE_DNS_ROUTING) { true }

app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import moe.matsuri.nb4a.proxy.config.ConfigBean
3535
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean
3636
import moe.matsuri.nb4a.proxy.shadowtls.buildSingBoxOutboundShadowTLSBean
3737
import moe.matsuri.nb4a.utils.JavaUtil.gson
38+
import moe.matsuri.nb4a.utils.Util
3839
import moe.matsuri.nb4a.utils.listByLineOrComma
3940
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
4041

@@ -335,9 +336,7 @@ fun buildConfig(
335336
// internal outbound
336337

337338
currentOutbound = when (bean) {
338-
is ConfigBean -> SingBoxOption().apply {
339-
_hack_custom_config = bean.config
340-
}
339+
is ConfigBean -> CustomSingBoxOption(bean.config)
341340

342341
is ShadowTLSBean -> // before StandardV2RayBean
343342
buildSingBoxOutboundShadowTLSBean(bean)
@@ -367,7 +366,7 @@ fun buildConfig(
367366
buildSingBoxOutboundAnyTLSBean(bean)
368367

369368
else -> throw IllegalStateException("can't reach")
370-
} as SingBoxOption
369+
}
371370

372371
// internal mux
373372
if (!muxApplied) {
@@ -739,10 +738,12 @@ fun buildConfig(
739738
}
740739
}
741740

742-
_hack_custom_config = proxy.requireBean().customConfigJson
741+
_hack_custom_config = DataStore.globalCustomConfig
743742
}.let {
743+
val configMap = it.asMap()
744+
Util.mergeJSON(configMap, proxy.requireBean().customConfigJson)
744745
ConfigBuildResult(
745-
gson.toJson(it.asMap()),
746+
gson.toJson(configMap),
746747
externalIndexMap,
747748
proxy.id,
748749
trafficMap,

app/src/main/java/io/nekohasekai/sagernet/ui/BackupFragment.kt

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import io.nekohasekai.sagernet.databinding.LayoutBackupBinding
2323
import io.nekohasekai.sagernet.databinding.LayoutImportBinding
2424
import io.nekohasekai.sagernet.databinding.LayoutProgressBinding
2525
import io.nekohasekai.sagernet.ktx.*
26+
import kotlinx.coroutines.delay
2627
import moe.matsuri.nb4a.utils.Util
2728
import org.json.JSONArray
2829
import org.json.JSONObject
@@ -34,33 +35,53 @@ class BackupFragment : NamedFragment(R.layout.layout_backup) {
3435
override fun name0() = app.getString(R.string.backup)
3536

3637
var content = ""
37-
private val exportSettings = registerForActivityResult(ActivityResultContracts.CreateDocument()) { data ->
38-
if (data != null) {
39-
runOnDefaultDispatcher {
40-
try {
41-
requireActivity().contentResolver.openOutputStream(
42-
data
43-
)!!.bufferedWriter().use {
44-
it.write(content)
45-
}
46-
onMainDispatcher {
47-
snackbar(getString(R.string.action_export_msg)).show()
48-
}
49-
} catch (e: Exception) {
50-
Logs.w(e)
51-
onMainDispatcher {
52-
snackbar(e.readableMessage).show()
38+
private val exportSettings =
39+
registerForActivityResult(ActivityResultContracts.CreateDocument()) { data ->
40+
if (data != null) {
41+
runOnDefaultDispatcher {
42+
try {
43+
requireActivity().contentResolver.openOutputStream(
44+
data
45+
)!!.bufferedWriter().use {
46+
it.write(content)
47+
}
48+
onMainDispatcher {
49+
snackbar(getString(R.string.action_export_msg)).show()
50+
}
51+
} catch (e: Exception) {
52+
Logs.w(e)
53+
onMainDispatcher {
54+
snackbar(e.readableMessage).show()
55+
}
5356
}
5457
}
55-
5658
}
5759
}
58-
}
5960

6061
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
6162
super.onViewCreated(view, savedInstanceState)
6263

6364
val binding = LayoutBackupBinding.bind(view)
65+
66+
binding.resetSettings.setOnClickListener {
67+
MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.confirm)
68+
.setMessage(R.string.reset_settings)
69+
.setNegativeButton(R.string.no, null)
70+
.setPositiveButton(R.string.yes) { _, _ ->
71+
runOnDefaultDispatcher {
72+
DataStore.configurationStore.reset()
73+
delay(500)
74+
runOnMainDispatcher {
75+
ProcessPhoenix.triggerRebirth(
76+
requireContext(),
77+
Intent(requireContext(), MainActivity::class.java)
78+
)
79+
}
80+
}
81+
}
82+
.show()
83+
}
84+
6485
binding.actionExport.setOnClickListener {
6586
runOnDefaultDispatcher {
6687
content = doBackup(

app/src/main/java/io/nekohasekai/sagernet/ui/DebugFragment.kt

Lines changed: 0 additions & 28 deletions
This file was deleted.

app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
2222

2323
private lateinit var isProxyApps: SwitchPreference
2424

25+
private lateinit var globalCustomConfig: EditConfigPreference
26+
27+
2528
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2629
super.onViewCreated(view, savedInstanceState)
2730

@@ -77,6 +80,8 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
7780

7881
val logLevel = findPreference<LongClickListPreference>(Key.LOG_LEVEL)!!
7982
val mtu = findPreference<MTUPreference>(Key.MTU)!!
83+
globalCustomConfig = findPreference(Key.GLOBAL_CUSTOM_CONFIG)!!
84+
globalCustomConfig.useConfigStore(Key.GLOBAL_CUSTOM_CONFIG)
8085

8186
logLevel.dialogLayoutResource = R.layout.layout_loglevel_help
8287
logLevel.setOnPreferenceChangeListener { _, _ ->
@@ -162,7 +167,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
162167
resolveDestination.onPreferenceChangeListener = reloadListener
163168
tunImplementation.onPreferenceChangeListener = reloadListener
164169
acquireWakeLock.onPreferenceChangeListener = reloadListener
165-
170+
globalCustomConfig.onPreferenceChangeListener = reloadListener
166171
}
167172

168173
override fun onResume() {
@@ -171,6 +176,9 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
171176
if (::isProxyApps.isInitialized) {
172177
isProxyApps.isChecked = DataStore.proxyApps
173178
}
179+
if (::globalCustomConfig.isInitialized) {
180+
globalCustomConfig.notifyChanged()
181+
}
174182
}
175183

176184
}

app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
77
import com.google.android.material.tabs.TabLayoutMediator
88
import io.nekohasekai.sagernet.R
99
import io.nekohasekai.sagernet.databinding.LayoutToolsBinding
10-
import io.nekohasekai.sagernet.ktx.isExpert
1110

1211
class ToolsFragment : ToolbarFragment(R.layout.layout_tools) {
1312

@@ -19,8 +18,6 @@ class ToolsFragment : ToolbarFragment(R.layout.layout_tools) {
1918
tools.add(NetworkFragment())
2019
tools.add(BackupFragment())
2120

22-
if (isExpert) tools.add(DebugFragment())
23-
2421
val binding = LayoutToolsBinding.bind(view)
2522
binding.toolsPager.adapter = ToolsAdapter(tools)
2623

app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class ConfigEditActivity : ThemedActivity() {
3333

3434
var dirty = false
3535
var key = Key.SERVER_CONFIG
36+
var useConfigStore = false
3637

3738
class UnsavedChangesDialogFragment : AlertDialogFragment<Empty, Empty>() {
3839
override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) {
@@ -55,6 +56,7 @@ class ConfigEditActivity : ThemedActivity() {
5556

5657
intent?.extras?.apply {
5758
getString("key")?.let { key = it }
59+
getString("useConfigStore")?.let { useConfigStore = true }
5860
}
5961

6062
binding = LayoutEditConfigBinding.inflate(layoutInflater)
@@ -70,7 +72,11 @@ class ConfigEditActivity : ThemedActivity() {
7072
binding.editor.apply {
7173
language = JsonLanguage()
7274
setHorizontallyScrolling(true)
73-
setTextContent(DataStore.profileCacheStore.getString(key)!!)
75+
if (useConfigStore) {
76+
setTextContent(DataStore.configurationStore.getString(key) ?: "")
77+
} else {
78+
setTextContent(DataStore.profileCacheStore.getString(key) ?: "")
79+
}
7480
addTextChangedListener {
7581
if (!dirty) {
7682
dirty = true
@@ -142,7 +148,11 @@ class ConfigEditActivity : ThemedActivity() {
142148

143149
fun saveAndExit() {
144150
formatText()?.let {
145-
DataStore.profileCacheStore.putString(key, it)
151+
if (useConfigStore) {
152+
DataStore.configurationStore.putString(key, it)
153+
} else {
154+
DataStore.profileCacheStore.putString(key, it)
155+
}
146156
finish()
147157
}
148158
}

app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@ public Map<String, Object> asMap() {
4747

4848
}
4949

50+
public static final class CustomSingBoxOption extends SingBoxOption {
51+
52+
public transient String config;
53+
54+
public CustomSingBoxOption(String config) {
55+
super();
56+
this.config = config;
57+
}
58+
59+
public Map<String, Object> getBasicMap() {
60+
Map<String, Object> map = gsonSingbox.fromJson(config, Map.class);
61+
if (map == null) {
62+
map = new HashMap<>();
63+
}
64+
return map;
65+
}
66+
}
67+
5068
// 自定义序列化器
5169
public static class SingBoxOptionSerializer implements JsonSerializer<SingBoxOption> {
5270
@Override
@@ -61,7 +79,12 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
6179
},
6280
TypeToken.get(src.getClass())
6381
);
64-
Map<String, Object> map = gsonSingbox.fromJson(((TypeAdapter<SingBoxOption>) delegate).toJson(src), Map.class);
82+
Map<String, Object> map;
83+
if (src instanceof CustomSingBoxOption) {
84+
map = ((CustomSingBoxOption) src).getBasicMap();
85+
} else {
86+
map = gsonSingbox.fromJson(((TypeAdapter<SingBoxOption>) delegate).toJson(src), Map.class);
87+
}
6588
if (src._hack_config_map != null && !src._hack_config_map.isEmpty()) {
6689
Util.INSTANCE.mergeMap(map, src._hack_config_map);
6790
}

app/src/main/java/moe/matsuri/nb4a/ui/EditConfigPreference.kt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import android.content.Context
44
import android.content.Intent
55
import android.util.AttributeSet
66
import androidx.preference.Preference
7+
import io.nekohasekai.sagernet.Key
78
import io.nekohasekai.sagernet.R
89
import io.nekohasekai.sagernet.database.DataStore
10+
import io.nekohasekai.sagernet.ktx.Logs
911
import io.nekohasekai.sagernet.ktx.app
1012
import io.nekohasekai.sagernet.ui.profile.ConfigEditActivity
1113

@@ -26,9 +28,27 @@ class EditConfigPreference : Preference {
2628
intent = Intent(context, ConfigEditActivity::class.java)
2729
}
2830

31+
var configKey = Key.SERVER_CONFIG
32+
var useConfigStore = false
33+
34+
fun useConfigStore(key: String) {
35+
try {
36+
this.configKey = key
37+
useConfigStore = true
38+
intent = intent!!.apply {
39+
putExtra("useConfigStore", "1")
40+
putExtra("key", key)
41+
}
42+
} catch (e: Exception) {
43+
Logs.w(e)
44+
}
45+
}
46+
2947
override fun getSummary(): CharSequence {
30-
val config = DataStore.serverConfig
31-
return if (DataStore.serverConfig.isBlank()) {
48+
val config =
49+
(if (useConfigStore) DataStore.configurationStore.getString(configKey) else DataStore.serverConfig)
50+
?: ""
51+
return if (config.isBlank()) {
3252
return app.resources.getString(androidx.preference.R.string.not_set)
3353
} else {
3454
app.resources.getString(R.string.lines, config.split('\n').size)

0 commit comments

Comments
 (0)