mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
Use known game size for preflight checks
This commit is contained in:
1 parent
82b8cf1230
commit
eaa095925c
5 files changed
+13
-58
No files matched your search
@@ -33,9 +33,6 @@ object StoreInstallRoot {
|
||||
val enough: Boolean,
|
||||
val requiredBytes: Long,
|
||||
val availableBytes: Long,
|
||||
val internalRequiredBytes: Long = 0L,
|
||||
val internalAvailableBytes: Long = 0L,
|
||||
val isInternalShortage: Boolean = false,
|
||||
val errorMessage: String? = null
|
||||
)
|
||||
|
||||
@@ -48,58 +45,21 @@ object StoreInstallRoot {
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimated bytes needed for an install. Epic on internal storage needs both chunk cache
|
||||
* and assembled files simultaneously (~2x game size).
|
||||
* The catalog size is the known minimum for an install. Epic's actual chunk-cache requirement
|
||||
* is determined from its manifest before chunk downloads begin.
|
||||
*/
|
||||
fun estimatedBytesNeeded(item: CatalogItem, targetRoot: File, isInternal: Boolean): Long {
|
||||
val size = StoreSizes.size(item)
|
||||
if (size <= 0L) return 0L
|
||||
return if (item.store == Store.EPIC && isInternal) size * 2 else size
|
||||
}
|
||||
fun estimatedBytesNeeded(item: CatalogItem): Long = StoreSizes.size(item).coerceAtLeast(0L)
|
||||
|
||||
/** Pre-install storage check to detect insufficient space before starting. */
|
||||
fun checkStorage(context: Context, item: CatalogItem, targetRoot: File): StorageCheck {
|
||||
val size = StoreSizes.size(item)
|
||||
val size = estimatedBytesNeeded(item)
|
||||
val freeTarget = availableBytes(targetRoot)
|
||||
if (size <= 0L) return StorageCheck(enough = true, requiredBytes = 0L, availableBytes = freeTarget)
|
||||
val internal = isInternal(context, targetRoot)
|
||||
if (internal) {
|
||||
val needed = if (item.store == Store.EPIC) size * 2 else size
|
||||
if (freeTarget in 1 until needed) {
|
||||
val msg = if (item.store == Store.EPIC) {
|
||||
context.getString(
|
||||
com.droiddeck.launcher.R.string.stores_storage_insufficient,
|
||||
formatBytes(needed),
|
||||
formatBytes(freeTarget)
|
||||
) + " (" + formatBytes(size) + " + " + formatBytes(size) + " " + context.getString(com.droiddeck.launcher.R.string.stores_stage_download).lowercase() + ")"
|
||||
} else {
|
||||
context.getString(com.droiddeck.launcher.R.string.stores_storage_insufficient, formatBytes(needed), formatBytes(freeTarget))
|
||||
}
|
||||
return StorageCheck(enough = false, requiredBytes = needed, availableBytes = freeTarget, errorMessage = msg)
|
||||
}
|
||||
return StorageCheck(enough = true, requiredBytes = needed, availableBytes = freeTarget)
|
||||
} else {
|
||||
if (freeTarget in 1 until size) {
|
||||
val msg = context.getString(com.droiddeck.launcher.R.string.stores_storage_insufficient, formatBytes(size), formatBytes(freeTarget))
|
||||
return StorageCheck(enough = false, requiredBytes = size, availableBytes = freeTarget, errorMessage = msg)
|
||||
}
|
||||
if (item.store == Store.EPIC) {
|
||||
val internalFree = availableBytes(context.cacheDir)
|
||||
if (internalFree in 1 until size) {
|
||||
val msg = context.getString(com.droiddeck.launcher.R.string.stores_storage_internal_cache_insufficient, formatBytes(size), formatBytes(internalFree))
|
||||
return StorageCheck(
|
||||
enough = false,
|
||||
requiredBytes = size,
|
||||
availableBytes = freeTarget,
|
||||
internalRequiredBytes = size,
|
||||
internalAvailableBytes = internalFree,
|
||||
isInternalShortage = true,
|
||||
errorMessage = msg
|
||||
)
|
||||
}
|
||||
}
|
||||
return StorageCheck(enough = true, requiredBytes = size, availableBytes = freeTarget)
|
||||
if (freeTarget in 1 until size) {
|
||||
val msg = context.getString(com.droiddeck.launcher.R.string.stores_storage_insufficient, formatBytes(size), formatBytes(freeTarget))
|
||||
return StorageCheck(enough = false, requiredBytes = size, availableBytes = freeTarget, errorMessage = msg)
|
||||
}
|
||||
return StorageCheck(enough = true, requiredBytes = size, availableBytes = freeTarget)
|
||||
}
|
||||
|
||||
/** The internal root: always there, always the default. */
|
||||
|
||||
@@ -72,7 +72,7 @@ internal fun InstallWhereDialog(item: CatalogItem, onDismiss: () -> Unit) {
|
||||
Rise(1) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
|
||||
targets.forEachIndexed { i, t ->
|
||||
val needed = com.droiddeck.launcher.stores.StoreInstallRoot.estimatedBytesNeeded(item, t.root, !t.removable)
|
||||
val needed = com.droiddeck.launcher.stores.StoreInstallRoot.estimatedBytesNeeded(item)
|
||||
val isLow = needed > 0 && t.freeBytes in 1 until needed
|
||||
val freeText = if (isLow) {
|
||||
stringResource(R.string.stores_storage_low, formatBytes(t.freeBytes), formatBytes(needed))
|
||||
|
||||
@@ -511,7 +511,7 @@ private fun InstallWhere(item: CatalogItem) {
|
||||
StepTitle(title)
|
||||
StepList {
|
||||
targets.forEachIndexed { i, t ->
|
||||
val needed = com.droiddeck.launcher.stores.StoreInstallRoot.estimatedBytesNeeded(item, t.root, !t.removable)
|
||||
val needed = com.droiddeck.launcher.stores.StoreInstallRoot.estimatedBytesNeeded(item)
|
||||
val isLow = needed > 0 && t.freeBytes in 1 until needed
|
||||
val trailingText = if (isLow) {
|
||||
stringResource(R.string.stores_storage_low, formatBytes(t.freeBytes), formatBytes(needed))
|
||||
|
||||
@@ -2258,7 +2258,6 @@
|
||||
<string name="stores_target_internal">Internal</string>
|
||||
<string name="stores_target_free">%1$s free</string>
|
||||
<string name="stores_storage_insufficient">Not enough free space: need %1$s, only %2$s free</string>
|
||||
<string name="stores_storage_internal_cache_insufficient">Not enough internal space for download cache: need %1$s, only %2$s free</string>
|
||||
<string name="stores_storage_low">Insufficient space (%1$s free, need %2$s)</string>
|
||||
<string name="stores_notification_channel">Store downloads</string>
|
||||
<string name="stores_notification_channel_hint">Shows game download progress and keeps downloads running in the background</string>
|
||||
|
||||
@@ -60,16 +60,12 @@ class StoreInstallRootTest {
|
||||
assertEquals("a_b_c", dir.name)
|
||||
}
|
||||
|
||||
@Test fun estimatedBytesNeededCountsDoubleForEpicInternalStorage() {
|
||||
@Test fun estimatedBytesNeededUsesKnownInstallSizeForAllStores() {
|
||||
val item = CatalogItem(Store.EPIC, "game1", "Game 1", imageUrl = null, owned = true, sizeBytes = 10_000_000L)
|
||||
val internalDir = StoreInstallRoot.internalRoot(app)
|
||||
val cardDir = File(app.filesDir, "card/Games")
|
||||
|
||||
assertEquals(20_000_000L, StoreInstallRoot.estimatedBytesNeeded(item, internalDir, isInternal = true))
|
||||
assertEquals(10_000_000L, StoreInstallRoot.estimatedBytesNeeded(item, cardDir, isInternal = false))
|
||||
assertEquals(10_000_000L, StoreInstallRoot.estimatedBytesNeeded(item))
|
||||
|
||||
val gogItem = CatalogItem(Store.GOG, "game2", "Game 2", imageUrl = null, owned = true, sizeBytes = 10_000_000L)
|
||||
assertEquals(10_000_000L, StoreInstallRoot.estimatedBytesNeeded(gogItem, internalDir, isInternal = true))
|
||||
assertEquals(10_000_000L, StoreInstallRoot.estimatedBytesNeeded(gogItem))
|
||||
}
|
||||
|
||||
@Test fun checkStorageReportsEnoughWhenSpaceIsUnknownOrAvailable() {
|
||||
|
||||
Reference in new issue
Block a user