From 73b1d8c1306af64a66077e7b590db113d72164c3 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Mon, 10 Jun 2024 13:49:05 +0100 Subject: [PATCH] rememberActivePlaceholderState API (#2263) --- .../wear/prompt/settings/SettingsScreen.kt | 12 +++- auth/composables/build.gradle.kts | 7 ++- composables/api/current.api | 2 +- composables/build.gradle.kts | 10 +-- .../horologist/composables/PlaceholderChip.kt | 61 ++++++++++--------- compose-layout/api/current.api | 4 ++ .../horologist/compose/layout/Placeholder.kt | 46 ++++++++++++++ compose-material/build.gradle.kts | 6 +- media/ui/api/current.api | 2 +- media/ui/build.gradle.kts | 1 + .../components/display/LoadingMediaDisplay.kt | 11 +--- .../screens/entity/PlaylistStreamingScreen.kt | 15 ++++- .../ui/screens/playlists/PlaylistsScreen.kt | 11 +++- sample/build.gradle.kts | 3 + .../android/horologist/paging/PagingScreen.kt | 25 +++----- 15 files changed, 150 insertions(+), 66 deletions(-) create mode 100644 compose-layout/src/main/java/com/google/android/horologist/compose/layout/Placeholder.kt diff --git a/ai/sample/wear-prompt-app/src/main/java/com/google/android/horologist/ai/sample/wear/prompt/settings/SettingsScreen.kt b/ai/sample/wear-prompt-app/src/main/java/com/google/android/horologist/ai/sample/wear/prompt/settings/SettingsScreen.kt index 7090bbe29a..cc152d47fd 100644 --- a/ai/sample/wear-prompt-app/src/main/java/com/google/android/horologist/ai/sample/wear/prompt/settings/SettingsScreen.kt +++ b/ai/sample/wear-prompt-app/src/main/java/com/google/android/horologist/ai/sample/wear/prompt/settings/SettingsScreen.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalWearMaterialApi::class) + package com.google.android.horologist.ai.sample.wear.prompt.settings import androidx.compose.runtime.Composable @@ -23,6 +25,7 @@ import androidx.compose.ui.Modifier import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.wear.compose.foundation.lazy.items +import androidx.wear.compose.material.ExperimentalWearMaterialApi import androidx.wear.compose.material.Text import androidx.wear.compose.ui.tooling.preview.WearPreviewLargeRound import com.google.android.horologist.ai.ui.model.ModelInstanceUiModel @@ -32,6 +35,7 @@ import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.It import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.listTextPadding import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults.padding import com.google.android.horologist.compose.layout.ScreenScaffold +import com.google.android.horologist.compose.layout.rememberActivePlaceholderState import com.google.android.horologist.compose.layout.rememberResponsiveColumnState import com.google.android.horologist.compose.material.ResponsiveListHeader import com.google.android.horologist.compose.material.ToggleChip @@ -64,11 +68,17 @@ private fun SettingsScreen( ), ) + val placeholderState = rememberActivePlaceholderState { uiState.models != null } + ScreenScaffold(scrollState = columnState, modifier = modifier) { ScalingLazyColumn(columnState = columnState) { if (uiState.models == null) { items(3) { - PlaceholderChip() + PlaceholderChip( + placeholderState = placeholderState, + icon = false, + secondaryLabel = false, + ) } } else { item { diff --git a/auth/composables/build.gradle.kts b/auth/composables/build.gradle.kts index e61dcc8152..59ac6efb27 100644 --- a/auth/composables/build.gradle.kts +++ b/auth/composables/build.gradle.kts @@ -44,8 +44,11 @@ android { kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-opt-in=kotlin.RequiresOptIn" - freeCompilerArgs = freeCompilerArgs + "-opt-in=com.google.android.horologist.annotations.ExperimentalHorologistApi" + freeCompilerArgs += listOf( + "-opt-in=com.google.android.horologist.annotations.ExperimentalHorologistApi", + "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", + "-opt-in=androidx.wear.compose.material.ExperimentalWearMaterialApi", + ) } composeOptions { diff --git a/composables/api/current.api b/composables/api/current.api index 0b80521756..6db62a96e6 100644 --- a/composables/api/current.api +++ b/composables/api/current.api @@ -11,7 +11,7 @@ package com.google.android.horologist.composables { } public final class PlaceholderChipKt { - method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void PlaceholderChip(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0 onClick, optional androidx.wear.compose.material.ChipColors colors, optional boolean enabled, optional String contentDescription); + method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void PlaceholderChip(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0 onClick, optional androidx.wear.compose.material.PlaceholderState placeholderState, optional boolean secondaryLabel, optional boolean icon, optional androidx.wear.compose.material.ChipColors colors, optional boolean enabled, optional String contentDescription); } public final class ProgressIndicatorSegment { diff --git a/composables/build.gradle.kts b/composables/build.gradle.kts index b52d168bb2..3d11e395a8 100644 --- a/composables/build.gradle.kts +++ b/composables/build.gradle.kts @@ -43,11 +43,11 @@ android { kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + - listOf( - "-opt-in=kotlin.RequiresOptIn", - "-opt-in=com.google.android.horologist.annotations.ExperimentalHorologistApi", - ) + freeCompilerArgs += listOf( + "-opt-in=com.google.android.horologist.annotations.ExperimentalHorologistApi", + "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", + "-opt-in=androidx.wear.compose.material.ExperimentalWearMaterialApi", + ) } composeOptions { diff --git a/composables/src/main/java/com/google/android/horologist/composables/PlaceholderChip.kt b/composables/src/main/java/com/google/android/horologist/composables/PlaceholderChip.kt index ecabb0e068..05aa56796c 100644 --- a/composables/src/main/java/com/google/android/horologist/composables/PlaceholderChip.kt +++ b/composables/src/main/java/com/google/android/horologist/composables/PlaceholderChip.kt @@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.paint @@ -41,10 +40,11 @@ import androidx.wear.compose.material.ChipDefaults import androidx.wear.compose.material.ExperimentalWearMaterialApi import androidx.wear.compose.material.MaterialTheme import androidx.wear.compose.material.PlaceholderDefaults +import androidx.wear.compose.material.PlaceholderState import androidx.wear.compose.material.placeholder import androidx.wear.compose.material.placeholderShimmer -import androidx.wear.compose.material.rememberPlaceholderState import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.rememberActivePlaceholderState /** * A placeholder chip to be displayed while the contents of the [Chip] is being loaded. @@ -55,12 +55,13 @@ import com.google.android.horologist.annotations.ExperimentalHorologistApi public fun PlaceholderChip( modifier: Modifier = Modifier, onClick: () -> Unit = {}, + placeholderState: PlaceholderState = rememberActivePlaceholderState { false }, + secondaryLabel: Boolean = true, + icon: Boolean = true, colors: ChipColors = ChipDefaults.primaryChipColors(), enabled: Boolean = false, contentDescription: String = stringResource(id = R.string.horologist_placeholderchip_content_description), ) { - val chipPlaceholderState = rememberPlaceholderState { false } - Chip( modifier = modifier .height(ChipDefaults.Height) @@ -70,7 +71,7 @@ public fun PlaceholderChip( painter = colors.background(enabled = enabled).value, contentScale = ContentScale.Crop, ) - .placeholderShimmer(chipPlaceholderState) + .placeholderShimmer(placeholderState) .semantics { this.contentDescription = contentDescription }, @@ -84,38 +85,40 @@ public fun PlaceholderChip( .clip(RoundedCornerShape(12.dp)) .fillMaxWidth() .height(12.dp) - .placeholder(chipPlaceholderState), + .placeholder(placeholderState), ) Spacer(Modifier.size(8.dp)) } }, - secondaryLabel = { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(end = 30.dp) - .clip(RoundedCornerShape(12.dp)) - .height(12.dp) - .placeholder(chipPlaceholderState), - ) + secondaryLabel = if (secondaryLabel) { + { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(end = 30.dp) + .clip(RoundedCornerShape(12.dp)) + .height(12.dp) + .placeholder(placeholderState), + ) + } + } else { + null }, - icon = { - Box( - modifier = Modifier - .clip(CircleShape) - .size(ChipDefaults.LargeIconSize) - .placeholder(chipPlaceholderState), - ) + icon = if (icon) { + { + Box( + modifier = Modifier + .clip(CircleShape) + .size(ChipDefaults.LargeIconSize) + .placeholder(placeholderState), + ) + } + } else { + null }, colors = PlaceholderDefaults.placeholderChipColors( originalChipColors = colors, - placeholderState = chipPlaceholderState, + placeholderState = placeholderState, ), ) - - if (!chipPlaceholderState.isShowContent) { - LaunchedEffect(chipPlaceholderState) { - chipPlaceholderState.startPlaceholderAnimation() - } - } } diff --git a/compose-layout/api/current.api b/compose-layout/api/current.api index 06e7e25015..707f474908 100644 --- a/compose-layout/api/current.api +++ b/compose-layout/api/current.api @@ -55,6 +55,10 @@ package com.google.android.horologist.compose.layout { method @androidx.compose.runtime.Composable public static void PagerScaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0? timeText, optional androidx.compose.foundation.pager.PagerState? pagerState, kotlin.jvm.functions.Function1 content); } + public final class PlaceholderKt { + method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PlaceholderState rememberActivePlaceholderState(kotlin.jvm.functions.Function0 isContentReady); + } + public final class ResponsiveTimeTextKt { method @androidx.compose.runtime.Composable public static void ResponsiveTimeText(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.TimeSource timeSource, optional androidx.compose.ui.text.TextStyle timeTextStyle, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0? startLinearContent, optional kotlin.jvm.functions.Function1? startCurvedContent, optional kotlin.jvm.functions.Function0? endLinearContent, optional kotlin.jvm.functions.Function1? endCurvedContent, optional kotlin.jvm.functions.Function0 textLinearSeparator, optional kotlin.jvm.functions.Function1 textCurvedSeparator); method @androidx.compose.runtime.Composable public static androidx.compose.foundation.layout.PaddingValues responsivePaddingDefaults(); diff --git a/compose-layout/src/main/java/com/google/android/horologist/compose/layout/Placeholder.kt b/compose-layout/src/main/java/com/google/android/horologist/compose/layout/Placeholder.kt new file mode 100644 index 0000000000..0bb629a56a --- /dev/null +++ b/compose-layout/src/main/java/com/google/android/horologist/compose/layout/Placeholder.kt @@ -0,0 +1,46 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalWearMaterialApi::class, ExperimentalWearFoundationApi::class) + +package com.google.android.horologist.compose.layout + +import androidx.compose.runtime.Composable +import androidx.wear.compose.foundation.ExperimentalWearFoundationApi +import androidx.wear.compose.foundation.OnFocusChange +import androidx.wear.compose.material.ExperimentalWearMaterialApi +import androidx.wear.compose.material.PlaceholderState +import androidx.wear.compose.material.rememberPlaceholderState +import kotlinx.coroutines.launch + +@Composable +fun rememberActivePlaceholderState(isContentReady: () -> Boolean): PlaceholderState { + val placeholderState = rememberPlaceholderState { + isContentReady() + } + + OnFocusChange { focused -> + if (focused) { + if (!placeholderState.isShowContent) { + launch { + placeholderState.startPlaceholderAnimation() + } + } + } + } + + return placeholderState +} diff --git a/compose-material/build.gradle.kts b/compose-material/build.gradle.kts index c799175e44..fd673f1d87 100644 --- a/compose-material/build.gradle.kts +++ b/compose-material/build.gradle.kts @@ -50,7 +50,11 @@ android { kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-opt-in=com.google.android.horologist.annotations.ExperimentalHorologistApi" + freeCompilerArgs += listOf( + "-opt-in=com.google.android.horologist.annotations.ExperimentalHorologistApi", + "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", + "-opt-in=androidx.wear.compose.material.ExperimentalWearMaterialApi", + ) } composeOptions { diff --git a/media/ui/api/current.api b/media/ui/api/current.api index bdf24e1a42..a3c8684f7d 100644 --- a/media/ui/api/current.api +++ b/media/ui/api/current.api @@ -219,7 +219,7 @@ package com.google.android.horologist.media.ui.components.controls { package com.google.android.horologist.media.ui.components.display { public final class LoadingMediaDisplayKt { - method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void LoadingMediaDisplay(optional androidx.compose.ui.Modifier modifier); + method @androidx.compose.runtime.Composable @com.google.android.horologist.annotations.ExperimentalHorologistApi public static void LoadingMediaDisplay(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.PlaceholderState placeholderState); } public final class MessageMediaDisplayKt { diff --git a/media/ui/build.gradle.kts b/media/ui/build.gradle.kts index 97ef7aa9a6..a959baf1f7 100644 --- a/media/ui/build.gradle.kts +++ b/media/ui/build.gradle.kts @@ -49,6 +49,7 @@ android { com.google.android.horologist.annotations.ExperimentalHorologistApi kotlin.RequiresOptIn kotlinx.coroutines.ExperimentalCoroutinesApi + androidx.wear.compose.material.ExperimentalWearMaterialApi """.trim().split("\\s+".toRegex()).map { "-opt-in=$it" } diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/display/LoadingMediaDisplay.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/display/LoadingMediaDisplay.kt index 201b71f7a9..377cc9cd6b 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/components/display/LoadingMediaDisplay.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/components/display/LoadingMediaDisplay.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -32,10 +31,11 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.dp import androidx.wear.compose.material.ExperimentalWearMaterialApi import androidx.wear.compose.material.MaterialTheme +import androidx.wear.compose.material.PlaceholderState import androidx.wear.compose.material.placeholder import androidx.wear.compose.material.placeholderShimmer -import androidx.wear.compose.material.rememberPlaceholderState import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.rememberActivePlaceholderState import com.google.android.horologist.media.ui.components.animated.MarqueeTextMediaDisplay import com.google.android.horologist.media.ui.util.isLargeScreen @@ -48,9 +48,8 @@ import com.google.android.horologist.media.ui.util.isLargeScreen @Composable public fun LoadingMediaDisplay( modifier: Modifier = Modifier, + placeholderState: PlaceholderState = rememberActivePlaceholderState { false }, ) { - // Always shimmer on the placeholder pills. - val placeholderState = rememberPlaceholderState(isContentReady = { false }) val isLargeScreen = LocalConfiguration.current.isLargeScreen Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { @@ -81,8 +80,4 @@ public fun LoadingMediaDisplay( .height(12.dp), ) } - - if (!placeholderState.isShowContent) { - LaunchedEffect(placeholderState) { placeholderState.startPlaceholderAnimation() } - } } diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/entity/PlaylistStreamingScreen.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/entity/PlaylistStreamingScreen.kt index 68196a4673..95d30c6f40 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/entity/PlaylistStreamingScreen.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/entity/PlaylistStreamingScreen.kt @@ -31,6 +31,7 @@ import androidx.wear.compose.material.ChipDefaults import com.google.android.horologist.annotations.ExperimentalHorologistApi import com.google.android.horologist.composables.PlaceholderChip import com.google.android.horologist.compose.layout.ScalingLazyColumnState +import com.google.android.horologist.compose.layout.rememberActivePlaceholderState import com.google.android.horologist.compose.material.Button import com.google.android.horologist.compose.material.Chip import com.google.android.horologist.images.coil.CoilPaintable @@ -64,11 +65,23 @@ public fun PlaylistStreamingScreen( PlaylistDownloadScreenState.Failed -> EntityScreenState.Failed } + // TODO This should be folded into SectionedList + val placeholderState = + rememberActivePlaceholderState { entityScreenState !is EntityScreenState.Loading } + EntityScreen( columnState = columnState, entityScreenState = entityScreenState, headerContent = { DefaultEntityScreenHeader(title = playlistName) }, - loadingContent = { items(count = 2) { PlaceholderChip(colors = ChipDefaults.secondaryChipColors()) } }, + loadingContent = { + items(count = 2) { + PlaceholderChip( + colors = ChipDefaults.secondaryChipColors(), + placeholderState = placeholderState, + secondaryLabel = false, + ) + } + }, mediaContent = { mediaUiModel -> val mediaTitle = mediaUiModel.title ?: defaultMediaTitle Chip( diff --git a/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/playlists/PlaylistsScreen.kt b/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/playlists/PlaylistsScreen.kt index 4a139e1a57..e912f2c67e 100644 --- a/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/playlists/PlaylistsScreen.kt +++ b/media/ui/src/main/java/com/google/android/horologist/media/ui/screens/playlists/PlaylistsScreen.kt @@ -29,6 +29,7 @@ import com.google.android.horologist.composables.Section import com.google.android.horologist.composables.SectionedList import com.google.android.horologist.compose.layout.ScalingLazyColumnState import com.google.android.horologist.compose.layout.ScreenScaffold +import com.google.android.horologist.compose.layout.rememberActivePlaceholderState import com.google.android.horologist.compose.material.Chip import com.google.android.horologist.compose.material.Title import com.google.android.horologist.images.coil.CoilPaintable @@ -59,6 +60,10 @@ public fun PlaylistsScreen( playlistContent: @Composable (playlist: T) -> Unit, modifier: Modifier = Modifier, ) { + // TODO This should be folded into SectionedList + val placeholderState = + rememberActivePlaceholderState { playlistsScreenState !is PlaylistsScreenState.Loading } + ScreenScaffold(scrollState = columnState) { SectionedList( modifier = modifier, @@ -85,7 +90,11 @@ public fun PlaylistsScreen( loading(count = 4) { Column { - PlaceholderChip(colors = ChipDefaults.secondaryChipColors()) + PlaceholderChip( + colors = ChipDefaults.secondaryChipColors(), + placeholderState = placeholderState, + secondaryLabel = false, + ) } } } diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 5ce364639f..7c3aa6136f 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -77,6 +77,7 @@ android { androidx.compose.ui.ExperimentalComposeUiApi androidx.wear.compose.material.ExperimentalWearMaterialApi com.google.android.horologist.annotations.ExperimentalHorologistApi + androidx.compose.foundation.ExperimentalFoundationApi kotlin.RequiresOptIn kotlinx.coroutines.ExperimentalCoroutinesApi """.trim().split("\\s+".toRegex()).map { @@ -152,6 +153,8 @@ dependencies { implementation(libs.compose.ui.toolingpreview) implementation(libs.androidx.wear.tooling.preview) + implementation(libs.kotlinx.serialization.core) + debugImplementation(libs.compose.ui.tooling) debugImplementation(projects.composeTools) debugImplementation(libs.androidx.wear.tiles.tooling.preview) diff --git a/sample/src/main/java/com/google/android/horologist/paging/PagingScreen.kt b/sample/src/main/java/com/google/android/horologist/paging/PagingScreen.kt index 012b689af7..7e2f7a936b 100644 --- a/sample/src/main/java/com/google/android/horologist/paging/PagingScreen.kt +++ b/sample/src/main/java/com/google/android/horologist/paging/PagingScreen.kt @@ -38,14 +38,15 @@ import androidx.paging.PagingState import androidx.paging.compose.collectAsLazyPagingItems import androidx.wear.compose.material.CardDefaults import androidx.wear.compose.material.PlaceholderDefaults +import androidx.wear.compose.material.PlaceholderState import androidx.wear.compose.material.Text import androidx.wear.compose.material.TitleCard import androidx.wear.compose.material.placeholder import androidx.wear.compose.material.placeholderShimmer -import androidx.wear.compose.material.rememberPlaceholderState import androidx.wear.compose.ui.tooling.preview.WearPreviewSquare import com.google.android.horologist.compose.layout.ScalingLazyColumn import com.google.android.horologist.compose.layout.ScalingLazyColumnState +import com.google.android.horologist.compose.layout.rememberActivePlaceholderState import com.google.android.horologist.compose.paging.items import com.google.android.horologist.sample.R import kotlinx.coroutines.delay @@ -78,6 +79,7 @@ fun PagingScreen( columnState = columnState, modifier = modifier, ) { + // TODO This should be folded into com.google.android.horologist.compose.paging.items if (lazyPagingItems.loadState.refresh == LoadState.Loading) { items(10) { PagingItemCard(item = null) @@ -98,35 +100,32 @@ fun PagingScreen( private fun PagingItemCard( item: PagingItem?, modifier: Modifier = Modifier, + placeholderState: PlaceholderState = rememberActivePlaceholderState { item != null }, onClick: () -> Unit = {}, ) { - // Workaround for https://issuetracker.google.com/issues/260343754 - val chipPlaceholderState = - if (item != null) rememberPlaceholderState { true } else rememberPlaceholderState { false } - TitleCard( modifier = modifier .fillMaxWidth() - .placeholderShimmer(chipPlaceholderState), + .placeholderShimmer(placeholderState), enabled = item != null, onClick = onClick, title = { Text( modifier = Modifier - .fillMaxWidth(if (chipPlaceholderState.isShowContent) 1f else 0.5f) - .placeholder(chipPlaceholderState), + .fillMaxWidth(if (placeholderState.isShowContent) 1f else 0.5f) + .placeholder(placeholderState), text = item?.toString().orEmpty(), ) }, backgroundPainter = PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush( - placeholderState = chipPlaceholderState, + placeholderState = placeholderState, painter = CardDefaults.cardBackgroundPainter(), ), ) { Text( modifier = Modifier .fillMaxWidth() - .placeholder(chipPlaceholderState), + .placeholder(placeholderState), text = if (item != null) { stringResource(R.string.lorem_ipsum) } else { @@ -136,12 +135,6 @@ private fun PagingItemCard( overflow = TextOverflow.Ellipsis, ) } - - if (!chipPlaceholderState.isShowContent) { - LaunchedEffect(chipPlaceholderState) { - chipPlaceholderState.startPlaceholderAnimation() - } - } } private class MyBackend {