Skip to content

Commit 359e278

Browse files
authored
Switching to PodcastImage (#1360)
This pull request switch the component to show thumbnails in tv apps from `AsyncImage` into `PodcastImage`. As a side effect of the migration, Podcast`, `PodcastWithExtraInfo` and `EpisodeToPodcast` are replaced with their external models.
2 parents 7631197 + 1793321 commit 359e278

File tree

20 files changed

+190
-182
lines changed

20 files changed

+190
-182
lines changed

Jetcaster/designsystem/src/main/java/com/example/jetcaster/designsystem/component/PodcastImage.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ import androidx.compose.foundation.layout.Box
2222
import androidx.compose.foundation.layout.fillMaxSize
2323
import androidx.compose.foundation.layout.size
2424
import androidx.compose.material3.CircularProgressIndicator
25-
import androidx.compose.material3.MaterialTheme
2625
import androidx.compose.runtime.Composable
2726
import androidx.compose.runtime.getValue
2827
import androidx.compose.runtime.mutableStateOf
2928
import androidx.compose.runtime.remember
3029
import androidx.compose.runtime.setValue
3130
import androidx.compose.ui.Alignment
3231
import androidx.compose.ui.Modifier
32+
import androidx.compose.ui.graphics.Brush
3333
import androidx.compose.ui.layout.ContentScale
3434
import androidx.compose.ui.platform.LocalContext
3535
import androidx.compose.ui.unit.dp
@@ -43,6 +43,7 @@ fun PodcastImage(
4343
contentDescription: String?,
4444
modifier: Modifier = Modifier,
4545
contentScale: ContentScale = ContentScale.Crop,
46+
placeholderBrush: Brush = thumbnailPlaceholderDefaultBrush(),
4647
) {
4748
var imagePainterState by remember {
4849
mutableStateOf<AsyncImagePainter.State>(AsyncImagePainter.State.Empty)
@@ -73,8 +74,9 @@ fun PodcastImage(
7374
else -> {
7475
Box(
7576
modifier = Modifier
77+
.background(placeholderBrush)
7678
.fillMaxSize()
77-
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
79+
7880
)
7981
}
8082
}

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/thumbnailPlaceholder.kt renamed to Jetcaster/designsystem/src/main/java/com/example/jetcaster/designsystem/component/thumbnailPlaceholder.kt

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,30 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.example.jetcaster.tv.ui.component
17+
package com.example.jetcaster.designsystem.component
1818

19+
import androidx.compose.foundation.isSystemInDarkTheme
1920
import androidx.compose.runtime.Composable
2021
import androidx.compose.ui.graphics.Brush
22+
import androidx.compose.ui.graphics.Color
2123
import androidx.compose.ui.graphics.SolidColor
22-
import androidx.compose.ui.graphics.painter.BrushPainter
23-
import androidx.tv.material3.ExperimentalTvMaterial3Api
24-
import androidx.tv.material3.MaterialTheme
24+
import com.example.jetcaster.designsystem.theme.surfaceVariantDark
25+
import com.example.jetcaster.designsystem.theme.surfaceVariantLight
2526

26-
@OptIn(ExperimentalTvMaterial3Api::class)
2727
@Composable
28-
internal fun thumbnailPlaceholder(
29-
brush: Brush = SolidColor(MaterialTheme.colorScheme.surfaceVariant)
30-
): BrushPainter {
31-
return BrushPainter(brush)
28+
internal fun thumbnailPlaceholderDefaultBrush(
29+
color: Color = thumbnailPlaceHolderDefaultColor()
30+
): Brush {
31+
return SolidColor(color)
32+
}
33+
34+
@Composable
35+
private fun thumbnailPlaceHolderDefaultColor(
36+
isInDarkMode: Boolean = isSystemInDarkTheme()
37+
): Color {
38+
return if (isInDarkMode) {
39+
surfaceVariantDark
40+
} else {
41+
surfaceVariantLight
42+
}
3243
}

Jetcaster/tv-app/build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ android {
4040
buildTypes {
4141
getByName("release") {
4242
isMinifyEnabled = true
43-
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"),
44-
"proguard-rules.pro")
43+
proguardFiles(
44+
getDefaultProguardFile("proguard-android-optimize.txt"),
45+
"proguard-rules.pro"
46+
)
4547
}
4648
}
4749

@@ -79,15 +81,13 @@ dependencies {
7981
implementation(libs.androidx.lifecycle.runtime.compose)
8082
implementation(libs.androidx.activity.compose)
8183
implementation(libs.androidx.navigation.compose)
82-
implementation(libs.coil.kt.compose)
8384

8485
// Dependency injection
8586
implementation(libs.androidx.hilt.navigation.compose)
8687
implementation(libs.hilt.android)
8788
implementation(project(":core:model"))
8889
ksp(libs.hilt.compiler)
8990

90-
9191
implementation(project(":core"))
9292
implementation(project(":designsystem"))
9393

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/model/PodcastList.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package com.example.jetcaster.tv.model
1818

1919
import androidx.compose.runtime.Immutable
20-
import com.example.jetcaster.core.data.database.model.PodcastWithExtraInfo
20+
import com.example.jetcaster.core.model.PodcastInfo
2121

2222
@Immutable
2323
data class PodcastList(
24-
val member: List<PodcastWithExtraInfo>
25-
) : List<PodcastWithExtraInfo> by member
24+
val member: List<PodcastInfo>
25+
) : List<PodcastInfo> by member

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/JetcasterApp.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ private fun Route(jetcasterAppState: JetcasterAppState) {
141141
LibraryScreen(
142142
navigateToDiscover = jetcasterAppState::navigateToDiscover,
143143
showPodcastDetails = {
144-
jetcasterAppState.showPodcastDetails(it.podcast.uri)
144+
jetcasterAppState.showPodcastDetails(it.uri)
145145
},
146146
playEpisode = {
147147
jetcasterAppState.playEpisode()
@@ -156,7 +156,7 @@ private fun Route(jetcasterAppState: JetcasterAppState) {
156156
composable(Screen.Search.route) {
157157
SearchScreen(
158158
onPodcastSelected = {
159-
jetcasterAppState.showPodcastDetails(it.podcast.uri)
159+
jetcasterAppState.showPodcastDetails(it.uri)
160160
},
161161
modifier = Modifier
162162
.padding(JetcasterAppDefaults.overScanMargin.default.intoPaddingValues())

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Background.kt

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,43 +23,54 @@ import androidx.compose.runtime.Composable
2323
import androidx.compose.ui.Alignment
2424
import androidx.compose.ui.Modifier
2525
import androidx.compose.ui.graphics.Color
26-
import com.example.jetcaster.core.data.database.model.Podcast
2726
import com.example.jetcaster.core.model.PlayerEpisode
27+
import com.example.jetcaster.core.model.PodcastInfo
2828
import com.example.jetcaster.designsystem.component.ImageBackgroundRadialGradientScrim
2929

3030
@Composable
31-
internal fun Background(
32-
podcast: Podcast,
33-
modifier: Modifier = Modifier,
34-
) = Background(imageUrl = podcast.imageUrl, modifier)
35-
36-
@Composable
37-
internal fun Background(
38-
episode: PlayerEpisode,
31+
internal fun BackgroundContainer(
32+
playerEpisode: PlayerEpisode,
3933
modifier: Modifier = Modifier,
40-
) = Background(imageUrl = episode.podcastImageUrl, modifier)
34+
contentAlignment: Alignment = Alignment.Center,
35+
content: @Composable BoxScope.() -> Unit
36+
) =
37+
BackgroundContainer(
38+
imageUrl = playerEpisode.podcastImageUrl,
39+
modifier,
40+
contentAlignment,
41+
content
42+
)
4143

4244
@Composable
43-
internal fun Background(
44-
imageUrl: String?,
45+
internal fun BackgroundContainer(
46+
podcastInfo: PodcastInfo,
4547
modifier: Modifier = Modifier,
46-
) {
47-
ImageBackgroundRadialGradientScrim(
48-
url = imageUrl,
49-
colors = listOf(Color.Black, Color.Transparent),
50-
modifier = modifier,
51-
)
52-
}
48+
contentAlignment: Alignment = Alignment.Center,
49+
content: @Composable BoxScope.() -> Unit
50+
) =
51+
BackgroundContainer(imageUrl = podcastInfo.imageUrl, modifier, contentAlignment, content)
5352

5453
@Composable
5554
internal fun BackgroundContainer(
56-
playerEpisode: PlayerEpisode,
55+
imageUrl: String,
5756
modifier: Modifier = Modifier,
5857
contentAlignment: Alignment = Alignment.Center,
5958
content: @Composable BoxScope.() -> Unit
6059
) {
6160
Box(modifier = modifier, contentAlignment = contentAlignment) {
62-
Background(episode = playerEpisode, modifier = Modifier.fillMaxSize())
61+
Background(imageUrl = imageUrl, modifier = Modifier.fillMaxSize())
6362
content()
6463
}
6564
}
65+
66+
@Composable
67+
private fun Background(
68+
imageUrl: String,
69+
modifier: Modifier = Modifier,
70+
) {
71+
ImageBackgroundRadialGradientScrim(
72+
url = imageUrl,
73+
colors = listOf(Color.Black, Color.Transparent),
74+
modifier = modifier,
75+
)
76+
}

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Catalog.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ import androidx.tv.foundation.lazy.list.rememberTvLazyListState
3535
import androidx.tv.material3.ExperimentalTvMaterial3Api
3636
import androidx.tv.material3.MaterialTheme
3737
import androidx.tv.material3.Text
38-
import com.example.jetcaster.core.data.database.model.PodcastWithExtraInfo
3938
import com.example.jetcaster.core.model.PlayerEpisode
39+
import com.example.jetcaster.core.model.PodcastInfo
4040
import com.example.jetcaster.tv.R
4141
import com.example.jetcaster.tv.model.EpisodeList
4242
import com.example.jetcaster.tv.model.PodcastList
@@ -46,7 +46,7 @@ import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults
4646
internal fun Catalog(
4747
podcastList: PodcastList,
4848
latestEpisodeList: EpisodeList,
49-
onPodcastSelected: (PodcastWithExtraInfo) -> Unit,
49+
onPodcastSelected: (PodcastInfo) -> Unit,
5050
onEpisodeSelected: (PlayerEpisode) -> Unit,
5151
modifier: Modifier = Modifier,
5252
state: TvLazyListState = rememberTvLazyListState(),
@@ -83,7 +83,7 @@ internal fun Catalog(
8383
@Composable
8484
private fun PodcastSection(
8585
podcastList: PodcastList,
86-
onPodcastSelected: (PodcastWithExtraInfo) -> Unit,
86+
onPodcastSelected: (PodcastInfo) -> Unit,
8787
modifier: Modifier = Modifier,
8888
title: String? = null,
8989
) {
@@ -142,7 +142,7 @@ private fun Section(
142142
@Composable
143143
private fun PodcastRow(
144144
podcastList: PodcastList,
145-
onPodcastSelected: (PodcastWithExtraInfo) -> Unit,
145+
onPodcastSelected: (PodcastInfo) -> Unit,
146146
modifier: Modifier = Modifier,
147147
contentPadding: PaddingValues = PaddingValues(),
148148
horizontalArrangement: Arrangement.Horizontal =
@@ -155,7 +155,7 @@ private fun PodcastRow(
155155
) {
156156
items(podcastList) {
157157
PodcastCard(
158-
podcast = it.podcast,
158+
podcastInfo = it,
159159
onClick = { onPodcastSelected(it) },
160160
modifier = Modifier.width(JetcasterAppDefaults.cardWidth.medium)
161161
)

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/EpisodeCard.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package com.example.jetcaster.tv.ui.component
1919
import androidx.compose.foundation.interaction.MutableInteractionSource
2020
import androidx.compose.foundation.layout.Column
2121
import androidx.compose.foundation.layout.Spacer
22-
import androidx.compose.foundation.layout.fillMaxSize
2322
import androidx.compose.foundation.layout.height
2423
import androidx.compose.foundation.layout.padding
2524
import androidx.compose.foundation.layout.size
@@ -36,7 +35,6 @@ import androidx.tv.material3.ExperimentalTvMaterial3Api
3635
import androidx.tv.material3.MaterialTheme
3736
import androidx.tv.material3.Text
3837
import androidx.tv.material3.WideCardLayout
39-
import coil.compose.AsyncImage
4038
import com.example.jetcaster.core.model.PlayerEpisode
4139
import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults
4240

@@ -78,12 +76,7 @@ private fun EpisodeThumbnail(
7876
scale = CardScale.None,
7977
modifier = modifier,
8078
) {
81-
AsyncImage(
82-
model = playerEpisode.podcastImageUrl,
83-
contentDescription = null,
84-
placeholder = thumbnailPlaceholder(),
85-
modifier = Modifier.fillMaxSize()
86-
)
79+
Thumbnail(episode = playerEpisode, size = JetcasterAppDefaults.thumbnailSize.episode)
8780
}
8881
}
8982

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/PodcastCard.kt

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.example.jetcaster.tv.ui.component
1818

1919
import androidx.compose.foundation.layout.padding
20-
import androidx.compose.foundation.layout.size
2120
import androidx.compose.runtime.Composable
2221
import androidx.compose.ui.Modifier
2322
import androidx.compose.ui.unit.dp
@@ -26,14 +25,13 @@ import androidx.tv.material3.CardScale
2625
import androidx.tv.material3.ExperimentalTvMaterial3Api
2726
import androidx.tv.material3.StandardCardLayout
2827
import androidx.tv.material3.Text
29-
import coil.compose.AsyncImage
30-
import com.example.jetcaster.core.data.database.model.Podcast
28+
import com.example.jetcaster.core.model.PodcastInfo
3129
import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults
3230

3331
@OptIn(ExperimentalTvMaterial3Api::class)
3432
@Composable
3533
internal fun PodcastCard(
36-
podcast: Podcast,
34+
podcastInfo: PodcastInfo,
3735
onClick: () -> Unit,
3836
modifier: Modifier = Modifier,
3937
) {
@@ -44,16 +42,14 @@ internal fun PodcastCard(
4442
interactionSource = it,
4543
scale = CardScale.None,
4644
) {
47-
AsyncImage(
48-
model = podcast.imageUrl,
49-
contentDescription = null,
50-
placeholder = thumbnailPlaceholder(),
51-
modifier = Modifier.size(JetcasterAppDefaults.thumbnailSize.podcast)
45+
Thumbnail(
46+
podcastInfo = podcastInfo,
47+
size = JetcasterAppDefaults.thumbnailSize.podcast
5248
)
5349
}
5450
},
5551
title = {
56-
Text(text = podcast.title, modifier = Modifier.padding(top = 12.dp))
52+
Text(text = podcastInfo.title, modifier = Modifier.padding(top = 12.dp))
5753
},
5854
modifier = modifier,
5955
)

Jetcaster/tv-app/src/main/java/com/example/jetcaster/tv/ui/component/Thumbnail.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ import androidx.compose.ui.draw.clip
2424
import androidx.compose.ui.layout.ContentScale
2525
import androidx.compose.ui.unit.DpSize
2626
import androidx.compose.ui.unit.dp
27-
import coil.compose.AsyncImage
28-
import com.example.jetcaster.core.data.database.model.Podcast
2927
import com.example.jetcaster.core.model.PlayerEpisode
28+
import com.example.jetcaster.core.model.PodcastInfo
29+
import com.example.jetcaster.designsystem.component.PodcastImage
3030
import com.example.jetcaster.tv.ui.theme.JetcasterAppDefaults
3131

3232
@Composable
3333
fun Thumbnail(
34-
podcast: Podcast,
34+
podcastInfo: PodcastInfo,
3535
modifier: Modifier = Modifier,
3636
shape: RoundedCornerShape = RoundedCornerShape(12.dp),
3737
size: DpSize = DpSize(
@@ -41,7 +41,7 @@ fun Thumbnail(
4141
contentScale: ContentScale = ContentScale.Crop
4242
) =
4343
Thumbnail(
44-
podcast.imageUrl,
44+
podcastInfo.imageUrl,
4545
modifier,
4646
shape,
4747
size,
@@ -69,7 +69,7 @@ fun Thumbnail(
6969

7070
@Composable
7171
fun Thumbnail(
72-
url: String?,
72+
url: String,
7373
modifier: Modifier = Modifier,
7474
shape: RoundedCornerShape = RoundedCornerShape(12.dp),
7575
size: DpSize = DpSize(
@@ -78,12 +78,11 @@ fun Thumbnail(
7878
),
7979
contentScale: ContentScale = ContentScale.Crop
8080
) =
81-
AsyncImage(
82-
model = url,
81+
PodcastImage(
82+
podcastImageUrl = url,
8383
contentDescription = null,
8484
contentScale = contentScale,
85-
modifier = Modifier
86-
.size(size)
85+
modifier = modifier
8786
.clip(shape)
88-
.then(modifier)
87+
.size(size),
8988
)

0 commit comments

Comments
 (0)