Optimizes recommended content & image caching (#359)

## Details
This PR contains a number of optimizations

### Images
Updates to request images with maximum sizes

The max sizes are estimates on the maximum number of pixels that will be
actually displayed. This means the server is downscaling large images
which means 1) better quality downscaling and 2) smaller images sent
over the network and cached

This should mean slightly better quality images and more images that can
be cached locally

### Paging
Reduces network calls when fetching paginated data, ie grid pages and
some rows. This PR combines the total record count & first page queries
which slightly reduces total time to load paginated data.

Additionally, on movies/tv show recommended pages, the rows now only
fetch a limited number of items (same as number on home page). While
they previously fetched using pagination, there is an overhead required
to paginate requests, so this is slightly faster.

### Async recommended fetching
On movies/tv show recommended pages, the rows are now fetched completely
separately from each other. Previously, the rows were requested
separtely, but each was only added to the UI in order as each completed.
Now they will add as the data arrived.

Note: Top unwatched TV shows is still very slow on `10.11.x`, see #204


### Image cache

The local, on-disk image cache size is increased from 100mb to 200mb.
Combined with the smaller images, this covers about 1500-2000 poster
images, but will vary by server.

The cache size is now also configurable in advanced settings from 25mb
to 1000mb. Additionally, you can see how much of both the disk and
memory caches are in use.

## Issues
Closes #330 
Related to #120
This commit is contained in:
damontecres 2025-12-02 16:00:21 -05:00 committed by GitHub
parent 10233eb459
commit 56bf3cb7a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 453 additions and 253 deletions

View file

@ -19,6 +19,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.datastore.core.DataStore
import androidx.lifecycle.lifecycleScope
@ -27,6 +28,8 @@ import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Surface
import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.preferences.AppPreference
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.DefaultUserConfiguration
import com.github.damontecres.wholphin.preferences.UserPreferences
@ -85,9 +88,31 @@ class MainActivity : AppCompatActivity() {
appUpgradeHandler.copySubfont(false)
}
setContent {
CoilConfig(okHttpClient, false)
val density = LocalDensity.current
LaunchedEffect(density) {
with(density) {
// Cards are never taller than 200 (most are around 120)
BaseItem.primaryMaxHeight = 200.dp.roundToPx()
// This width covers up to 2.35:1 aspect ratio images
BaseItem.primaryMaxWidth = 480.dp.roundToPx()
}
}
val appPreferences by userPreferencesDataStore.data.collectAsState(null)
appPreferences?.let { appPreferences ->
CoilConfig(
diskCacheSizeBytes =
appPreferences.advancedPreferences.imageDiskCacheSizeBytes.let {
if (it < AppPreference.ImageDiskCacheSize.min * AppPreference.MEGA_BIT) {
AppPreference.ImageDiskCacheSize.defaultValue * AppPreference.MEGA_BIT
} else {
it
}
},
okHttpClient = okHttpClient,
debugLogging = false,
enableCache = true,
)
LaunchedEffect(appPreferences.debugLogging) {
DebugLogTree.INSTANCE.enabled = appPreferences.debugLogging
}