Skip to content

Commit

Permalink
[Jetcaster]: Display latest episodes for all subscribed podcasts in l…
Browse files Browse the repository at this point in the history
  • Loading branch information
arriolac committed Apr 29, 2024
2 parents 21a59c1 + f1231a4 commit fbef032
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 47 deletions.
Expand Up @@ -17,6 +17,5 @@
package com.example.jetcaster.core.model

data class LibraryInfo(
val podcast: PodcastInfo? = null,
val episodes: List<EpisodeInfo> = emptyList()
)
val episodes: List<PodcastToEpisodeInfo> = emptyList()
) : List<PodcastToEpisodeInfo> by episodes
Expand Up @@ -21,10 +21,5 @@ package com.example.jetcaster.core.model
*/
data class PodcastCategoryFilterResult(
val topPodcasts: List<PodcastInfo> = emptyList(),
val episodes: List<PodcastCategoryEpisode> = emptyList()
)

data class PodcastCategoryEpisode(
val episode: EpisodeInfo,
val podcast: PodcastInfo,
val episodes: List<PodcastToEpisodeInfo> = emptyList()
)
@@ -0,0 +1,22 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.jetcaster.core.model

data class PodcastToEpisodeInfo(
val episode: EpisodeInfo,
val podcast: PodcastInfo,
)
Expand Up @@ -20,7 +20,7 @@ import androidx.room.Embedded
import androidx.room.Ignore
import androidx.room.Relation
import com.example.jetcaster.core.model.PlayerEpisode
import com.example.jetcaster.core.model.PodcastCategoryEpisode
import com.example.jetcaster.core.model.PodcastToEpisodeInfo
import java.util.Objects

class EpisodeToPodcast {
Expand Down Expand Up @@ -62,8 +62,8 @@ fun EpisodeToPodcast.toPlayerEpisode(): PlayerEpisode =
podcastImageUrl = podcast.imageUrl ?: "",
)

fun EpisodeToPodcast.asPodcastCategoryEpisode(): PodcastCategoryEpisode =
PodcastCategoryEpisode(
fun EpisodeToPodcast.asPodcastToEpisodeInfo(): PodcastToEpisodeInfo =
PodcastToEpisodeInfo(
episode = episode.asExternalModel(),
podcast = podcast.asExternalModel(),
)
Expand Up @@ -18,7 +18,7 @@ package com.example.jetcaster.core.data.domain

import com.example.jetcaster.core.data.database.model.Category
import com.example.jetcaster.core.data.database.model.asExternalModel
import com.example.jetcaster.core.data.database.model.asPodcastCategoryEpisode
import com.example.jetcaster.core.data.database.model.asPodcastToEpisodeInfo
import com.example.jetcaster.core.data.repository.CategoryStore
import com.example.jetcaster.core.model.CategoryInfo
import com.example.jetcaster.core.model.PodcastCategoryFilterResult
Expand Down Expand Up @@ -52,7 +52,7 @@ class PodcastCategoryFilterUseCase @Inject constructor(
return combine(recentPodcastsFlow, episodesFlow) { topPodcasts, episodes ->
PodcastCategoryFilterResult(
topPodcasts = topPodcasts.map { it.asExternalModel() },
episodes = episodes.map { it.asPodcastCategoryEpisode() }
episodes = episodes.map { it.asPodcastToEpisodeInfo() }
)
}
}
Expand Down
Expand Up @@ -22,7 +22,7 @@ import com.example.jetcaster.core.data.database.model.EpisodeToPodcast
import com.example.jetcaster.core.data.database.model.Podcast
import com.example.jetcaster.core.data.database.model.PodcastWithExtraInfo
import com.example.jetcaster.core.data.database.model.asExternalModel
import com.example.jetcaster.core.data.database.model.asPodcastCategoryEpisode
import com.example.jetcaster.core.data.database.model.asPodcastToEpisodeInfo
import com.example.jetcaster.core.data.repository.TestCategoryStore
import java.time.OffsetDateTime
import kotlinx.coroutines.flow.first
Expand Down Expand Up @@ -109,7 +109,7 @@ class PodcastCategoryFilterUseCaseTest {
result.topPodcasts
)
assertEquals(
testEpisodeToPodcast.map { it.asPodcastCategoryEpisode() },
testEpisodeToPodcast.map { it.asPodcastToEpisodeInfo() },
result.episodes
)
}
Expand Down
Expand Up @@ -921,7 +921,7 @@ private fun PreviewHomeContent() {
),
podcastCategoryFilterResult = PodcastCategoryFilterResult(
topPodcasts = PreviewPodcasts,
episodes = PreviewPodcastCategoryEpisodes
episodes = PreviewPodcastEpisodes
),
library = LibraryInfo(),
onCategorySelected = {},
Expand Down Expand Up @@ -957,7 +957,7 @@ private fun PreviewHomeContentExpanded() {
),
podcastCategoryFilterResult = PodcastCategoryFilterResult(
topPodcasts = PreviewPodcasts,
episodes = PreviewPodcastCategoryEpisodes
episodes = PreviewPodcastEpisodes
),
library = LibraryInfo(),
onCategorySelected = {},
Expand Down
Expand Up @@ -21,6 +21,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.jetcaster.core.data.database.model.EpisodeToPodcast
import com.example.jetcaster.core.data.database.model.asExternalModel
import com.example.jetcaster.core.data.database.model.asPodcastToEpisodeInfo
import com.example.jetcaster.core.data.domain.FilterableCategoriesUseCase
import com.example.jetcaster.core.data.domain.PodcastCategoryFilterUseCase
import com.example.jetcaster.core.data.repository.EpisodeStore
Expand All @@ -41,9 +42,11 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch

@OptIn(ExperimentalCoroutinesApi::class)
Expand All @@ -70,6 +73,9 @@ class HomeViewModel @Inject constructor(
// Holds the view state if the UI is refreshing for new data
private val refreshing = MutableStateFlow(false)

private val subscribedPodcasts = podcastStore.followedPodcastsSortedByLastEpisode(limit = 10)
.shareIn(viewModelScope, SharingStarted.WhileSubscribed())

val state: StateFlow<HomeScreenUiState>
get() = _state

Expand All @@ -80,17 +86,17 @@ class HomeViewModel @Inject constructor(
combine(
homeCategories,
selectedHomeCategory,
podcastStore.followedPodcastsSortedByLastEpisode(limit = 10),
subscribedPodcasts,
refreshing,
_selectedCategory.flatMapLatest { selectedCategory ->
filterableCategoriesUseCase(selectedCategory)
},
_selectedCategory.flatMapLatest {
podcastCategoryFilterUseCase(it)
},
selectedLibraryPodcast.flatMapLatest {
episodeStore.episodesInPodcast(
podcastUri = it?.uri ?: "",
subscribedPodcasts.flatMapLatest { podcasts ->
episodeStore.episodesInPodcasts(
podcastUris = podcasts.map { it.podcast.uri },
limit = 20
)
}
Expand Down Expand Up @@ -175,8 +181,7 @@ class HomeViewModel @Inject constructor(

private fun List<EpisodeToPodcast>.asLibrary(): LibraryInfo =
LibraryInfo(
podcast = this.firstOrNull()?.podcast?.asExternalModel(),
episodes = this.map { it.episode.asExternalModel() }
episodes = this.map { it.asPodcastToEpisodeInfo() }
)

enum class HomeCategory {
Expand Down
Expand Up @@ -18,8 +18,8 @@ package com.example.jetcaster.ui.home

import com.example.jetcaster.core.model.CategoryInfo
import com.example.jetcaster.core.model.EpisodeInfo
import com.example.jetcaster.core.model.PodcastCategoryEpisode
import com.example.jetcaster.core.model.PodcastInfo
import com.example.jetcaster.core.model.PodcastToEpisodeInfo
import java.time.OffsetDateTime
import java.time.ZoneOffset

Expand Down Expand Up @@ -58,8 +58,8 @@ val PreviewEpisodes = listOf(
)
)

val PreviewPodcastCategoryEpisodes = listOf(
PodcastCategoryEpisode(
val PreviewPodcastEpisodes = listOf(
PodcastToEpisodeInfo(
podcast = PreviewPodcasts[0],
episode = PreviewEpisodes[0],
)
Expand Down
Expand Up @@ -40,12 +40,6 @@ fun LazyListScope.libraryItems(
navigateToPlayer: (EpisodeInfo) -> Unit,
onQueueEpisode: (PlayerEpisode) -> Unit
) {
val podcast = library.podcast
if (podcast == null || library.episodes.isEmpty()) {
// TODO: Empty state
return
}

item {
Text(
text = stringResource(id = R.string.latest_episodes),
Expand All @@ -58,12 +52,12 @@ fun LazyListScope.libraryItems(
}

items(
library.episodes,
key = { it.uri }
library,
key = { it.episode.uri }
) { item ->
EpisodeListItem(
episode = item,
podcast = podcast,
episode = item.episode,
podcast = item.podcast,
onClick = navigateToPlayer,
onQueueEpisode = onQueueEpisode,
modifier = Modifier.fillParentMaxWidth(),
Expand All @@ -76,12 +70,6 @@ fun LazyGridScope.libraryItems(
navigateToPlayer: (EpisodeInfo) -> Unit,
onQueueEpisode: (PlayerEpisode) -> Unit
) {
val podcast = library.podcast
if (podcast == null || library.episodes.isEmpty()) {
// TODO: Empty state
return
}

fullWidthItem {
Text(
text = stringResource(id = R.string.latest_episodes),
Expand All @@ -94,12 +82,12 @@ fun LazyGridScope.libraryItems(
}

items(
library.episodes,
key = { it.uri }
library,
key = { it.episode.uri }
) { item ->
EpisodeListItem(
episode = item,
podcast = podcast,
episode = item.episode,
podcast = item.podcast,
onClick = navigateToPlayer,
onQueueEpisode = onQueueEpisode,
modifier = Modifier.fillMaxWidth()
Expand Down

0 comments on commit fbef032

Please sign in to comment.