mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
Stores: the Installed tab draws what its count counts
The tab's count came from the installs on disk and its grid from the library filtered by id, so two installs could read Installed (2) over an empty grid. Both now come from installedCards: each install joined to its library item by store id, or by title when the ids differ, else a card made from the sidecar's own title and art.
This commit is contained in:
1 parent
e835f5c523
commit
1379396b99
4 files changed
+50
-3
No files matched your search
@@ -52,6 +52,21 @@ class StoreShelves(
|
||||
}
|
||||
|
||||
/** A game a store installed, as found on disk through its sidecar. */
|
||||
/**
|
||||
* The Installed tab's cards for [store], from the installs on disk - the same source as its count:
|
||||
* each joined to its library item by store id (by title when the ids differ), else a card made
|
||||
* from the sidecar's own title and art, so an install shows even before the library has loaded.
|
||||
*/
|
||||
fun installedCards(store: Store, installed: List<InstalledStoreGame>, library: List<CatalogItem>): List<CatalogItem> {
|
||||
val byId = library.associateBy { it.id }
|
||||
val byTitle = library.associateBy { it.title.lowercase() }
|
||||
return installed.filter { it.sidecar.store == store }.map { game ->
|
||||
val s = game.sidecar
|
||||
byId[s.id] ?: byTitle[s.title.lowercase()]
|
||||
?: CatalogItem(store, s.id, s.title, imageUrl = s.hero ?: s.cover, tallImageUrl = s.cover ?: s.hero, owned = true)
|
||||
}.distinctBy { it.id }.sortedBy { it.title.lowercase() }
|
||||
}
|
||||
|
||||
class InstalledStoreGame(val sidecar: StoreGameSidecar, val folder: java.io.File) {
|
||||
val key: String get() = "${sidecar.store.id}:${sidecar.id}"
|
||||
}
|
||||
|
||||
@@ -280,17 +280,18 @@ private fun Storefront(
|
||||
val colors = MaterialTheme.colorScheme
|
||||
val library = StoresState.library[store] ?: emptyList()
|
||||
val shelves = StoresState.shelves[store]
|
||||
val installedKeys = remember(StoresState.installed) { StoresState.installed.filter { it.sidecar.store == store }.map { it.sidecar.id }.toSet() }
|
||||
// The Installed tab, its count and every card's installed mark come from the installs on disk.
|
||||
val installedItems = remember(StoresState.installed, library) { com.droiddeck.launcher.stores.installedCards(store, StoresState.installed, library) }
|
||||
val installedKeys = remember(installedItems) { installedItems.map { it.id }.toSet() + StoresState.installed.filter { it.sidecar.store == store }.map { it.sidecar.id } }
|
||||
val q = query.trim().lowercase()
|
||||
fun matches(i: CatalogItem) = q.isEmpty() || i.title.lowercase().contains(q)
|
||||
// Everything this store knows about: the library plus whatever the shelves brought, each title once.
|
||||
val everything = remember(library, shelves) { (library + (shelves?.all ?: emptyList())).distinctBy { it.id } }
|
||||
val installedItems = library.filter { it.id in installedKeys }
|
||||
Rise(1) {
|
||||
SubTabs(
|
||||
listOf(
|
||||
"store" to stringResource(R.string.stores_tab_store),
|
||||
"installed" to stringResource(R.string.stores_tab_count, stringResource(R.string.stores_tab_installed), installedKeys.size),
|
||||
"installed" to stringResource(R.string.stores_tab_count, stringResource(R.string.stores_tab_installed), installedItems.size),
|
||||
"library" to stringResource(R.string.stores_tab_count, stringResource(R.string.stores_tab_library), library.size),
|
||||
"all" to stringResource(R.string.stores_tab_count, stringResource(R.string.stores_tab_all), everything.size),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.droiddeck.launcher.stores
|
||||
|
||||
import java.io.File
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
/** The Installed tab draws what its count counts: the installs on disk. */
|
||||
class InstalledCardsTest {
|
||||
private fun install(store: Store, id: String, title: String) =
|
||||
InstalledStoreGame(StoreGameSidecar(store, id, title, "game.exe", cover = "https://img/$id.jpg"), File("/x/$id"))
|
||||
|
||||
@Test fun everyInstallIsACardWhetherOrNotTheLibraryHasLoaded() {
|
||||
val installed = listOf(install(Store.GOG, "1", "DOOM + DOOM II"), install(Store.GOG, "2", "DOOM I Enhanced"), install(Store.EPIC, "e", "DOOMBLADE"))
|
||||
// Library not loaded: cards from the sidecars.
|
||||
val bare = installedCards(Store.GOG, installed, emptyList())
|
||||
assertEquals(listOf("DOOM + DOOM II", "DOOM I Enhanced"), bare.map { it.title })
|
||||
assertEquals("https://img/1.jpg", bare.first().tallImageUrl)
|
||||
// Loaded: the library item wins, by id, or by title when the ids differ.
|
||||
val library = listOf(
|
||||
CatalogItem(Store.GOG, "1", "DOOM + DOOM II", imageUrl = "wide1", owned = true),
|
||||
CatalogItem(Store.GOG, "999", "DOOM I Enhanced", imageUrl = "wide2", owned = true),
|
||||
CatalogItem(Store.GOG, "3", "Not installed", imageUrl = null, owned = true),
|
||||
)
|
||||
val joined = installedCards(Store.GOG, installed, library)
|
||||
assertEquals(listOf("wide1", "wide2"), joined.map { it.imageUrl })
|
||||
assertEquals(1, installedCards(Store.EPIC, installed, library).size)
|
||||
}
|
||||
}
|
||||
@@ -144,6 +144,9 @@ without it and Setup says "Stores engine not built").
|
||||
(`token`, `__token__`, `f_token`, `hdnts`, access/refresh/id tokens, `code=`) and Authorization /
|
||||
Cookie headers are blanked outside URLs too. `StoreLogTest` covers a GOG secure link and an Epic
|
||||
Akamai URL. The engine's own logcat lines (tag `EpicNative` etc.) are written on the native side.
|
||||
- **Installed tab empty under "Installed (2)" (device):** the count came from the installs on disk,
|
||||
the grid from the library filtered by id. Both now come from `installedCards`: each install joined
|
||||
to its library item by id (or title), else a card from the sidecar's title and art.
|
||||
- **GOG rows (device, DOOM + DOOM II):** bytes read "0 B" instead of blank; GOG and Amazon report
|
||||
their size on disk from the manifest; their Install stage counts its finishing steps (record and
|
||||
launcher, art, Steam) instead of sitting empty - GOG writes files in place while downloading, so
|
||||
|
||||
Reference in new issue
Block a user