mirror of
https://github.com/Hamza417/Inure.git
synced 2026-03-13 10:19:43 +08:00
improve: use flow in batch uninstaller
This commit is contained in:
@@ -30,10 +30,10 @@ class AdapterBatchUninstaller(private val results: ArrayList<BatchUninstaller.Co
|
||||
holder.name.text = result.packageInfo.packageName
|
||||
}
|
||||
|
||||
holder.result.text = if (result.isSuccessful) {
|
||||
holder.itemView.context.getString(R.string.uninstalled)
|
||||
} else {
|
||||
holder.itemView.context.getString(R.string.failed)
|
||||
holder.result.text = when (result.isSuccessful) {
|
||||
null -> holder.itemView.context.getString(R.string.pending)
|
||||
true -> holder.itemView.context.getString(R.string.uninstalled)
|
||||
false -> holder.itemView.context.getString(R.string.failed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,16 @@ class AdapterBatchUninstaller(private val results: ArrayList<BatchUninstaller.Co
|
||||
return results.size
|
||||
}
|
||||
|
||||
fun updateResults(newResults: ArrayList<BatchUninstaller.Companion.BatchUninstallerResult>) {
|
||||
// Find which items changed and notify only those
|
||||
for (i in results.indices) {
|
||||
if (i < newResults.size && results[i].isSuccessful != newResults[i].isSuccessful) {
|
||||
results[i] = newResults[i]
|
||||
notifyItemChanged(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class Holder(itemView: View) : VerticalListViewHolder(itemView) {
|
||||
val icon: ImageView = itemView.findViewById(R.id.app_icon)
|
||||
val name: TypeFaceTextView = itemView.findViewById(R.id.app_name)
|
||||
|
||||
@@ -6,22 +6,21 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.simple.inure.R
|
||||
import app.simple.inure.adapters.batch.AdapterBatchUninstaller
|
||||
import app.simple.inure.constants.BundleConstants
|
||||
import app.simple.inure.decorations.overscroll.CustomVerticalRecyclerView
|
||||
import app.simple.inure.decorations.views.LoaderImageView
|
||||
import app.simple.inure.extensions.fragments.ScopedBottomSheetFragment
|
||||
import app.simple.inure.factories.panels.BatchViewModelFactory
|
||||
import app.simple.inure.models.BatchPackageInfo
|
||||
import app.simple.inure.util.ParcelUtils.parcelableArrayList
|
||||
import app.simple.inure.util.ViewUtils.gone
|
||||
import app.simple.inure.viewmodels.dialogs.BatchUninstallerViewModel
|
||||
import app.simple.inure.viewmodels.panels.BatchViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class BatchUninstaller : ScopedBottomSheetFragment() {
|
||||
|
||||
private lateinit var loader: LoaderImageView
|
||||
private lateinit var recyclerView: CustomVerticalRecyclerView
|
||||
private var adapterBatchUninstaller: AdapterBatchUninstaller? = null
|
||||
|
||||
@@ -32,7 +31,6 @@ class BatchUninstaller : ScopedBottomSheetFragment() {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.dialog_batch_uninstall, container, false)
|
||||
|
||||
loader = view.findViewById(R.id.loader)
|
||||
recyclerView = view.findViewById(R.id.recycler_view)
|
||||
|
||||
appList = requireArguments().parcelableArrayList(BundleConstants.selectedBatchApps)!!
|
||||
@@ -47,12 +45,17 @@ class BatchUninstaller : ScopedBottomSheetFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
loader.start()
|
||||
|
||||
batchUninstallerViewModel?.getData()?.observe(viewLifecycleOwner) {
|
||||
loader.gone()
|
||||
adapterBatchUninstaller = AdapterBatchUninstaller(it)
|
||||
recyclerView.adapter = adapterBatchUninstaller
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
batchUninstallerViewModel?.uninstallResults?.collect { results ->
|
||||
if (adapterBatchUninstaller == null) {
|
||||
// Initialize adapter with the first emission (all pending)
|
||||
adapterBatchUninstaller = AdapterBatchUninstaller(results)
|
||||
recyclerView.adapter = adapterBatchUninstaller
|
||||
} else {
|
||||
// Update existing adapter with new results
|
||||
adapterBatchUninstaller?.updateResults(results)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +72,7 @@ class BatchUninstaller : ScopedBottomSheetFragment() {
|
||||
|
||||
data class BatchUninstallerResult(
|
||||
val packageInfo: PackageInfo,
|
||||
val isSuccessful: Boolean
|
||||
val isSuccessful: Boolean? // null = pending, true = success, false = failed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package app.simple.inure.viewmodels.dialogs
|
||||
import android.app.Application
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.simple.inure.apk.utils.PackageUtils.safeApplicationInfo
|
||||
import app.simple.inure.constants.Warnings
|
||||
@@ -14,39 +12,38 @@ import app.simple.inure.helpers.ShizukuServiceHelper
|
||||
import app.simple.inure.models.BatchPackageInfo
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class BatchUninstallerViewModel(application: Application, val list: ArrayList<BatchPackageInfo>) : RootShizukuViewModel(application) {
|
||||
|
||||
private val data: MutableLiveData<ArrayList<BatchUninstallerResult>> by lazy {
|
||||
MutableLiveData<ArrayList<BatchUninstallerResult>>().also {
|
||||
initializeCoreFramework()
|
||||
}
|
||||
}
|
||||
private val _uninstallResults = MutableStateFlow<ArrayList<BatchUninstallerResult>>(arrayListOf())
|
||||
val uninstallResults: StateFlow<ArrayList<BatchUninstallerResult>> = _uninstallResults.asStateFlow()
|
||||
|
||||
fun getData(): LiveData<ArrayList<BatchUninstallerResult>> {
|
||||
return data
|
||||
init {
|
||||
// Initialize with pending state for all apps
|
||||
val initialResults = ArrayList(list.map { BatchUninstallerResult(it.packageInfo, null) })
|
||||
_uninstallResults.value = initialResults
|
||||
initializeCoreFramework()
|
||||
}
|
||||
|
||||
override fun onShellCreated(shell: Shell?) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val uninstalledApps = arrayListOf<BatchUninstallerResult>()
|
||||
val results = ArrayList(_uninstallResults.value)
|
||||
|
||||
for (app in list) {
|
||||
for ((index, app) in list.withIndex()) {
|
||||
runCatching {
|
||||
Shell.cmd(app.packageInfo.getUninstallCommand()).exec().let {
|
||||
if (it.isSuccess) {
|
||||
uninstalledApps.add(BatchUninstallerResult(app.packageInfo, true))
|
||||
} else {
|
||||
uninstalledApps.add(BatchUninstallerResult(app.packageInfo, false))
|
||||
}
|
||||
results[index] = BatchUninstallerResult(app.packageInfo, it.isSuccess)
|
||||
_uninstallResults.value = ArrayList(results)
|
||||
}
|
||||
}.onFailure {
|
||||
uninstalledApps.add(BatchUninstallerResult(app.packageInfo, false))
|
||||
results[index] = BatchUninstallerResult(app.packageInfo, false)
|
||||
_uninstallResults.value = ArrayList(results)
|
||||
}
|
||||
}
|
||||
|
||||
data.postValue(uninstalledApps)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,23 +61,19 @@ class BatchUninstallerViewModel(application: Application, val list: ArrayList<Ba
|
||||
|
||||
override fun onShizukuCreated(shizukuServiceHelper: ShizukuServiceHelper) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val uninstalledApps = arrayListOf<BatchUninstallerResult>()
|
||||
val results = ArrayList(_uninstallResults.value)
|
||||
|
||||
for (app in list) {
|
||||
for ((index, app) in list.withIndex()) {
|
||||
runCatching {
|
||||
shizukuServiceHelper.service!!.simpleExecute(app.packageInfo.getUninstallCommand()).let {
|
||||
if (it.isSuccess) {
|
||||
uninstalledApps.add(BatchUninstallerResult(app.packageInfo, true))
|
||||
} else {
|
||||
uninstalledApps.add(BatchUninstallerResult(app.packageInfo, false))
|
||||
}
|
||||
results[index] = BatchUninstallerResult(app.packageInfo, it.isSuccess)
|
||||
_uninstallResults.value = ArrayList(results)
|
||||
}
|
||||
}.onFailure {
|
||||
uninstalledApps.add(BatchUninstallerResult(app.packageInfo, false))
|
||||
results[index] = BatchUninstallerResult(app.packageInfo, false)
|
||||
_uninstallResults.value = ArrayList(results)
|
||||
}
|
||||
}
|
||||
|
||||
data.postValue(uninstalledApps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,6 @@
|
||||
app:isTopFadingEdgeOnly="false"
|
||||
app:statusBarPaddingRequired="false" />
|
||||
|
||||
<app.simple.inure.decorations.views.LoaderImageView
|
||||
android:id="@+id/loader"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="@dimen/loader_size"
|
||||
android:layout_height="@dimen/loader_size" />
|
||||
|
||||
</app.simple.inure.decorations.corners.DynamicCornerFrameLayout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user