Skip to content

Commit 10f2fec

Browse files
committed
[Jetcaster] Implement 'Your Library'
1 parent b14eb5b commit 10f2fec

File tree

8 files changed

+106
-74
lines changed

8 files changed

+106
-74
lines changed

Jetcaster/app/src/main/java/com/example/jetcaster/data/EpisodeStore.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class EpisodeStore(
3939
fun episodesInPodcast(
4040
podcastUri: String,
4141
limit: Int = Integer.MAX_VALUE
42-
): Flow<List<Episode>> {
42+
): Flow<List<EpisodeToPodcast>> {
4343
return episodesDao.episodesForPodcastUri(podcastUri, limit)
4444
}
4545

Jetcaster/app/src/main/java/com/example/jetcaster/data/room/EpisodesDao.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ abstract class EpisodesDao : BaseDao<Episode> {
4646
abstract fun episodesForPodcastUri(
4747
podcastUri: String,
4848
limit: Int
49-
): Flow<List<Episode>>
49+
): Flow<List<EpisodeToPodcast>>
5050

5151
@Transaction
5252
@Query(

Jetcaster/app/src/main/java/com/example/jetcaster/ui/home/Home.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@ import androidx.lifecycle.viewmodel.compose.viewModel
7676
import coil.compose.AsyncImage
7777
import com.example.jetcaster.R
7878
import com.example.jetcaster.data.Category
79+
import com.example.jetcaster.data.EpisodeToPodcast
7980
import com.example.jetcaster.data.PodcastWithExtraInfo
8081
import com.example.jetcaster.ui.home.category.PodcastCategoryViewState
8182
import com.example.jetcaster.ui.home.discover.DiscoverViewState
8283
import com.example.jetcaster.ui.home.discover.discoverItems
84+
import com.example.jetcaster.ui.home.library.libraryItems
8385
import com.example.jetcaster.ui.theme.JetcasterTheme
8486
import com.example.jetcaster.ui.theme.Keyline1
8587
import com.example.jetcaster.ui.theme.MinContrastOfPrimaryVsSurface
@@ -108,6 +110,7 @@ fun Home(
108110
selectedHomeCategory = viewState.selectedHomeCategory,
109111
discoverViewState = viewState.discoverViewState,
110112
podcastCategoryViewState = viewState.podcastCategoryViewState,
113+
libraryEpisodes = viewState.libraryEpisodes,
111114
onHomeCategorySelected = viewModel::onHomeCategorySelected,
112115
onCategorySelected = viewModel::onCategorySelected,
113116
onPodcastUnfollowed = viewModel::onPodcastUnfollowed,
@@ -173,6 +176,7 @@ fun Home(
173176
homeCategories: List<HomeCategory>,
174177
discoverViewState: DiscoverViewState,
175178
podcastCategoryViewState: PodcastCategoryViewState,
179+
libraryEpisodes: List<EpisodeToPodcast>,
176180
modifier: Modifier = Modifier,
177181
onPodcastUnfollowed: (String) -> Unit,
178182
onHomeCategorySelected: (HomeCategory) -> Unit,
@@ -239,6 +243,7 @@ fun Home(
239243
homeCategories = homeCategories,
240244
discoverViewState = discoverViewState,
241245
podcastCategoryViewState = podcastCategoryViewState,
246+
libraryEpisodes = libraryEpisodes,
242247
scrimColor = scrimColor,
243248
pagerState = pagerState,
244249
onPodcastUnfollowed = onPodcastUnfollowed,
@@ -260,6 +265,7 @@ private fun HomeContent(
260265
homeCategories: List<HomeCategory>,
261266
discoverViewState: DiscoverViewState,
262267
podcastCategoryViewState: PodcastCategoryViewState,
268+
libraryEpisodes: List<EpisodeToPodcast>,
263269
scrimColor: Color,
264270
pagerState: PagerState,
265271
modifier: Modifier = Modifier,
@@ -303,7 +309,10 @@ private fun HomeContent(
303309

304310
when (selectedHomeCategory) {
305311
HomeCategory.Library -> {
306-
// TODO
312+
libraryItems(
313+
episodes = libraryEpisodes,
314+
navigateToPlayer = navigateToPlayer
315+
)
307316
}
308317

309318
HomeCategory.Discover -> {
@@ -504,6 +513,7 @@ fun PreviewHomeContent() {
504513
topPodcasts = PreviewPodcastsWithExtraInfo,
505514
episodes = PreviewEpisodeToPodcasts,
506515
),
516+
libraryEpisodes = emptyList(),
507517
onCategorySelected = {},
508518
onPodcastUnfollowed = {},
509519
navigateToPlayer = {},

Jetcaster/app/src/main/java/com/example/jetcaster/ui/home/HomeViewModel.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import androidx.lifecycle.viewModelScope
2121
import com.example.jetcaster.Graph
2222
import com.example.jetcaster.data.Category
2323
import com.example.jetcaster.data.CategoryStore
24+
import com.example.jetcaster.data.EpisodeStore
25+
import com.example.jetcaster.data.EpisodeToPodcast
2426
import com.example.jetcaster.data.PodcastStore
2527
import com.example.jetcaster.data.PodcastWithExtraInfo
2628
import com.example.jetcaster.data.PodcastsRepository
@@ -43,7 +45,8 @@ import kotlinx.coroutines.launch
4345
class HomeViewModel(
4446
private val podcastsRepository: PodcastsRepository = Graph.podcastRepository,
4547
private val categoryStore: CategoryStore = Graph.categoryStore,
46-
private val podcastStore: PodcastStore = Graph.podcastStore
48+
private val podcastStore: PodcastStore = Graph.podcastStore,
49+
private val episodeStore: EpisodeStore = Graph.episodeStore
4750
) : ViewModel() {
4851
// Holds our currently selected home category
4952
private val selectedHomeCategory = MutableStateFlow(HomeCategory.Discover)
@@ -56,6 +59,16 @@ class HomeViewModel(
5659
// Holds the view state if the UI is refreshing for new data
5760
private val refreshing = MutableStateFlow(false)
5861

62+
@OptIn(ExperimentalCoroutinesApi::class)
63+
private val libraryEpisodes = podcastStore.followedPodcastsSortedByLastEpisode()
64+
.flatMapLatest { followedPodcasts ->
65+
combine(followedPodcasts.map { p ->
66+
episodeStore.episodesInPodcast(p.podcast.uri, 5)
67+
}) { allEpisodes ->
68+
allEpisodes.toList().flatten().sortedByDescending { it.episode.published }
69+
}
70+
}
71+
5972
private val discover = combine(
6073
categoryStore.categoriesSortedByPodcastCount()
6174
.onEach { categories ->
@@ -110,20 +123,23 @@ class HomeViewModel(
110123
podcastStore.followedPodcastsSortedByLastEpisode(limit = 20),
111124
refreshing,
112125
discover,
113-
podcastCategory
126+
podcastCategory,
127+
libraryEpisodes
114128
) { homeCategories,
115129
selectedHomeCategory,
116130
podcasts,
117131
refreshing,
118132
discoverViewState,
119-
podcastCategoryViewState ->
133+
podcastCategoryViewState,
134+
libraryEpisodes ->
120135
HomeViewState(
121136
homeCategories = homeCategories,
122137
selectedHomeCategory = selectedHomeCategory,
123138
featuredPodcasts = podcasts.toPersistentList(),
124139
refreshing = refreshing,
125140
discoverViewState = discoverViewState,
126141
podcastCategoryViewState = podcastCategoryViewState,
142+
libraryEpisodes = libraryEpisodes,
127143
errorMessage = null, /* TODO */
128144
)
129145
}.catch { throwable ->
@@ -181,5 +197,6 @@ data class HomeViewState(
181197
val homeCategories: List<HomeCategory> = emptyList(),
182198
val discoverViewState: DiscoverViewState = DiscoverViewState(),
183199
val podcastCategoryViewState: PodcastCategoryViewState = PodcastCategoryViewState(),
200+
val libraryEpisodes: List<EpisodeToPodcast> = emptyList(),
184201
val errorMessage: String? = null
185202
)

Jetcaster/app/src/main/java/com/example/jetcaster/ui/home/category/PodcastCategory.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ import com.example.jetcaster.util.ToggleFollowPodcastIconButton
8080
import java.time.format.DateTimeFormatter
8181
import java.time.format.FormatStyle
8282

83+
data class PodcastCategoryViewState(
84+
val topPodcasts: List<PodcastWithExtraInfo> = emptyList(),
85+
val episodes: List<EpisodeToPodcast> = emptyList()
86+
)
8387
fun LazyListScope.podcastCategory(
8488
topPodcasts: List<PodcastWithExtraInfo>,
8589
episodes: List<EpisodeToPodcast>,

Jetcaster/app/src/main/java/com/example/jetcaster/ui/home/category/PodcastCategoryViewModel.kt

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.example.jetcaster.ui.home.library
2+
3+
import androidx.compose.foundation.lazy.LazyListScope
4+
import androidx.compose.foundation.lazy.items
5+
import androidx.compose.ui.Modifier
6+
import com.example.jetcaster.data.EpisodeToPodcast
7+
import com.example.jetcaster.ui.home.category.EpisodeListItem
8+
9+
fun LazyListScope.libraryItems(
10+
episodes: List<EpisodeToPodcast>,
11+
navigateToPlayer: (String) -> Unit
12+
) {
13+
if (episodes.isEmpty()) {
14+
// TODO: Empty state
15+
return
16+
}
17+
18+
items(episodes, key = { it.episode.uri }) { item ->
19+
EpisodeListItem(
20+
episode = item.episode,
21+
podcast = item.podcast,
22+
onClick = navigateToPlayer,
23+
modifier = Modifier.fillParentMaxWidth()
24+
)
25+
}
26+
}

Jetcaster/app/src/main/java/com/example/jetcaster/util/Flows.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,46 @@ fun <T1, T2, T3, T4, T5, T6, R> combine(
4949
args[5] as T6,
5050
)
5151
}
52+
53+
/**
54+
* Combines seven flows into a single flow by combining their latest values using the provided transform function.
55+
*
56+
* @param flow The first flow.
57+
* @param flow2 The second flow.
58+
* @param flow3 The third flow.
59+
* @param flow4 The fourth flow.
60+
* @param flow5 The fifth flow.
61+
* @param flow6 The sixth flow.
62+
* @param flow7 The seventh flow.
63+
* @param transform The transform function to combine the latest values of the seven flows.
64+
* @return A flow that emits the results of the transform function applied to the latest values of the seven flows.
65+
*/
66+
fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
67+
flow: Flow<T1>,
68+
flow2: Flow<T2>,
69+
flow3: Flow<T3>,
70+
flow4: Flow<T4>,
71+
flow5: Flow<T5>,
72+
flow6: Flow<T6>,
73+
flow7: Flow<T7>,
74+
transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
75+
): Flow<R> =
76+
kotlinx.coroutines.flow.combine(
77+
flow,
78+
flow2,
79+
flow3,
80+
flow4,
81+
flow5,
82+
flow6,
83+
flow7
84+
) { args: Array<*> ->
85+
transform(
86+
args[0] as T1,
87+
args[1] as T2,
88+
args[2] as T3,
89+
args[3] as T4,
90+
args[4] as T5,
91+
args[5] as T6,
92+
args[6] as T7,
93+
)
94+
}

0 commit comments

Comments
 (0)