diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/HomeProfileStores.kt b/app/src/main/java/com/fluxa/app/ui/catalog/HomeProfileStores.kt index 453162a..b929f15 100644 --- a/app/src/main/java/com/fluxa/app/ui/catalog/HomeProfileStores.kt +++ b/app/src/main/java/com/fluxa/app/ui/catalog/HomeProfileStores.kt @@ -99,3 +99,27 @@ class HomeCategoryCache @Inject constructor( return if (profile?.isGuest == true || profile == null) "home_cache_guest" else "home_cache_${profile.id}" } } + +@Singleton +class HomeBillboardCache @Inject constructor( + @ApplicationContext context: Context, + private val gson: Gson +) { + private val prefs = context.getSharedPreferences("fluxa_home_billboard_cache", Context.MODE_PRIVATE) + + fun load(profile: UserProfile?): List { + val saved = prefs.getString(key(profile), null) ?: return emptyList() + return runCatching { + val listType = object : TypeToken>() {}.type + gson.fromJson>(saved, listType).orEmpty() + }.getOrElse { emptyList() } + } + + fun save(profile: UserProfile?, pool: List) { + prefs.edit().putString(key(profile), gson.toJson(pool)).apply() + } + + private fun key(profile: UserProfile?): String { + return if (profile?.isGuest == true || profile == null) "billboard_cache_guest" else "billboard_cache_${profile.id}" + } +} diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt b/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt index 3cb0b3e..d79568b 100644 --- a/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt +++ b/app/src/main/java/com/fluxa/app/ui/catalog/HomeViewModel.kt @@ -51,6 +51,7 @@ class HomeViewModel @Inject constructor( private val watchlistStore: WatchlistStore, private val searchHistoryStore: SearchHistoryStore, private val homeCategoryCache: HomeCategoryCache, + private val homeBillboardCache: HomeBillboardCache, private val forgottenContinueWatchingStore: ForgottenContinueWatchingStore, private val coordinatorFactory: HomeViewModelCoordinatorFactory, private val externalSyncPushCoordinator: ExternalSyncPushCoordinator, @@ -254,6 +255,7 @@ class HomeViewModel @Inject constructor( private var externalContinueWatching: List = emptyList() private var traktWatchedState: TraktWatchedState = TraktWatchedState() private var currentActiveProfile: UserProfile? = null + private var hasFetchedFreshBillboard = false private var searchJob: Job? = null private val _isSearchLoading = MutableStateFlow(false) val isSearchLoading: StateFlow = _isSearchLoading.asStateFlow() @@ -349,7 +351,10 @@ class HomeViewModel @Inject constructor( fetchCs3FeedItems = { feed -> platformContentGateway.cloudFeedItems(feed.key) }, - setPool = { billboardState.poolValue = it }, + setPool = { pool -> + billboardState.poolValue = pool + homeBillboardCache.save(currentActiveProfile, pool) + }, updateContent = billboardRuntime::updateContent, normalizePool = { items -> items.distinctBy(HomeBillboardRanking::contentIdentityKey) }, startRotation = billboardRuntime::startRotation @@ -1018,9 +1023,20 @@ class HomeViewModel @Inject constructor( } scheduleCs3Refresh() } - if (force || billboardState.poolValue.isEmpty()) { + if (billboardState.poolValue.isEmpty()) { + val cachedPool = homeBillboardCache.load(activeProfile) + if (cachedPool.isNotEmpty()) { + billboardState.poolValue = cachedPool + viewModelScope.launch { + billboardRuntime.updateContent(cachedPool[0]) + billboardRuntime.startRotation() + } + } + } + if (force || !hasFetchedFreshBillboard) { viewModelScope.launch { billboardLoader.load(activeProfile) + hasFetchedFreshBillboard = true } } }