feat(discovery): expand to 11 regions with language pickers and richer recommendations - #953
Conversation
Drop the live sections/v1 client in favor of catalog/v3, move ContentRegions and discovery poster cards into shared cores, redesign onboarding suggestion lanes, and clear detekt LongMethod/parameter debt for CI.
|
Warning Review limit reached
Next review available in: 22 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR adds region-aware content language preferences, propagates them through discovery and recommendation APIs, introduces shared design-system components, removes the content-sections v1 contract, redesigns onboarding suggestions and welcome animations, and makes OPML import dialogs full-screen. ChangesContent language and discovery
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (5 errors, 1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches
Comment |
Collapse FeedMediaCard chrome slots and extract region/onboarding helpers so Sonar new-code quality gate can pass.
There was a problem hiding this comment.
Actionable comments posted: 20
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
core/playback/src/main/java/cx/aswin/boxlore/core/playback/SmartQueueSources.kt (1)
160-210: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winAdd the required playback README update and JVM tests.
This changes Smart Queue’s discovery inputs, but the cohort includes neither a
core/playback/README.mdupdate nor tests for preference success, fallback on preference failure, and cancellation propagation.As per coding guidelines, “Whenever production Kotlin under core//src/main/ changed, the matching module README.md must also be modified” and “must add or extend hermetic JVM unit tests”; as per path instructions, “Require hermetic JVM tests for new/changed engines, DAOs math, and pure helpers.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/playback/src/main/java/cx/aswin/boxlore/core/playback/SmartQueueSources.kt` around lines 160 - 210, Update core/playback/README.md to document the Smart Queue language inputs, and add hermetic JVM tests covering getPersonalizedRecommendations and getSimilarEpisodes when preferences load successfully, when loading fails and languages fall back to null, and when CancellationException propagates. Target the production methods in SmartQueueSources and verify repository calls receive the expected languages.Sources: Coding guidelines, Path instructions
feature/explore/src/main/java/cx/aswin/boxlore/feature/explore/ExploreViewModel.kt (1)
727-741: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRefresh Explore recommendations when content languages change.
fetchPersonalizedRecommendations()now samplescontentLanguagesStream, but the collector at Lines 315-321 only observes region and subscriptions. Changing languages therefore leaves the existing recommendations stale until another trigger occurs.Include
contentLanguagesStreamin that collector and add a regression test.Proposed fix
combine( userPrefs.regionStream, + userPrefs.contentLanguagesStream, subscriptionRepository.subscribedPodcastIds, -) { _, _ -> }.collect { +) { _, _, _ -> }.collect { fetchPersonalizedRecommendations() }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@feature/explore/src/main/java/cx/aswin/boxlore/feature/explore/ExploreViewModel.kt` around lines 727 - 741, Update the collector that triggers fetchPersonalizedRecommendations() to observe contentLanguagesStream alongside region and subscription changes, ensuring language updates refresh Explore recommendations. Add a regression test verifying that changing content languages invokes the recommendation refresh.Source: Path instructions
core/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.kt (1)
680-694: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winAdd hermetic JVM coverage for the changed language-propagation paths.
core/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.kt#L680-L694: test selected-language forwarding and timeout fallback.core/downloads/src/main/java/cx/aswin/boxlore/core/downloads/SmartDownloadManager.kt#L182-L190: test forwarding languages to personalized recommendations.feature/info/src/main/java/cx/aswin/boxlore/feature/info/EpisodeInfoViewModel.kt#L426-L443: test construction of the language-aware similar-episodes query.feature/home/src/main/java/cx/aswin/boxlore/feature/home/HomeViewModelLoadData.kt#L90-L98: test language-change flow restart and downstream propagation.As per path instructions, substantially changed production Kotlin must add or extend hermetic JVM tests under the corresponding
src/testdirectory.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.kt` around lines 680 - 694, Add or extend hermetic JVM tests under the corresponding src/test directories for all four changed paths: AutoBrowseTreeBuilder.getCuratedChildren must cover selected-language forwarding and the timeout fallback; SmartDownloadManager must cover forwarding languages to personalized recommendations; EpisodeInfoViewModel must cover construction of the language-aware similar-episodes query; and HomeViewModelLoadData must cover language-change flow restart and downstream propagation. Update core/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.kt:680-694, core/downloads/src/main/java/cx/aswin/boxlore/core/downloads/SmartDownloadManager.kt:182-190, feature/info/src/main/java/cx/aswin/boxlore/feature/info/EpisodeInfoViewModel.kt:426-443, and feature/home/src/main/java/cx/aswin/boxlore/feature/home/HomeViewModelLoadData.kt:90-98 only as needed to support the tests.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepository.kt`:
- Around line 546-549: Update the catch block in the similar-episode loading
flow to rethrow CancellationException before handling other exceptions. Preserve
the existing error logging and emptyList fallback for non-cancellation failures,
matching the cancellation handling in getNetworkEpisodesPaginated,
getRssPodcastDetails, and getPersonalizedRecommendations.
- Around line 516-539: Add a MockWebServer-backed regression test in
PodcastRepositoryCatalogTest.kt for getSimilarEpisodes, using an RSS podcast ID
and negative episode ID, and assert the serialized SimilarEpisodesRequest
normalizes those IDs to "0", canonicalizes the country, and includes the
expanded query languages. Follow existing catalog test setup and
request-assertion patterns.
In
`@core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryRecommendations.kt`:
- Around line 17-20: Remove the ad-hoc lowercase-and-length validation for
resolvedCountry in the recommendations request construction. Reuse the already
canonical country supplied by PodcastRepository.getPersonalizedRecommendations,
or apply ContentRegions.canonicalize consistently, so valid values such as
global-style storefronts are not replaced with "us".
In
`@core/catalog/src/test/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryContentMappingHelpersTest.kt`:
- Around line 49-63: Extend resolveContentLanguagesForQuery tests with
emptyList() and an unmapped country such as "fr", asserting the expected
fallback behavior. Add a duplicate and mixed-case language input case to verify
deduplication and stable ordering, while preserving the existing null and
mapped-country assertions.
In
`@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/EqualHeightPosterGrid.kt`:
- Around line 17-21: Complete the shared-grid migration by removing the
duplicate EqualHeightPosterGrid implementation from HomeFeedRecommendations and
updating its usages to import and call
core.designsystem.components.EqualHeightPosterGrid. Preserve the existing Home
grid behavior and parameters while relying solely on the shared component.
In
`@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedMediaCard.kt`:
- Around line 37-48: Reduce the parameter count of FeedMediaCard by grouping its
related display data and/or composable slots into a small dedicated model,
keeping the API within the configured Sonar limit. Update the call sites and
preserve the existing title, subtitle, click, modifier, line-limit, badge, and
overlay behavior.
In
`@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedPosterSpacing.kt`:
- Around line 11-15: Update TitleLineHeight and textFootHeight so the reserved
poster-foot height scales with the title typography’s font scale, deriving the
line height from the actual text style in a density-aware Compose context
instead of using a fixed 18.dp value; preserve the minimum one-line behavior.
In
`@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.kt`:
- Around line 191-205: Update the hint Surface in the
showOffMarketHint/offMarket block to use
MaterialTheme.colorScheme.secondaryContainer directly as its color, removing the
translucent copy alpha while preserving the existing shape, content color, and
layout.
- Around line 323-392: Reduce cognitive complexity in RegionPickerOptionRow by
extracting selected/unselected presentation values and recommended-label
rendering into focused helper functions or composables. Keep
RegionPickerOptionRow responsible for layout and selection behavior, while
preserving the existing colors, typography, and conditional suggested-language
display.
- Around line 132-206: Add hermetic JVM coverage for the language-selection
behavior used by ContentLanguageChipRow and its LanguageChipSection transitions.
Extract the selection transition logic into a testable production symbol if
necessary, then add or extend the related Test.kt under src/test to verify
English locking, the MAX_LANGUAGES limit, deselection at capacity,
normalization, and off-market selections. Ensure tests cover both valid
transitions and unchanged selections when constraints reject an update.
- Around line 387-390: Update the RadioButton inside the region selector to use
a null onClick handler, relying on the parent selectable action for interaction
and exposing only one accessible control. Preserve the existing selected state
and onSelect behavior on the parent.
In
`@core/prefs/src/main/java/cx/aswin/boxlore/core/prefs/UserPreferencesRepository.kt`:
- Around line 96-112: Serialize setRegion and setContentLanguages with one
repository mutex, and move setContentLanguages’ region lookup inside the same
dataStore.edit preferences snapshot instead of using regionStream.first().
Preserve setRegion’s language reset and ensure concurrent writes cannot
overwrite it. Add or extend the related repository Test.kt with a regression
test for the ordering, including default and malformed stored-language cases.
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionCards.kt`:
- Around line 92-101: Update the OutlinedCard modifier in the onboarding
suggestion card, including the corresponding card instance around the second
referenced section, to expose its subscription state through accessibility
semantics. Mark each card as selected when isSubscribed is true and assign an
appropriate selection-control role, while preserving the existing click behavior
and visuals.
- Around line 156-178: Update the IconButton containing Icons.Rounded.Info to
provide a 48.dp minimum interactive touch target while preserving the existing
36.dp visual icon/circle sizing. Avoid allowing the card’s subscription toggle
to receive taps within the expanded info-button target.
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionsScreen.kt`:
- Around line 86-92: The isLoading calculation in AiSuggestionsScreen must not
treat every empty, error-free state as an active load. Gate the second
empty-state clause on an in-flight flag such as uiState.isLoadingPodcasts or
uiState.isAiLoading, while preserving the existing first clause, so completed
empty responses render the “No suggestions yet” state.
- Around line 327-405: Reduce cognitive complexity in SuggestionsLaneChip and
SuggestionsFinishBar by extracting their conditional logic into focused helpers:
provide a laneChipColors(selected) holder for container, content, border, and
badge colors, and a pure finishCtaLabel(uiState, selectedCount): String for CTA
text. Update both composables to consume these helpers, and add unit coverage
for finishCtaLabel under src/test while preserving existing behavior.
- Around line 211-224: In the charts branch of onToggleAll within
AiSuggestionsScreen, simplify the lane.podcasts forEach toggle logic by
combining the two conditional checks into one condition based on whether
allSelected differs from each podcast’s selected state. Preserve the existing
behavior of toggling only podcasts that need to change, while leaving the
non-charts path unchanged.
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingScreen.kt`:
- Around line 326-344: Update the onboarding entrance interaction logic around
chromeInteractive and the CTA click handlers so welcome actions are not ignored
during the full WelcomeEntranceMs animation. Allow the CTAs to respond once
their reveal segment completes (about 0.72 progress), or have the first
interaction snap entranceProgress to 1f before executing the action; apply the
same behavior to the additional CTA logic near the referenced second location.
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelGenre.kt`:
- Around line 83-86: Canonicalize the country field wherever onboarding requests
pair it with recommendedLanguages: update OnboardingViewModelGenre.kt lines
83-86, OnboardingViewModelSearch.kt lines 320-322 and 424-426, and
OnboardingViewModelAi.kt lines 353-356 to use
ContentRegions.canonicalize(currentRegion). In the OPML request at
OnboardingViewModelSearch.kt lines 424-426, hoist the single _uiState.value read
into a local so country and languages use the same state snapshot.
In
`@feature/onboarding/src/test/java/cx/aswin/boxlore/feature/onboarding/OnboardingSuggestionsLanesTest.kt`:
- Around line 39-57: Add tests in OnboardingSuggestionsLanesTest covering
purposeForCurriculumTitle for a blank title and for a title matching no rule,
asserting each fallback purpose, and cover chartsPurpose when no genres are
selected, asserting its empty-selection result. Keep the existing lane and
clampIndex tests unchanged.
---
Outside diff comments:
In
`@core/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.kt`:
- Around line 680-694: Add or extend hermetic JVM tests under the corresponding
src/test directories for all four changed paths:
AutoBrowseTreeBuilder.getCuratedChildren must cover selected-language forwarding
and the timeout fallback; SmartDownloadManager must cover forwarding languages
to personalized recommendations; EpisodeInfoViewModel must cover construction of
the language-aware similar-episodes query; and HomeViewModelLoadData must cover
language-change flow restart and downstream propagation. Update
core/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.kt:680-694,
core/downloads/src/main/java/cx/aswin/boxlore/core/downloads/SmartDownloadManager.kt:182-190,
feature/info/src/main/java/cx/aswin/boxlore/feature/info/EpisodeInfoViewModel.kt:426-443,
and
feature/home/src/main/java/cx/aswin/boxlore/feature/home/HomeViewModelLoadData.kt:90-98
only as needed to support the tests.
In
`@core/playback/src/main/java/cx/aswin/boxlore/core/playback/SmartQueueSources.kt`:
- Around line 160-210: Update core/playback/README.md to document the Smart
Queue language inputs, and add hermetic JVM tests covering
getPersonalizedRecommendations and getSimilarEpisodes when preferences load
successfully, when loading fails and languages fall back to null, and when
CancellationException propagates. Target the production methods in
SmartQueueSources and verify repository calls receive the expected languages.
In
`@feature/explore/src/main/java/cx/aswin/boxlore/feature/explore/ExploreViewModel.kt`:
- Around line 727-741: Update the collector that triggers
fetchPersonalizedRecommendations() to observe contentLanguagesStream alongside
region and subscription changes, ensuring language updates refresh Explore
recommendations. Add a regression test verifying that changing content languages
invokes the recommendation refresh.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 87f3618a-32a4-4c76-a274-bc3cece54566
📒 Files selected for processing (75)
app/README.mdapp/src/main/java/cx/aswin/boxlore/navigation/NavGraphLibrarySettingsDestinations.ktapp/src/main/java/cx/aswin/boxlore/navigation/NavGraphWiring.ktapp/src/main/java/cx/aswin/boxlore/ui/BoxLoreAppRoot.ktapp/src/main/java/cx/aswin/boxlore/ui/libraryimport/OpmlImportDialog.ktcore/catalog/README.mdcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepository.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryContentCache.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryContentMapping.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryRecommendations.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/SimilarEpisodesQuery.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/backup/LibraryBackupManager.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/content/ContentSectionsCachePolicy.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/content/ContentSignalEnrichment.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/content/GroupedContentSectionProvider.ktcore/catalog/src/test/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryContentMappingHelpersTest.ktcore/catalog/src/test/java/cx/aswin/boxlore/core/catalog/content/ContentSectionsCachePolicyTest.ktcore/catalog/src/test/java/cx/aswin/boxlore/core/catalog/content/ContentSignalEnrichmentTest.ktcore/catalog/src/test/java/cx/aswin/boxlore/core/catalog/content/GroupedContentSectionsTest.ktcore/designsystem/README.mdcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/BoxLoreLogo.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/CuratedEpisodeCard.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/EqualHeightPosterGrid.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedMediaCard.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedPosterSpacing.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.ktcore/designsystem/src/test/java/cx/aswin/boxlore/core/designsystem/components/EqualHeightPosterGridTest.ktcore/designsystem/src/test/java/cx/aswin/boxlore/core/designsystem/components/RegionAliasHelpersTest.ktcore/downloads/src/main/java/cx/aswin/boxlore/core/downloads/SmartDownloadManager.ktcore/model/README.mdcore/model/src/main/java/cx/aswin/boxlore/core/model/ContentRegion.ktcore/model/src/test/java/cx/aswin/boxlore/core/model/ContentRegionsTest.ktcore/network/README.mdcore/network/src/main/java/cx/aswin/boxlore/core/network/BoxLoreApi.ktcore/network/src/main/java/cx/aswin/boxlore/core/network/model/OnboardingModels.ktcore/network/src/main/java/cx/aswin/boxlore/core/network/model/PodcastIndexModels.ktcore/network/src/main/java/cx/aswin/boxlore/core/network/model/SyncModels.ktcore/network/src/test/java/cx/aswin/boxlore/core/network/BoxLoreApiContractTest.ktcore/network/src/test/java/cx/aswin/boxlore/core/network/model/ContentSectionsV1RequestSerializationTest.ktcore/network/src/test/resources/fixtures/content_sections_v1.jsoncore/playback/src/main/java/cx/aswin/boxlore/core/playback/SmartQueueSources.ktcore/playback/src/main/java/cx/aswin/boxlore/core/playback/service/auto/AutoBrowseTreeBuilder.ktcore/prefs/README.mdcore/prefs/src/main/java/cx/aswin/boxlore/core/prefs/UserPreferenceKeys.ktcore/prefs/src/main/java/cx/aswin/boxlore/core/prefs/UserPreferencesRepository.ktdocs/recommendation-system.mdfeature/explore/README.mdfeature/explore/src/main/java/cx/aswin/boxlore/feature/explore/ExploreScreen.ktfeature/explore/src/main/java/cx/aswin/boxlore/feature/explore/ExploreViewModel.ktfeature/explore/src/main/java/cx/aswin/boxlore/feature/explore/components/ExploreBrowseHeaders.ktfeature/explore/src/main/java/cx/aswin/boxlore/feature/explore/components/ExploreCards.ktfeature/home/README.mdfeature/home/src/main/java/cx/aswin/boxlore/feature/home/HomeFeedEditorialRows.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/HomeFeedRecommendations.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/HomeViewModelLoadData.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/components/BecauseYouLikeSection.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/components/ForYouSection.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/components/HomeFeedSpacing.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/components/PodcastCard.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/logic/HomeHeroLogic.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/settings/SettingsScreen.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/settings/pages/LibrarySettingsPage.ktfeature/home/src/test/java/cx/aswin/boxlore/feature/home/logic/HomeHeroLogicBranchesTest.ktfeature/info/README.mdfeature/info/src/main/java/cx/aswin/boxlore/feature/info/EpisodeInfoViewModel.ktfeature/onboarding/README.mdfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionCards.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionRowCard.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionsScreen.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingScreen.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingSuggestionsLanes.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelAi.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelGenre.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelSearch.ktfeature/onboarding/src/test/java/cx/aswin/boxlore/feature/onboarding/OnboardingSuggestionsLanesTest.kt
💤 Files with no reviewable changes (10)
- core/network/src/test/resources/fixtures/content_sections_v1.json
- core/network/src/test/java/cx/aswin/boxlore/core/network/model/ContentSectionsV1RequestSerializationTest.kt
- core/catalog/src/test/java/cx/aswin/boxlore/core/catalog/content/ContentSignalEnrichmentTest.kt
- core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/content/ContentSignalEnrichment.kt
- core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/content/ContentSectionsCachePolicy.kt
- core/catalog/src/test/java/cx/aswin/boxlore/core/catalog/content/ContentSectionsCachePolicyTest.kt
- feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionRowCard.kt
- core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/content/GroupedContentSectionProvider.kt
- core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryContentCache.kt
- core/network/src/test/java/cx/aswin/boxlore/core/network/BoxLoreApiContractTest.kt
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedMediaCard.kt (1)
37-124: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd
FeedMediaCardtest coverage.
FeedMediaCardnow owns title-line clamping, subtitle/no-subtitle layout, fixed-height title-only rendering, andimageChromeplacement; add a focusedFeedMediaCardTestundercore/designsystem/src/test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedMediaCard.kt` around lines 37 - 124, The new FeedMediaCard behavior lacks focused tests. Add FeedMediaCardTest under core/designsystem/src/test covering titleMaxLines clamping, subtitle and no-subtitle rendering, fixed-height title-only layout, and imageChrome placement; use the existing Compose testing conventions and target the FeedMediaCard composable directly.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionsScreen.kt`:
- Around line 517-538: The search-flow branch in suggestionsFinishCtaLabel must
not return “Start without subscribing” when any podcast is selected. After
checking selected curriculum recommendations, use a generic subscribe label
whenever uiState.subscribedPodcastIds is non-empty, while preserving the
existing recommended-count label when applicable and the non-search flow
behavior.
---
Outside diff comments:
In
`@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedMediaCard.kt`:
- Around line 37-124: The new FeedMediaCard behavior lacks focused tests. Add
FeedMediaCardTest under core/designsystem/src/test covering titleMaxLines
clamping, subtitle and no-subtitle rendering, fixed-height title-only layout,
and imageChrome placement; use the existing Compose testing conventions and
target the FeedMediaCard composable directly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 3d1fd58f-eb5a-47e3-927f-b530af4846a4
📒 Files selected for processing (5)
core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/CuratedEpisodeCard.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedMediaCard.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.ktfeature/home/src/main/java/cx/aswin/boxlore/feature/home/components/PodcastCard.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionsScreen.kt
Rethrow cancellation in similar-episode fetches, canonicalize regions consistently, fix empty-suggestions loader, extract language-toggle logic with tests, and polish a11y/region UI nits.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionCards.kt (1)
422-438: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPreserve paragraph boundaries while stripping HTML.
<p>First</p><p>Second</p>becomesFirstSecond, producing unreadable detail-sheet copy. Normalize block/break tags to whitespace before stripping remaining tags, and add hermetic regression tests for tags and entities.Proposed fix
internal fun String.stripHtml(): String { - val withoutTags = this.replace(Regex("<[^>]*>"), "") + val normalized = + replace(Regex("(?i)<\\s*(br\\s*/?|/p|/div|/li)\\s*>"), "\n") + val withoutTags = normalized.replace(Regex("<[^>]*>"), "")As per coding guidelines, substantially changed production logic must add hermetic JVM unit tests; as per path instructions, changed main-source behavior requires related
src/testcoverage.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionCards.kt` around lines 422 - 438, Update String.stripHtml so block and break tags such as paragraph boundaries are first normalized to whitespace, then strip remaining HTML tags and retain the existing entity decoding and trimming. Add hermetic JVM tests under the related src/test path covering paragraph/break-tag preservation and the existing entity conversions.Sources: Coding guidelines, Path instructions
core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.kt (1)
423-435: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDisable the locked English chip.
English is marked locked but remains enabled and clickable;
applyTogglethen silently returnsnull. Expose it as non-actionable instead.Proposed fix
- enabled = isEnglish || canSelectMore, + enabled = !isEnglish && canSelectMore,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.kt` around lines 423 - 435, Update the LanguagePreferenceChip configuration in the language selector so the locked English option is not enabled or actionable. Keep English identified as locked, but exclude isEnglish from the enabled condition and prevent its onClick toggle path from being invoked, while preserving selection behavior for other languages.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@core/model/src/test/java/cx/aswin/boxlore/core/model/ContentLanguageSelectionTest.kt`:
- Around line 8-89: Add a hermetic JVM test in ContentLanguageSelectionTest
covering applyToggle with an invalid language code such as "xx", and assert that
it returns null. Keep the test focused on rejection of codes outside the
allowlist.
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelAi.kt`:
- Around line 353-354: Add hermetic JVM unit coverage for the repeated
onboarding request payload wiring. In OnboardingViewModelAi.kt:353-354,
OnboardingViewModelGenre.kt:84-85, and OnboardingViewModelSearch.kt:321-322 and
:425-426, capture requests with a fake API or extract a pure builder, then
assert region aliases produce the same canonical country and recommended
languages for curriculum, genre-synthesis, search recommendation, and OPML
recommendation requests.
---
Outside diff comments:
In
`@core/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.kt`:
- Around line 423-435: Update the LanguagePreferenceChip configuration in the
language selector so the locked English option is not enabled or actionable.
Keep English identified as locked, but exclude isEnglish from the enabled
condition and prevent its onClick toggle path from being invoked, while
preserving selection behavior for other languages.
In
`@feature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionCards.kt`:
- Around line 422-438: Update String.stripHtml so block and break tags such as
paragraph boundaries are first normalized to whitespace, then strip remaining
HTML tags and retain the existing entity decoding and trimming. Add hermetic JVM
tests under the related src/test path covering paragraph/break-tag preservation
and the existing entity conversions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2e47a48d-8586-4c9c-8d1f-120d50997d71
📒 Files selected for processing (15)
core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepository.ktcore/catalog/src/main/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryRecommendations.ktcore/catalog/src/test/java/cx/aswin/boxlore/core/catalog/PodcastRepositoryContentMappingHelpersTest.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/FeedPosterSpacing.ktcore/designsystem/src/main/java/cx/aswin/boxlore/core/designsystem/components/RegionSegmentedSelector.ktcore/model/README.mdcore/model/src/main/java/cx/aswin/boxlore/core/model/ContentLanguageSelection.ktcore/model/src/test/java/cx/aswin/boxlore/core/model/ContentLanguageSelectionTest.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionCards.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/AiSuggestionsScreen.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingScreen.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelAi.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelGenre.ktfeature/onboarding/src/main/java/cx/aswin/boxlore/feature/onboarding/OnboardingViewModelSearch.ktfeature/onboarding/src/test/java/cx/aswin/boxlore/feature/onboarding/OnboardingSuggestionsLanesTest.kt
…ge toggles Extract discoveryLocaleForRegion for canonical country/languages payloads and add hermetic coverage CodeRabbit requested on PR 953.
|
Split the thin one-liner into listener-facing New features / Improvements and clarify Unreleased changelog entries so future sync-readme runs have cleaner source material.



Summary
content/sections/v1).ContentRegions/ language helpers in:core:modelaligned with the proxy.Listener impact
What changes in the user’s life
Test plan
testDebugUnitTest+coderabbit-threads-resolvedgreen