From f72cfe6831eb5bd880343e23b8bd75f202e4dbb4 Mon Sep 17 00:00:00 2001 From: Filip Stanis Date: Wed, 3 Apr 2024 16:30:45 +0100 Subject: [PATCH] Changes MediaUiModel to use Paintable --- images/coil/api/current.api | 2 +- .../horologist/images/coil/ArtworkColor.kt | 8 ++--- .../ui/player/UampMediaPlayerScreen.kt | 21 ++++++++++---- media/ui/api/current.api | 13 +++++---- .../ui/components/MediaArtworkPreview.kt | 2 +- .../media/ui/components/MediaChipPreview.kt | 6 ++-- .../media/ui/components/MediaArtwork.kt | 29 +++++++++++++++---- .../media/ui/components/MediaChip.kt | 8 ++--- .../background/ArtworkColorBackground.kt | 5 ++-- .../ui/state/mapper/MediaUiModelMapper.kt | 3 +- .../media/ui/state/model/MediaUiModel.kt | 2 +- .../ui/components/MediaArtworkA11yTest.kt | 3 +- .../media/ui/components/MediaChipA11yTest.kt | 7 ++++- .../ui/state/mapper/MediaUiModelMapperTest.kt | 3 +- 14 files changed, 74 insertions(+), 38 deletions(-) diff --git a/images/coil/api/current.api b/images/coil/api/current.api index 6e3cf25624..2efc45750d 100644 --- a/images/coil/api/current.api +++ b/images/coil/api/current.api @@ -2,7 +2,7 @@ package com.google.android.horologist.images.coil { public final class ArtworkColorKt { - method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.runtime.State rememberArtworkColor(String? artworkUri, optional long defaultColor); + method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.runtime.State rememberArtworkColor(Object? model, optional long defaultColor); } @androidx.compose.runtime.Stable public final class CoilPaintable implements com.google.android.horologist.images.base.paintable.Paintable { diff --git a/images/coil/src/main/java/com/google/android/horologist/images/coil/ArtworkColor.kt b/images/coil/src/main/java/com/google/android/horologist/images/coil/ArtworkColor.kt index 536447417a..7d9f818860 100644 --- a/images/coil/src/main/java/com/google/android/horologist/images/coil/ArtworkColor.kt +++ b/images/coil/src/main/java/com/google/android/horologist/images/coil/ArtworkColor.kt @@ -33,7 +33,7 @@ import com.google.android.horologist.annotations.ExperimentalHorologistApi @Composable @ExperimentalHorologistApi public fun rememberArtworkColor( - artworkUri: String?, + model: Any?, defaultColor: Color = MaterialTheme.colors.primary, ): State { val context = LocalContext.current @@ -41,11 +41,11 @@ public fun rememberArtworkColor( val artworkColor = remember { mutableStateOf(defaultColor) } - LaunchedEffect(artworkUri) { - artworkColor.value = if (artworkUri != null) { + LaunchedEffect(model) { + artworkColor.value = if (model != null) { val request = ImageRequest.Builder(context) - .data(artworkUri) + .data(model) .allowHardware(false) .build() val result = imageLoader.execute(request) diff --git a/media/sample/src/main/java/com/google/android/horologist/mediasample/ui/player/UampMediaPlayerScreen.kt b/media/sample/src/main/java/com/google/android/horologist/mediasample/ui/player/UampMediaPlayerScreen.kt index 2affe26123..7fd2d27623 100644 --- a/media/sample/src/main/java/com/google/android/horologist/mediasample/ui/player/UampMediaPlayerScreen.kt +++ b/media/sample/src/main/java/com/google/android/horologist/mediasample/ui/player/UampMediaPlayerScreen.kt @@ -24,10 +24,12 @@ import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.wear.compose.material.MaterialTheme import com.google.android.horologist.audio.ui.VolumeViewModel +import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.media.ui.components.PodcastControlButtons import com.google.android.horologist.media.ui.components.animated.AnimatedMediaControlButtons import com.google.android.horologist.media.ui.components.animated.AnimatedMediaInfoDisplay import com.google.android.horologist.media.ui.components.background.ArtworkColorBackground +import com.google.android.horologist.media.ui.components.background.ColorBackground import com.google.android.horologist.media.ui.screens.player.DefaultMediaInfoDisplay import com.google.android.horologist.media.ui.screens.player.DefaultPlayerScreenControlButtons import com.google.android.horologist.media.ui.screens.player.PlayerScreen @@ -49,12 +51,19 @@ fun UampMediaPlayerScreen( PlayerScreen( modifier = modifier, background = { - val artworkUri = it.media?.artworkUri - ArtworkColorBackground( - artworkUri = artworkUri, - defaultColor = MaterialTheme.colors.primary, - modifier = Modifier.fillMaxSize(), - ) + val artworkColor = it.media?.artworkColor + if (artworkColor != null) { + ColorBackground( + color = artworkColor, + modifier = Modifier.fillMaxSize(), + ) + } else { + ArtworkColorBackground( + paintable = it.media?.artwork as? CoilPaintable, + defaultColor = MaterialTheme.colors.primary, + modifier = Modifier.fillMaxSize(), + ) + } }, playerViewModel = mediaPlayerScreenViewModel, volumeViewModel = volumeViewModel, diff --git a/media/ui/api/current.api b/media/ui/api/current.api index eba90f67fe..fa2fb1a766 100644 --- a/media/ui/api/current.api +++ b/media/ui/api/current.api @@ -53,6 +53,7 @@ package com.google.android.horologist.media.ui.components { } public final class MediaArtworkKt { + method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void MediaArtwork(androidx.compose.ui.graphics.painter.Painter painter, String? contentDescription, optional androidx.compose.ui.Modifier modifier); method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void MediaArtwork(com.google.android.horologist.images.base.paintable.Paintable artworkPaintable, String? contentDescription, optional androidx.compose.ui.Modifier modifier); method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void MediaArtwork(com.google.android.horologist.media.ui.state.model.MediaUiModel media, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.painter.Painter? placeholder); } @@ -133,7 +134,7 @@ package com.google.android.horologist.media.ui.components.animated { package com.google.android.horologist.media.ui.components.background { public final class ArtworkColorBackgroundKt { - method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void ArtworkColorBackground(String? artworkUri, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Color? defaultColor, optional long background); + method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void ArtworkColorBackground(com.google.android.horologist.images.coil.CoilPaintable? paintable, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Color? defaultColor, optional long background); method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void ColorBackground(androidx.compose.ui.graphics.Color? color, optional androidx.compose.ui.Modifier modifier, optional long background); method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static androidx.compose.runtime.State rememberArtworkColorBrush(long artworkColor, optional long background); } @@ -769,23 +770,23 @@ package com.google.android.horologist.media.ui.state.model { } @com.google.android.horologist.annotations.ExperimentalHorologistApi public final class MediaUiModel { - ctor public MediaUiModel(String id, String title, optional String subtitle, optional String? artworkUri, optional androidx.compose.ui.graphics.Color? artworkColor, optional com.google.android.horologist.images.base.paintable.Paintable? titleIcon); + ctor public MediaUiModel(String id, String title, optional String subtitle, optional com.google.android.horologist.images.base.paintable.Paintable? artwork, optional androidx.compose.ui.graphics.Color? artworkColor, optional com.google.android.horologist.images.base.paintable.Paintable? titleIcon); method public String component1(); method public String component2(); method public String component3(); - method public String? component4(); + method public com.google.android.horologist.images.base.paintable.Paintable? component4(); method public androidx.compose.ui.graphics.Color? component5-QN2ZGVo(); method public com.google.android.horologist.images.base.paintable.Paintable? component6(); - method public com.google.android.horologist.media.ui.state.model.MediaUiModel copy-gCxFOHY(String id, String title, String subtitle, String? artworkUri, androidx.compose.ui.graphics.Color? artworkColor, com.google.android.horologist.images.base.paintable.Paintable? titleIcon); + method public com.google.android.horologist.media.ui.state.model.MediaUiModel copy-gCxFOHY(String id, String title, String subtitle, com.google.android.horologist.images.base.paintable.Paintable? artwork, androidx.compose.ui.graphics.Color? artworkColor, com.google.android.horologist.images.base.paintable.Paintable? titleIcon); + method public com.google.android.horologist.images.base.paintable.Paintable? getArtwork(); method public androidx.compose.ui.graphics.Color? getArtworkColor(); - method public String? getArtworkUri(); method public String getId(); method public boolean getLoading(); method public String getSubtitle(); method public String getTitle(); method public com.google.android.horologist.images.base.paintable.Paintable? getTitleIcon(); + property public final com.google.android.horologist.images.base.paintable.Paintable? artwork; property public final androidx.compose.ui.graphics.Color? artworkColor; - property public final String? artworkUri; property public final String id; property public final boolean loading; property public final String subtitle; diff --git a/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaArtworkPreview.kt b/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaArtworkPreview.kt index e051bbd2df..c43c5da876 100644 --- a/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaArtworkPreview.kt +++ b/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaArtworkPreview.kt @@ -33,7 +33,7 @@ fun MediaArtworkPreview() { media = MediaUiModel( id = "id", title = "title", - artworkUri = "artworkUri", + artwork = null, ), placeholder = rememberVectorPainter(image = Icons.Default.Album), ) diff --git a/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaChipPreview.kt b/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaChipPreview.kt index 629a2bfa0c..1607207533 100644 --- a/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaChipPreview.kt +++ b/media/ui/src/debug/java/com/google/android/horologist/media/ui/components/MediaChipPreview.kt @@ -32,7 +32,7 @@ fun MediaChipPreview() { media = MediaUiModel( id = "id", title = "Red Hot Chilli Peppers", - artworkUri = "artworkUri", + artwork = null, ), onClick = {}, placeholder = rememberVectorPainter( @@ -67,7 +67,7 @@ fun MediaChipPreviewNoArtwork() { @Composable fun MediaChipPreviewNoTitle() { MediaChip( - media = MediaUiModel(id = "id", title = "title", artworkUri = "artworkUri"), + media = MediaUiModel(id = "id", title = "title", artwork = null), onClick = {}, defaultTitle = "No title", placeholder = rememberVectorPainter( @@ -88,7 +88,7 @@ fun MediaChipPreviewVeryLongTitle() { media = MediaUiModel( id = "id", title = "Very very very very very very very very very very very very very very very very very very very long title", - artworkUri = "artworkUri", + artwork = null, ), onClick = {}, placeholder = rememberVectorPainter( diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaArtwork.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaArtwork.kt index 68bf9b9b97..d94e698f4b 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaArtwork.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaArtwork.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import com.google.android.horologist.annotations.ExperimentalHorologistApi import com.google.android.horologist.images.base.paintable.Paintable -import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.media.ui.state.model.MediaUiModel @ExperimentalHorologistApi @@ -33,11 +32,14 @@ public fun MediaArtwork( modifier: Modifier = Modifier, placeholder: Painter? = null, ) { - MediaArtwork( - artworkPaintable = CoilPaintable(media.artworkUri, placeholder), - contentDescription = media.title, - modifier = modifier, - ) + val painter = media.artwork?.rememberPainter() ?: placeholder + if (painter != null) { + MediaArtwork( + painter = painter, + contentDescription = media.title, + modifier = modifier, + ) + } } @ExperimentalHorologistApi @@ -54,3 +56,18 @@ public fun MediaArtwork( contentScale = ContentScale.Fit, ) } + +@ExperimentalHorologistApi +@Composable +public fun MediaArtwork( + painter: Painter, + contentDescription: String?, + modifier: Modifier = Modifier, +) { + Image( + modifier = modifier, + painter = painter, + contentDescription = contentDescription, + contentScale = ContentScale.Fit, + ) +} diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaChip.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaChip.kt index eb557404e0..ccb4835727 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaChip.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/MediaChip.kt @@ -37,12 +37,12 @@ import com.google.android.horologist.media.ui.state.model.MediaUiModel * A rounded chip to show a single [MediaUiModel]. * * @param media The [MediaUiModel] that the [title][MediaUiModel.title] and - * [artwork][MediaUiModel.artworkUri] will be used to display on the chip. + * [artwork][MediaUiModel.artwork] will be used to display on the chip. * @param onClick Will be called when the user clicks the chip. * @param modifier The Modifier to be applied to the chip. * @param defaultTitle A text to be used when [MediaUiModel.title] is null. * @param placeholder A placeholder image to be displayed while - * [artwork][MediaUiModel.artworkUri] is being loaded. + * [artwork][MediaUiModel.artwork] is being loaded. */ @ExperimentalHorologistApi @Composable @@ -53,7 +53,7 @@ public fun MediaChip( defaultTitle: String = "", placeholder: Painter? = null, ) { - val artworkUri = media.artworkUri + val artworkUri = media.artwork val title = media.title MediaChip( @@ -80,7 +80,7 @@ public fun MediaChip( MediaArtwork( modifier = Modifier.size(ChipDefaults.LargeIconSize), contentDescription = title, - artworkPaintable = artworkPaintable, + artworkPaintable = it, ) } } diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/background/ArtworkColorBackground.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/background/ArtworkColorBackground.kt index 91ead7a391..d8cb2b4025 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/background/ArtworkColorBackground.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/background/ArtworkColorBackground.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.graphics.RadialGradientShader import androidx.compose.ui.graphics.compositeOver import androidx.wear.compose.material.MaterialTheme import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.images.coil.rememberArtworkColor /** @@ -45,13 +46,13 @@ import com.google.android.horologist.images.coil.rememberArtworkColor @Composable @ExperimentalHorologistApi public fun ArtworkColorBackground( - artworkUri: String?, + paintable: CoilPaintable?, modifier: Modifier = Modifier, defaultColor: Color? = null, background: Color = MaterialTheme.colors.background, ) { val artworkColor = rememberArtworkColor( - artworkUri = artworkUri, + model = paintable?.model, defaultColor = defaultColor ?: Color.Black, ) diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapper.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapper.kt index 61fbdff105..90fd1805d9 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapper.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapper.kt @@ -18,6 +18,7 @@ package com.google.android.horologist.media.ui.state.mapper import androidx.compose.ui.graphics.Color import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.media.model.Media import com.google.android.horologist.media.ui.state.model.MediaUiModel @@ -38,7 +39,7 @@ public object MediaUiModelMapper { id = media.id, title = title, subtitle = artist, - artworkUri = media.artworkUri, + artwork = media.artworkUri?.let { CoilPaintable(it) }, artworkColor = media.artworkColor?.let { Color(it) }, ) } diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/state/model/MediaUiModel.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/state/model/MediaUiModel.kt index 5427afcc21..e6916b1db9 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/state/model/MediaUiModel.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/state/model/MediaUiModel.kt @@ -25,7 +25,7 @@ public data class MediaUiModel( val id: String, val title: String, val subtitle: String = "", - val artworkUri: String? = null, + val artwork: Paintable? = null, val artworkColor: Color? = null, val titleIcon: Paintable? = null, ) { diff --git a/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaArtworkA11yTest.kt b/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaArtworkA11yTest.kt index 01da4c5b79..e906ebe1cf 100644 --- a/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaArtworkA11yTest.kt +++ b/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaArtworkA11yTest.kt @@ -29,6 +29,7 @@ import coil.annotation.ExperimentalCoilApi import coil.decode.DataSource import coil.request.SuccessResult import coil.test.FakeImageLoaderEngine +import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.images.coil.FakeImageLoader import com.google.android.horologist.media.ui.state.model.MediaUiModel import com.google.android.horologist.screenshots.rng.WearLegacyA11yTest @@ -62,7 +63,7 @@ class MediaArtworkA11yTest : WearLegacyA11yTest() { media = MediaUiModel( id = "id", title = "title", - artworkUri = FakeImageLoader.TestIconResourceUri, + artwork = CoilPaintable(FakeImageLoader.TestIconResourceUri), ), placeholder = rememberVectorPainter(image = Icons.Default.Album), ) diff --git a/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaChipA11yTest.kt b/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaChipA11yTest.kt index 0ad3255960..b807fc5767 100644 --- a/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaChipA11yTest.kt +++ b/media/ui/src/test/java/com/google/android/horologist/media/ui/components/MediaChipA11yTest.kt @@ -23,6 +23,11 @@ import coil.annotation.ExperimentalCoilApi import coil.decode.DataSource import coil.request.SuccessResult import coil.test.FakeImageLoaderEngine +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.images.coil.FakeImageLoader import com.google.android.horologist.media.ui.state.model.MediaUiModel import com.google.android.horologist.screenshots.rng.WearLegacyA11yTest @@ -55,7 +60,7 @@ class MediaChipA11yTest : WearLegacyA11yTest() { media = MediaUiModel( id = "id", title = "Red Hot Chilli Peppers", - artworkUri = FakeImageLoader.TestIconResourceUri, + artwork = CoilPaintable(FakeImageLoader.TestIconResourceUri), ), onClick = {}, ) diff --git a/media/ui/src/test/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapperTest.kt b/media/ui/src/test/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapperTest.kt index 338bc441d1..d6b544c6af 100644 --- a/media/ui/src/test/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapperTest.kt +++ b/media/ui/src/test/java/com/google/android/horologist/media/ui/state/mapper/MediaUiModelMapperTest.kt @@ -16,6 +16,7 @@ package com.google.android.horologist.media.ui.state.mapper +import com.google.android.horologist.images.coil.CoilPaintable import com.google.android.horologist.media.model.Media import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -44,6 +45,6 @@ class MediaUiModelMapperTest { assertThat(result.id).isEqualTo(id) assertThat(result.title).isEqualTo(title) assertThat(result.subtitle).isEqualTo(artist) - assertThat(result.artworkUri).isEqualTo(artworkUri) + assertThat(result.artwork).isEqualTo(CoilPaintable(artworkUri)) } }