-
Notifications
You must be signed in to change notification settings - Fork 3
.pr_agent_accepted_suggestions
| PR 800 (2026-07-03) |
[reliability] Stale last-seen keys accumulate
Stale last-seen keys accumulate
HomeRoute and PodcastInfoViewModel write lastSeenEpisodeId for any viewed podcast with a latestEpisode, even when the podcast isn’t subscribed; those entries are only removed on unsubscribe, so they can persist indefinitely and grow the DataStore preferences set. This increases the work done on every preferences read because lastSeenEpisodesStream scans all prefs and filters by prefix.setLastSeenEpisodeId() is invoked for podcasts that may not be subscribed (e.g., Home recommendations and general PodcastInfo loads). Since removeLastSeenEpisodeId() is only called on unsubscribe, this leaves behind persistent per-podcast DataStore keys that can accumulate and slow preference reads/mapping.
The stored last-seen mapping is only meaningful for subscribed podcasts (both isEpisodeNew() helpers require subscribedAt > 0). Writing entries for non-subscribed podcasts provides no benefit but increases stored preference keys and the cost of lastSeenEpisodesStream.
- feature/home/src/main/java/cx/aswin/boxcast/feature/home/HomeScreen.kt[207-226]
- feature/home/src/main/java/cx/aswin/boxcast/feature/home/HomeViewModel.kt[231-235]
- feature/info/src/main/java/cx/aswin/boxcast/feature/info/PodcastInfoViewModel.kt[285-291]
- feature/info/src/main/java/cx/aswin/boxcast/feature/info/PodcastInfoViewModel.kt[326-330]
- Only call
setLastSeenEpisodeId(podcastId, episodeId)when the podcast is subscribed.- In
HomeViewModel.markPodcastEpisodeAsSeen, checksubscriptionRepository.isSubscribed(podcastId)before writing. - In
PodcastInfoViewModel.loadPodcast, reuse the already-computedisSubscribedflag to guard bothsetLastSeenEpisodeIdcalls.
- In
- Optionally add a periodic cleanup routine (e.g., on app start) that removes
last_seen_episode_id_*keys for podcastIds not insubscribedPodcastIds, if you want defense-in-depth.
[correctness] NEW badge ignores play status
NEW badge ignores play status
Subscriptions Shows tab now computes the NEW badge solely from publish time + lastSeenId and no longer considers podcast.episodeStatus, so the badge can appear even when the latest episode is already completed/in-progress. This is misleading because LibraryViewModel explicitly enriches podcasts with episodeStatus from listening history.The Shows grid card NEW indicator no longer checks podcast.episodeStatus, so it can display NEW for podcasts whose latest episode is already completed or in progress.
LibraryViewModel enriches each subscribed podcast with episodeStatus derived from listening history. The Shows tab previously used this to only show the indicator for UNPLAYED, but the new isEpisodeNew()/hasRecentNew path ignores it.
- feature/library/src/main/java/cx/aswin/boxcast/feature/library/SubscriptionsScreen.kt[1256-1281]
- feature/library/src/main/java/cx/aswin/boxcast/feature/library/SubscriptionsScreen.kt[1331-1353]
- feature/library/src/main/java/cx/aswin/boxcast/feature/library/LibraryViewModel.kt[103-138]
- Gate the NEW badge with episode status, e.g.:
val shouldShowNew = (podcast.episodeStatus == EpisodeStatus.UNPLAYED) && isEpisodeNew(...)- or, if desired:
podcast.episodeStatus != EpisodeStatus.COMPLETED.
- Keep the
lastSeenIdsuppression as-is so users can dismiss the badge by viewing the show.
| PR 780 (2026-06-28) |
[maintainability] Dead isDarkTheme parameter
Dead isDarkTheme parameter
FullPlayerContent still requires an isDarkTheme parameter, but system-bar appearance now uses LocalEffectiveDarkTheme instead, leaving misleading API surface and no-op argument plumbing from call sites.FullPlayerContent keeps an isDarkTheme parameter, but the function no longer uses it after switching to LocalEffectiveDarkTheme.current. This makes call sites look meaningful while having no effect.
UnifiedPlayerSheet now passes effectiveDarkTheme into isDarkTheme, but FullPlayerContent ignores it.
Remove isDarkTheme from FullPlayerContent’s signature and update all call sites accordingly (or reintroduce using the parameter if you intentionally want the composable to be theme-agnostic).
- feature/player/src/main/java/cx/aswin/boxcast/feature/player/FullPlayerContent.kt[79-94]
- feature/player/src/main/java/cx/aswin/boxcast/feature/player/FullPlayerContent.kt[181-187]
- feature/player/src/main/java/cx/aswin/boxcast/feature/player/UnifiedPlayerSheet.kt[543-548]