Add SettingsChangeManager and centralize restart logic

This commit is contained in:
2dust
2026-01-05 10:40:55 +08:00
parent 37bd57ffc5
commit 71f0d98e68
10 changed files with 60 additions and 28 deletions
@@ -567,10 +567,6 @@ object MmkvManager {
return settingsStorage.decodeStringSet(key)
}
//endregion
//region Others
/**
* Encodes the start on boot setting.
*
@@ -594,17 +590,17 @@ object MmkvManager {
//region WebDAV
/**
* Encodes the WebDAV config as JSON into settings storage.
* Encodes the WebDAV config as JSON into storage.
*/
fun encodeWebDavConfig(config: WebDavConfig): Boolean {
return settingsStorage.encode(KEY_WEBDAV_CONFIG, JsonUtil.toJson(config))
return mainStorage.encode(KEY_WEBDAV_CONFIG, JsonUtil.toJson(config))
}
/**
* Decodes the WebDAV config from settings storage.
* Decodes the WebDAV config from storage.
*/
fun decodeWebDavConfig(): WebDavConfig? {
val json = settingsStorage.decodeString(KEY_WEBDAV_CONFIG) ?: return null
val json = mainStorage.decodeString(KEY_WEBDAV_CONFIG) ?: return null
return JsonUtil.fromJson(json, WebDavConfig::class.java)
}
@@ -0,0 +1,32 @@
package com.v2ray.ang.handler
import kotlinx.coroutines.flow.MutableStateFlow
object SettingsChangeManager {
private val _restartService = MutableStateFlow(false)
private val _reinitGroupTab = MutableStateFlow(false)
// Mark restartService as requiring a restart
fun makeRestartService() {
_restartService.value = true
}
// Read and clear the restartService flag
fun consumeRestartService(): Boolean {
val v = _restartService.value
_restartService.value = false
return v
}
// Mark reinitGroupTab as requiring tab reinitialization
fun makeReinitGroupTab() {
_reinitGroupTab.value = true
}
// Read and clear the reinitGroupTab flag
fun consumeReinitGroupTab(): Boolean {
val v = _reinitGroupTab.value
_reinitGroupTab.value = false
return v
}
}
@@ -70,7 +70,7 @@ object V2RayServiceManager {
* @param context The context from which the service is stopped.
*/
fun stopVService(context: Context) {
context.toast(R.string.toast_services_stop)
//context.toast(R.string.toast_services_stop)
MessageUtil.sendMsg2Service(context, AppConfig.MSG_STATE_STOP, "")
}
@@ -27,6 +27,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import com.v2ray.ang.databinding.DialogWebdavBinding
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.util.ZipUtil
import java.io.File
import java.text.SimpleDateFormat
@@ -169,6 +170,8 @@ class BackupActivity : BaseActivity() {
}
val count = MMKV.restoreAllFromDirectory(backupDir)
SettingsChangeManager.makeReinitGroupTab()
SettingsChangeManager.makeRestartService()
return count > 0
}
@@ -312,7 +315,6 @@ class BackupActivity : BaseActivity() {
val restored = restoreConfiguration(target)
withContext(Dispatchers.Main) {
if (restored) {
setResult(RESULT_OK, Intent().putExtra("config_restored", true))
toastSuccess(R.string.toast_success)
} else {
toastError(R.string.toast_failure)
@@ -36,6 +36,7 @@ import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.toastError
import com.v2ray.ang.handler.AngConfigManager
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.handler.V2RayServiceManager
import com.v2ray.ang.util.Utils
@@ -57,7 +58,12 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
}
private val requestActivityLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
initGroupTab()
if (SettingsChangeManager.consumeRestartService() && mainViewModel.isRunning.value == true) {
restartV2Ray()
}
if (SettingsChangeManager.consumeReinitGroupTab()) {
initGroupTab()
}
}
private val tabGroupListener = object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
@@ -255,7 +261,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
V2RayServiceManager.startVService(this)
}
private fun restartV2Ray() {
public fun restartV2Ray() {
if (mainViewModel.isRunning.value == true) {
V2RayServiceManager.stopVService(this)
}
@@ -673,14 +679,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.sub_setting -> requestActivityLauncher.launch(Intent(this, SubSettingActivity::class.java))
R.id.per_app_proxy_settings -> startActivity(Intent(this, PerAppProxyActivity::class.java))
R.id.per_app_proxy_settings -> requestActivityLauncher.launch(Intent(this, PerAppProxyActivity::class.java))
R.id.routing_setting -> requestActivityLauncher.launch(Intent(this, RoutingSettingActivity::class.java))
R.id.user_asset_setting -> startActivity(Intent(this, UserAssetActivity::class.java))
R.id.settings -> startActivity(
Intent(this, SettingsActivity::class.java)
.putExtra("isRunning", mainViewModel.isRunning.value == true)
)
R.id.user_asset_setting -> requestActivityLauncher.launch(Intent(this, UserAssetActivity::class.java))
R.id.settings -> requestActivityLauncher.launch(Intent(this, SettingsActivity::class.java))
R.id.promotion -> Utils.openUri(this, "${Utils.decode(AppConfig.APP_PROMOTION_URL)}?t=${System.currentTimeMillis()}")
R.id.logcat -> startActivity(Intent(this, LogcatActivity::class.java))
R.id.check_for_update -> startActivity(Intent(this, CheckUpdateActivity::class.java))
@@ -311,15 +311,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
}
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
if (isRunning) {
V2RayServiceManager.stopVService(mActivity)
mActivity.lifecycleScope.launch {
try {
delay(500)
V2RayServiceManager.startVService(mActivity)
} catch (e: Exception) {
Log.e(AppConfig.TAG, "Failed to restart V2Ray service", e)
}
}
mActivity.restartV2Ray()
}
}
}
@@ -18,6 +18,7 @@ import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.toastSuccess
import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.handler.SettingsManager
import com.v2ray.ang.util.AppManagerUtil
import com.v2ray.ang.util.HttpUtil
@@ -216,6 +217,7 @@ class PerAppProxyActivity : BaseActivity() {
private fun allowPerAppProxy() {
binding.switchPerAppProxy.isChecked = true
SettingsChangeManager.makeRestartService()
}
@SuppressLint("NotifyDataSetChanged")
@@ -6,6 +6,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.v2ray.ang.databinding.ItemRecyclerBypassListBinding
import com.v2ray.ang.dto.AppInfo
import com.v2ray.ang.handler.SettingsChangeManager
class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) :
RecyclerView.Adapter<PerAppProxyAdapter.BaseViewHolder>() {
@@ -83,6 +84,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
blacklist.add(appInfo.packageName)
itemBypassBinding.checkBox.isChecked = true
}
SettingsChangeManager.makeRestartService()
}
}
}
@@ -13,6 +13,7 @@ import com.v2ray.ang.dto.SubscriptionItem
import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.toastSuccess
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -30,6 +31,7 @@ class SubEditActivity : BaseActivity() {
setContentView(binding.root)
title = getString(R.string.title_sub_setting)
SettingsChangeManager.makeReinitGroupTab()
val subItem = MmkvManager.decodeSubscription(editSubId)
if (subItem != null) {
bindingServer(subItem)
@@ -7,6 +7,7 @@ import androidx.lifecycle.AndroidViewModel
import androidx.preference.PreferenceManager
import com.v2ray.ang.AppConfig
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.handler.SettingsManager
class SettingsViewModel(application: Application) : AndroidViewModel(application),
@@ -100,5 +101,6 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
if (key == AppConfig.PREF_UI_MODE_NIGHT) {
SettingsManager.setNightMode()
}
SettingsChangeManager.makeRestartService()
}
}