Refactor InstallResult to be more extensible

This commit is contained in:
Torsten Grote 2020-10-08 10:16:51 -03:00 committed by Chirayu Desai
parent f45411d81b
commit 747384fb59
3 changed files with 51 additions and 15 deletions

View file

@ -15,7 +15,6 @@ import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.restore.RestoreViewModel import com.stevesoltys.seedvault.restore.RestoreViewModel
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class InstallProgressFragment : Fragment() { class InstallProgressFragment : Fragment() {
@ -75,12 +74,11 @@ class InstallProgressFragment : Fragment() {
// skip this screen, if there are no apps to install // skip this screen, if there are no apps to install
if (installResult.isEmpty()) viewModel.onNextClicked() if (installResult.isEmpty()) viewModel.onNextClicked()
val result = installResult.filterValues { it.state != QUEUED }
val position = layoutManager.findFirstVisibleItemPosition() val position = layoutManager.findFirstVisibleItemPosition()
adapter.update(result.values) adapter.update(installResult.getNotQueued())
if (position == 0) layoutManager.scrollToPosition(0) if (position == 0) layoutManager.scrollToPosition(0)
result.getInProgress()?.let { installResult.getInProgress()?.let {
progressBar.progress = it.progress progressBar.progress = it.progress
progressBar.max = it.total progressBar.max = it.total
} }

View file

@ -1,28 +1,66 @@
package com.stevesoltys.seedvault.restore.install package com.stevesoltys.seedvault.restore.install
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
internal typealias InstallResult = Map<String, ApkInstallResult> internal interface InstallResult {
/**
* Returns true, if there is no packages to install and false otherwise.
*/
fun isEmpty(): Boolean
internal fun InstallResult.getInProgress(): ApkInstallResult? { /**
val filtered = filterValues { result -> result.state == ApkInstallState.IN_PROGRESS } * Returns the [ApkInstallResult] of the package currently [IN_PROGRESS]
if (filtered.isEmpty()) return null * or null if there is no such package.
check(filtered.size == 1) { "More than one package in progress: ${filtered.keys}" } */
return filtered.values.first() fun getInProgress(): ApkInstallResult?
/**
* Get all [ApkInstallResult]s that are not in state [QUEUED].
*/
fun getNotQueued(): Collection<ApkInstallResult>
/**
* Get the [ApkInstallResult] for the given package name or null if none exists.
*/
operator fun get(packageName: String): ApkInstallResult?
} }
internal class MutableInstallResult(initialCapacity: Int) : internal class MutableInstallResult(initialCapacity: Int) : InstallResult {
ConcurrentHashMap<String, ApkInstallResult>(initialCapacity) {
private val installResults = ConcurrentHashMap<String, ApkInstallResult>(initialCapacity)
override fun isEmpty() = installResults.isEmpty()
override fun getInProgress(): ApkInstallResult? {
val filtered = installResults.filterValues { result -> result.state == IN_PROGRESS }
if (filtered.isEmpty()) return null
check(filtered.size == 1) { "More than one package in progress: ${filtered.keys}" }
return filtered.values.first()
}
override fun getNotQueued(): Collection<ApkInstallResult> {
return installResults.filterValues { result -> result.state != QUEUED }.values
}
override fun get(packageName: String) = installResults[packageName]
operator fun set(packageName: String, installResult: ApkInstallResult) {
installResults[packageName] = installResult
}
fun update( fun update(
packageName: String, packageName: String,
updateFun: (ApkInstallResult) -> ApkInstallResult updateFun: (ApkInstallResult) -> ApkInstallResult
): MutableInstallResult { ): MutableInstallResult {
val result = get(packageName) val result = get(packageName)
check(result != null) { "ApkRestoreResult for $packageName does not exist." } check(result != null) { "ApkRestoreResult for $packageName does not exist." }
set(packageName, updateFun(result)) installResults[packageName] = updateFun(result)
return this return this
} }
} }
internal data class ApkInstallResult( internal data class ApkInstallResult(

View file

@ -167,7 +167,7 @@ internal class ApkRestoreTest : TransportTest() {
@Test @Test
fun `test successful run`(@TempDir tmpDir: Path) = runBlocking { fun `test successful run`(@TempDir tmpDir: Path) = runBlocking {
val installResult = MutableInstallResult(1).apply { val installResult = MutableInstallResult(1).apply {
put( set(
packageName, ApkInstallResult( packageName, ApkInstallResult(
packageName, packageName,
progress = 1, progress = 1,
@ -244,7 +244,7 @@ internal class ApkRestoreTest : TransportTest() {
every { installedPackageInfo.longVersionCode } returns packageMetadata.version!! - 1 every { installedPackageInfo.longVersionCode } returns packageMetadata.version!! - 1
if (!willFail) { if (!willFail) {
val installResult = MutableInstallResult(1).apply { val installResult = MutableInstallResult(1).apply {
put( set(
packageName, packageName,
ApkInstallResult(packageName, progress = 1, total = 1, state = SUCCEEDED) ApkInstallResult(packageName, progress = 1, total = 1, state = SUCCEEDED)
) )