Preserve app picker state on Activity recreation (#5972)
* Preserve app picker selection on recreation * Avoid reloading app picker data on recreation
This commit is contained in:
1 parent
070abd78ea
commit
aacc8e091f
2 files changed
+48
-10
No files matched your search
@@ -8,6 +8,7 @@ import com.v2ray.ang.dto.AppInfo
|
||||
import com.v2ray.ang.ui.base.BaseViewModel
|
||||
import com.v2ray.ang.util.AppManagerUtil
|
||||
import com.v2ray.ang.util.LogUtil
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -26,28 +27,40 @@ class AppPickerViewModel(application: Application) : BaseViewModel(application)
|
||||
private val _displayedApps = MutableStateFlow<List<AppInfo>>(emptyList())
|
||||
val displayedApps: StateFlow<List<AppInfo>> = _displayedApps.asStateFlow()
|
||||
|
||||
private var appsAll: List<AppInfo> = emptyList()
|
||||
private var allApps: List<AppInfo>? = null
|
||||
private var currentQuery: String = ""
|
||||
private var SelectedSnapshot: Set<String> = emptySet()
|
||||
private var selectedSnapshot: Set<String> = emptySet()
|
||||
private var initialized = false
|
||||
private var isAppListLoading = false
|
||||
|
||||
fun initialize(initialSelected: Collection<String>) {
|
||||
if (initialized) return
|
||||
initialized = true
|
||||
_selectedPackages.value = initialSelected.toSet()
|
||||
}
|
||||
|
||||
fun loadApps(context: Context) {
|
||||
if (allApps != null || isAppListLoading) return
|
||||
|
||||
val applicationContext = context.applicationContext
|
||||
isAppListLoading = true
|
||||
launchLoading {
|
||||
try {
|
||||
SelectedSnapshot = _selectedPackages.value.toSet()
|
||||
selectedSnapshot = _selectedPackages.value
|
||||
val apps = withContext(Dispatchers.IO) {
|
||||
val list = AppManagerUtil.loadNetworkAppList(context)
|
||||
val special = createSpecialItemUnidentified(context)
|
||||
val list = AppManagerUtil.loadNetworkAppList(applicationContext)
|
||||
val special = createSpecialItemUnidentified(applicationContext)
|
||||
sortApps(list + special)
|
||||
}
|
||||
appsAll = apps
|
||||
allApps = apps
|
||||
_displayedApps.value = applyFilter(currentQuery)
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
LogUtil.e("AppPickerViewModel", "Failed to load app list", e)
|
||||
toastError(R.string.toast_failure)
|
||||
} finally {
|
||||
isAppListLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,16 +94,18 @@ class AppPickerViewModel(application: Application) : BaseViewModel(application)
|
||||
fun getSelectedPackages(): List<String> = _selectedPackages.value.sorted()
|
||||
|
||||
private fun applyFilter(query: String): List<AppInfo> {
|
||||
if (query.isBlank()) return appsAll
|
||||
val apps = allApps ?: return emptyList()
|
||||
if (query.isBlank()) return apps
|
||||
|
||||
val key = query.uppercase()
|
||||
return appsAll.filter {
|
||||
return apps.filter {
|
||||
it.appName.uppercase().contains(key) || it.packageName.uppercase().contains(key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortApps(apps: List<AppInfo>): List<AppInfo> {
|
||||
val collator = Collator.getInstance()
|
||||
val snapshot = SelectedSnapshot
|
||||
val snapshot = selectedSnapshot
|
||||
return apps.sortedWith { p1, p2 ->
|
||||
val p1Selected = snapshot.contains(p1.packageName)
|
||||
val p2Selected = snapshot.contains(p2.packageName)
|
||||
@@ -116,4 +131,4 @@ class AppPickerViewModel(application: Application) : BaseViewModel(application)
|
||||
isSelected = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.v2ray.ang.ui.apppicker
|
||||
|
||||
import android.app.Application
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
class AppPickerViewModelTest {
|
||||
|
||||
@Test
|
||||
fun initialize_preservesChangesAfterFirstCall() {
|
||||
val viewModel = AppPickerViewModel(mock<Application>())
|
||||
|
||||
viewModel.initialize(listOf("initial.package"))
|
||||
viewModel.toggleApp("added.package")
|
||||
viewModel.initialize(listOf("initial.package"))
|
||||
|
||||
assertEquals(
|
||||
setOf("initial.package", "added.package"),
|
||||
viewModel.selectedPackages.value
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user