-
Notifications
You must be signed in to change notification settings - Fork 305
[TV] Local folder results in search (Plus) #5747
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/tv-search-parity
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,15 +9,18 @@ import au.com.shiftyjelly.pocketcasts.discover.TvDiscoverPodcast | |
| import au.com.shiftyjelly.pocketcasts.discover.TvDiscoverRow | ||
| import au.com.shiftyjelly.pocketcasts.models.entity.Podcast | ||
| import au.com.shiftyjelly.pocketcasts.models.entity.PodcastEpisode | ||
| import au.com.shiftyjelly.pocketcasts.models.to.FolderItem | ||
| import au.com.shiftyjelly.pocketcasts.models.to.ImprovedSearchResultItem | ||
| import au.com.shiftyjelly.pocketcasts.models.to.SearchAutoCompleteItem | ||
| import au.com.shiftyjelly.pocketcasts.models.to.SearchHistoryEntry | ||
| import au.com.shiftyjelly.pocketcasts.repositories.playback.PlaybackManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.podcast.EpisodeManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.podcast.FolderManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.podcast.PodcastManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.search.ImprovedSearchManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.searchhistory.SearchHistoryManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.sync.SyncManager | ||
| import au.com.shiftyjelly.pocketcasts.repositories.user.UserManager | ||
| import au.com.shiftyjelly.pocketcasts.servers.model.DiscoverCategory | ||
| import dagger.hilt.android.lifecycle.HiltViewModel | ||
| import javax.inject.Inject | ||
|
|
@@ -46,6 +49,8 @@ class TvSearchViewModel @Inject constructor( | |
| private val episodeManager: EpisodeManager, | ||
| private val playbackManager: PlaybackManager, | ||
| private val searchHistoryManager: SearchHistoryManager, | ||
| private val folderManager: FolderManager, | ||
| private val userManager: UserManager, | ||
| ) : ViewModel() { | ||
|
|
||
| private val _categories = MutableStateFlow<List<DiscoverCategory>>(emptyList()) | ||
|
|
@@ -129,6 +134,7 @@ class TvSearchViewModel @Inject constructor( | |
| _searchState.value = TvSearchState.Searching | ||
| _searchState.value = try { | ||
| val fullSearch = async { runCatching { improvedSearchManager.combinedSearch(term) } } | ||
| val foldersSearch = async { runCatching { searchFolders(term) }.getOrDefault(emptyList()) } | ||
| val localPodcasts = podcastManager.findSubscribedFlow(term).first().map(Podcast::toSearchItem) | ||
| val localUuids = localPodcasts.mapTo(HashSet(), ImprovedSearchResultItem.PodcastItem::uuid) | ||
| val predictiveResults = try { | ||
|
|
@@ -153,10 +159,11 @@ class TvSearchViewModel @Inject constructor( | |
| .map { if (it.uuid in localUuids) it.copy(isFollowed = true) else it } | ||
| val episodes = remoteResults.filterIsInstance<ImprovedSearchResultItem.EpisodeItem>() | ||
| .distinctBy(ImprovedSearchResultItem.EpisodeItem::uuid) | ||
| if (podcasts.isEmpty() && episodes.isEmpty()) { | ||
| val folders = foldersSearch.await() | ||
| if (podcasts.isEmpty() && episodes.isEmpty() && folders.isEmpty()) { | ||
| TvSearchState.NoResults | ||
| } else { | ||
| TvSearchState.Results(podcasts = podcasts, episodes = episodes) | ||
| TvSearchState.Results(podcasts = podcasts, episodes = episodes, folders = folders) | ||
| } | ||
| } catch (exception: CancellationException) { | ||
| throw exception | ||
|
|
@@ -171,6 +178,19 @@ class TvSearchViewModel @Inject constructor( | |
| _filter.value = filter | ||
| } | ||
|
|
||
| private suspend fun searchFolders(term: String): List<FolderItem.Folder> { | ||
| if (!userManager.getSignInState().firstOrError().await().isSignedInAsPlusOrPatron) { | ||
| return emptyList() | ||
| } | ||
| return folderManager.getAll() | ||
| .filter { it.name.contains(term, ignoreCase = true) } | ||
| .map { folder -> FolderItem.Folder(folder = folder, podcasts = podcastManager.findPodcastsInFolder(folder.uuid)) } | ||
| } | ||
|
Comment on lines
+181
to
+188
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Subscribing to
Because the terminal state assignment awaits it ( The phone avoids this by subscribing once and seeding a value ( private val signInStateObservable = userManager.getSignInState().startWith(SignInState.SignedOut).toObservable()Suggest mirroring that — hoist the sign-in state into a Two smaller notes on this block:
|
||
|
|
||
| suspend fun folderPodcasts(folderUuid: String): List<Podcast> { | ||
| return folderManager.findFolderPodcastsSorted(folderUuid) | ||
| } | ||
|
|
||
| fun saveSearchTerm(term: String) { | ||
| val trimmed = term.trim() | ||
| if (trimmed.isEmpty()) { | ||
|
|
@@ -286,6 +306,7 @@ sealed interface TvSearchState { | |
| data class Results( | ||
| val podcasts: List<ImprovedSearchResultItem.PodcastItem>, | ||
| val episodes: List<ImprovedSearchResultItem.EpisodeItem>, | ||
| val folders: List<FolderItem.Folder> = emptyList(), | ||
| val isPartial: Boolean = false, | ||
| ) : TvSearchState | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The folder card has no width here, so this row will not lay out correctly.
Every other tile used inside
TvRowcarries an explicit width, because aLazyRowitem nested in aLazyColumnitem is measured with unbounded constraints on both axes:TvPodcastTile→imageModifier = Modifier.width(TvPodcastTileDefaults.RowImageWidth)(TvSearchScreen.kt:711)TvSearchEpisodeCard→Modifier.width(SearchEpisodeCardWidth)TvVideoTile→.width(323.dp),TvFeaturedTile→.width(642.dp)TvFolderCardhas no intrinsic size — it derives everything fromBoxWithConstraints:With unbounded constraints
fillMaxWidth()is a no-op,aspectRatio(1f)finds no finite constraint to anchor to and passes the original constraints through, somaxWidth == Dp.Infinity. Every derived value (coverSize,coverSpacing, thepadding(top = …),Arrangement.spacedBy(coverSpacing)) becomesDp.Infinityand the card degenerates. InTvYourPodcastsGridthis never surfaces because the grid passes a sizingitemModifier(TvYourPodcastsScreen.kt:181).Suggested fix — give it the same footprint as the podcast tiles in the row:
Worth adding a
@Previewwith aTvSearchState.Resultscontaining folders — the existingTvSearchScreenPreviewonly rendersIdle, so nothing currently exercises this row.