Refactor per-app proxy logic to ViewModel
This commit is contained in:
1 parent
68ed08d36e
commit
4a3686fb32
3 files changed
+101
-69
No files matched your search
@@ -7,6 +7,7 @@ import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.v2ray.ang.AppConfig
|
||||
@@ -23,6 +24,7 @@ import com.v2ray.ang.handler.SettingsManager
|
||||
import com.v2ray.ang.util.AppManagerUtil
|
||||
import com.v2ray.ang.util.HttpUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.PerAppProxyViewModel
|
||||
import es.dmoral.toasty.Toasty
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -34,6 +36,7 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
|
||||
private var adapter: PerAppProxyAdapter? = null
|
||||
private var appsAll: List<AppInfo>? = null
|
||||
private val viewModel: PerAppProxyViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -64,14 +67,13 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val blacklist =
|
||||
MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
||||
val apps = withContext(Dispatchers.IO) {
|
||||
val appsList = AppManagerUtil.loadNetworkAppList(this@PerAppProxyActivity)
|
||||
|
||||
if (blacklist != null) {
|
||||
val blacklistSet = viewModel.getAll()
|
||||
if (blacklistSet.isNotEmpty()) {
|
||||
appsList.forEach { app ->
|
||||
app.isSelected = if (blacklist.contains(app.packageName)) 1 else 0
|
||||
app.isSelected = if (blacklistSet.contains(app.packageName)) 1 else 0
|
||||
}
|
||||
appsList.sortedWith { p1, p2 ->
|
||||
when {
|
||||
@@ -93,8 +95,9 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
appsAll = apps
|
||||
adapter = PerAppProxyAdapter(this@PerAppProxyActivity, apps, blacklist)
|
||||
adapter = PerAppProxyAdapter(this@PerAppProxyActivity, apps, viewModel)
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(ANG_PACKAGE, "Error loading apps", e)
|
||||
} finally {
|
||||
@@ -103,13 +106,6 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
adapter?.let {
|
||||
MmkvManager.encodeSettings(AppConfig.PREF_PER_APP_PROXY_SET, it.blacklist)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_bypass_list, menu)
|
||||
|
||||
@@ -164,33 +160,23 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun selectAllApp() {
|
||||
adapter?.let { it ->
|
||||
val pkgNames = it.apps.map { it.packageName }
|
||||
if (it.blacklist.containsAll(pkgNames)) {
|
||||
it.apps.forEach {
|
||||
val packageName = it.packageName
|
||||
adapter?.blacklist?.remove(packageName)
|
||||
}
|
||||
adapter?.let { adapter ->
|
||||
val pkgNames = adapter.apps.map { it.packageName }
|
||||
val allSelected = pkgNames.all { viewModel.contains(it) }
|
||||
|
||||
if (allSelected) {
|
||||
viewModel.removeAll(pkgNames)
|
||||
} else {
|
||||
it.apps.forEach {
|
||||
val packageName = it.packageName
|
||||
adapter?.blacklist?.add(packageName)
|
||||
}
|
||||
viewModel.addAll(pkgNames)
|
||||
}
|
||||
it.notifyDataSetChanged()
|
||||
true
|
||||
refreshData()
|
||||
}
|
||||
}
|
||||
|
||||
private fun invertSelection() {
|
||||
adapter?.let { adapter ->
|
||||
adapter.apps.forEach { app ->
|
||||
val packageName = app.packageName
|
||||
if (adapter.blacklist.contains(packageName)) {
|
||||
adapter.blacklist.remove(packageName)
|
||||
} else {
|
||||
adapter.blacklist.add(packageName)
|
||||
}
|
||||
viewModel.toggle(app.packageName)
|
||||
}
|
||||
refreshData()
|
||||
}
|
||||
@@ -226,8 +212,8 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
private fun exportProxyApp() {
|
||||
var lst = binding.switchBypassApps.isChecked.toString()
|
||||
|
||||
adapter?.blacklist?.forEach block@{
|
||||
lst = lst + System.lineSeparator() + it
|
||||
viewModel.getAll().forEach { pkg ->
|
||||
lst = lst + System.lineSeparator() + pkg
|
||||
}
|
||||
Utils.setClipboard(applicationContext, lst)
|
||||
toastSuccess(R.string.toast_success)
|
||||
@@ -248,29 +234,27 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
}
|
||||
if (TextUtils.isEmpty(proxyApps)) return false
|
||||
|
||||
adapter?.blacklist?.clear()
|
||||
viewModel.clear()
|
||||
|
||||
if (binding.switchBypassApps.isChecked) {
|
||||
adapter?.let { it ->
|
||||
it.apps.forEach block@{
|
||||
val packageName = it.packageName
|
||||
adapter?.let { adapter ->
|
||||
adapter.apps.forEach { app ->
|
||||
val packageName = app.packageName
|
||||
if (!inProxyApps(proxyApps, packageName, force)) {
|
||||
adapter?.blacklist?.add(packageName)
|
||||
return@block
|
||||
viewModel.add(packageName)
|
||||
}
|
||||
}
|
||||
it.notifyDataSetChanged()
|
||||
refreshData()
|
||||
}
|
||||
} else {
|
||||
adapter?.let { it ->
|
||||
it.apps.forEach block@{
|
||||
val packageName = it.packageName
|
||||
adapter?.let { adapter ->
|
||||
adapter.apps.forEach { app ->
|
||||
val packageName = app.packageName
|
||||
if (inProxyApps(proxyApps, packageName, force)) {
|
||||
adapter?.blacklist?.add(packageName)
|
||||
return@block
|
||||
viewModel.add(packageName)
|
||||
}
|
||||
}
|
||||
it.notifyDataSetChanged()
|
||||
refreshData()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -308,7 +292,7 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
adapter = PerAppProxyAdapter(this, apps, adapter?.blacklist)
|
||||
adapter = PerAppProxyAdapter(this, apps, adapter?.viewModel ?: viewModel)
|
||||
binding.recyclerView.adapter = adapter
|
||||
refreshData()
|
||||
return true
|
||||
|
||||
@@ -6,9 +6,9 @@ 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
|
||||
import com.v2ray.ang.viewmodel.PerAppProxyViewModel
|
||||
|
||||
class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) :
|
||||
class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, val viewModel: PerAppProxyViewModel) :
|
||||
RecyclerView.Adapter<PerAppProxyAdapter.BaseViewHolder>() {
|
||||
|
||||
companion object {
|
||||
@@ -16,8 +16,6 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
|
||||
private const val VIEW_TYPE_ITEM = 1
|
||||
}
|
||||
|
||||
val blacklist = if (blacklist == null) HashSet() else HashSet(blacklist)
|
||||
|
||||
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
|
||||
if (holder is AppViewHolder) {
|
||||
val appInfo = apps[position - 1]
|
||||
@@ -39,11 +37,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
|
||||
)
|
||||
BaseViewHolder(view)
|
||||
}
|
||||
// VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater
|
||||
// .inflate(R.layout.item_recycler_bypass_list, parent, false))
|
||||
|
||||
else -> AppViewHolder(ItemRecyclerBypassListBinding.inflate(LayoutInflater.from(ctx), parent, false))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,13 +47,11 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
|
||||
|
||||
inner class AppViewHolder(private val itemBypassBinding: ItemRecyclerBypassListBinding) : BaseViewHolder(itemBypassBinding.root),
|
||||
View.OnClickListener {
|
||||
private val inBlacklist: Boolean get() = blacklist.contains(appInfo.packageName)
|
||||
private lateinit var appInfo: AppInfo
|
||||
|
||||
fun bind(appInfo: AppInfo) {
|
||||
this.appInfo = appInfo
|
||||
|
||||
// Set app icon and name
|
||||
itemBypassBinding.icon.setImageDrawable(appInfo.appIcon)
|
||||
itemBypassBinding.name.text = if (appInfo.isSystemApp) {
|
||||
String.format("** %s", appInfo.appName)
|
||||
@@ -67,24 +59,16 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
|
||||
appInfo.appName
|
||||
}
|
||||
|
||||
// Set package name and checkbox state
|
||||
itemBypassBinding.packageName.text = appInfo.packageName
|
||||
itemBypassBinding.checkBox.isChecked = inBlacklist
|
||||
itemBypassBinding.checkBox.isChecked = viewModel.contains(appInfo.packageName)
|
||||
|
||||
// Handle item click to toggle blacklist status
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
if (inBlacklist) {
|
||||
blacklist.remove(appInfo.packageName)
|
||||
itemBypassBinding.checkBox.isChecked = false
|
||||
} else {
|
||||
blacklist.add(appInfo.packageName)
|
||||
itemBypassBinding.checkBox.isChecked = true
|
||||
}
|
||||
SettingsChangeManager.makeRestartService()
|
||||
val packageName = appInfo.packageName
|
||||
viewModel.toggle(packageName)
|
||||
itemBypassBinding.checkBox.isChecked = viewModel.contains(packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.v2ray.ang.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SettingsChangeManager
|
||||
|
||||
class PerAppProxyViewModel : ViewModel() {
|
||||
private val blacklist: MutableSet<String> = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)?.let {
|
||||
HashSet(it)
|
||||
} ?: HashSet()
|
||||
|
||||
fun contains(packageName: String): Boolean = blacklist.contains(packageName)
|
||||
|
||||
fun getAll(): Set<String> = blacklist.toSet()
|
||||
|
||||
fun add(packageName: String): Boolean {
|
||||
val changed = blacklist.add(packageName)
|
||||
if (changed) {
|
||||
save()
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
fun remove(packageName: String): Boolean {
|
||||
val changed = blacklist.remove(packageName)
|
||||
if (changed) {
|
||||
save()
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
fun toggle(packageName: String) {
|
||||
if (blacklist.contains(packageName)) {
|
||||
remove(packageName)
|
||||
} else {
|
||||
add(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
fun addAll(packages: Collection<String>) {
|
||||
if (blacklist.addAll(packages)) {
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAll(packages: Collection<String>) {
|
||||
if (blacklist.removeAll(packages.toSet())) {
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
if (blacklist.isNotEmpty()) {
|
||||
blacklist.clear()
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
private fun save() {
|
||||
MmkvManager.encodeSettings(AppConfig.PREF_PER_APP_PROXY_SET, blacklist)
|
||||
SettingsChangeManager.makeRestartService()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user