diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/Animations.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/Animations.kt index 19bbfcba..de8c97fa 100644 --- a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/Animations.kt +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/Animations.kt @@ -29,42 +29,47 @@ import com.stslex.core.ui.theme.toPx import kotlin.math.roundToInt fun Modifier.shimmerLoadingAnimation( + isShimmerVisible: Boolean = true, widthOfShadowBrush: Int = 500, angleOfAxisY: Float = 270f, durationMillis: Int = 1000, -): Modifier = composed { - val shimmerColors = with(MaterialTheme.colorScheme.surfaceVariant) { - listOf( - copy(alpha = 0.3f), - copy(alpha = 0.5f), - copy(alpha = 0.7f), - copy(alpha = 0.5f), - copy(alpha = 0.3f), - ) - } +): Modifier = if (isShimmerVisible) { + composed { + val shimmerColors = with(MaterialTheme.colorScheme.surfaceVariant) { + listOf( + copy(alpha = 0.3f), + copy(alpha = 0.5f), + copy(alpha = 0.7f), + copy(alpha = 0.5f), + copy(alpha = 0.3f), + ) + } - val transition = rememberInfiniteTransition(label = "shimmer loading animation transition") + val transition = rememberInfiniteTransition(label = "shimmer loading animation transition") - val translateAnimation = transition.animateFloat( - initialValue = 0f, - targetValue = (durationMillis + widthOfShadowBrush).toFloat(), - animationSpec = infiniteRepeatable( - animation = tween( - durationMillis = durationMillis, - easing = LinearEasing, + val translateAnimation = transition.animateFloat( + initialValue = 0f, + targetValue = (durationMillis + widthOfShadowBrush).toFloat(), + animationSpec = infiniteRepeatable( + animation = tween( + durationMillis = durationMillis, + easing = LinearEasing, + ), + repeatMode = RepeatMode.Restart, ), - repeatMode = RepeatMode.Restart, - ), - label = "Shimmer loading animation", - ) + label = "Shimmer loading animation", + ) - background( - brush = Brush.linearGradient( - colors = shimmerColors, - start = Offset(x = translateAnimation.value - widthOfShadowBrush, y = 0.0f), - end = Offset(x = translateAnimation.value, y = angleOfAxisY), - ), - ) + background( + brush = Brush.linearGradient( + colors = shimmerColors, + start = Offset(x = translateAnimation.value - widthOfShadowBrush, y = 0.0f), + end = Offset(x = translateAnimation.value, y = angleOfAxisY), + ), + ) + } +} else { + this } @Composable diff --git a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenContent.kt b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenContent.kt index 22b9d157..171203ad 100644 --- a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenContent.kt +++ b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenContent.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.stslex.core.ui.base.DotsPrintAnimation import com.stslex.core.ui.base.paging.PagingState +import com.stslex.core.ui.base.shimmerLoadingAnimation import com.stslex.core.ui.theme.AppDimension import com.stslex.feature.match.ui.model.MatchUiModel import com.stslex.feature.match.ui.store.MatchScreenState @@ -54,9 +55,6 @@ internal fun MatchScreenContent( } } - Column { - - } Box( modifier = modifier.fillMaxSize(), ) { @@ -64,9 +62,6 @@ internal fun MatchScreenContent( modifier = Modifier.fillMaxSize(), state = lazyListState, ) { - item { - Text("total count: ${state.total}, result size: ${state.result.size}") - } items( count = state.result.size, key = { index -> @@ -85,6 +80,9 @@ internal fun MatchScreenContent( if (screen is MatchScreenState.Content.Append) { item { DotsPrintAnimation( + modifier = Modifier + .fillMaxWidth() + .padding(AppDimension.Padding.medium), dotsCount = 3, ) } @@ -99,27 +97,33 @@ internal fun MatchScreenContent( } @Composable -private fun MatchItem( +internal fun MatchItem( item: MatchUiModel, onItemClicked: (matchUuid: String) -> Unit, modifier: Modifier = Modifier, + isShimmer: Boolean = false, ) { ElevatedCard( - modifier = modifier.fillMaxWidth().padding(AppDimension.Padding.medium), + modifier = modifier + .fillMaxWidth() + .padding(AppDimension.Padding.medium) + .shimmerLoadingAnimation(isShimmer), onClick = { onItemClicked(item.uuid) }, ) { Column { Text( text = item.title, modifier = Modifier - .padding(AppDimension.Padding.medium), + .padding(AppDimension.Padding.medium) + .shimmerLoadingAnimation(isShimmer), style = MaterialTheme.typography.titleLarge, ) Spacer(modifier = Modifier.height(AppDimension.Padding.medium)) Text( text = item.title, modifier = Modifier - .padding(AppDimension.Padding.medium), + .padding(AppDimension.Padding.medium) + .shimmerLoadingAnimation(isShimmer), style = MaterialTheme.typography.bodyMedium, ) } diff --git a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenShimmer.kt b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenShimmer.kt index bcd711ef..1dc6c250 100644 --- a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenShimmer.kt +++ b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/components/MatchScreenShimmer.kt @@ -2,10 +2,12 @@ package com.stslex.feature.match.ui.components import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import com.stslex.feature.match.ui.model.MatchUiModel @Composable internal fun MatchScreenShimmer( @@ -15,6 +17,19 @@ internal fun MatchScreenShimmer( modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { + items( + count = 15 + ) { + MatchItem( + isShimmer = true, + onItemClicked = { }, + item = MatchUiModel.EMPTY + ) + } + } Text(text = "Shimmer") } } \ No newline at end of file diff --git a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/model/MatchUiModel.kt b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/model/MatchUiModel.kt index 6bbda61a..8784cf4f 100644 --- a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/model/MatchUiModel.kt +++ b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/model/MatchUiModel.kt @@ -3,6 +3,7 @@ package com.stslex.feature.match.ui.model import androidx.compose.runtime.Stable import com.stslex.core.ui.base.paging.PagingItem import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf @Stable data class MatchUiModel( @@ -15,4 +16,20 @@ data class MatchUiModel( val expiresAtDays: Int, val expiresAtHours: Int, val expiresAtMinutes: Int, -) : PagingItem +) : PagingItem { + + companion object { + + val EMPTY = MatchUiModel( + uuid = "", + title = "", + description = "", + status = MatchUiStatusModel.PENDING, + participants = persistentListOf(), + isCreator = false, + expiresAtDays = 0, + expiresAtHours = 0, + expiresAtMinutes = 0, + ) + } +} diff --git a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/store/MatchStore.kt b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/store/MatchStore.kt index c2f7bd5c..8e27ccbd 100644 --- a/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/store/MatchStore.kt +++ b/feature/match/src/commonMain/kotlin/com/stslex/feature/match/ui/store/MatchStore.kt @@ -4,7 +4,6 @@ import com.stslex.core.core.AppDispatcher import com.stslex.core.core.paging.PagingCoreData.Companion.DEFAULT_PAGE import com.stslex.core.database.store.UserStore import com.stslex.core.ui.base.mapToAppError -import com.stslex.core.ui.base.paging.PagingState import com.stslex.core.ui.base.paging.pagingMap import com.stslex.core.ui.mvi.BaseStore import com.stslex.core.ui.mvi.Store.Event.Snackbar @@ -44,16 +43,18 @@ class MatchStore( } private fun actionInit(action: Action.Init) { - val uuid = action.args.uuid ?: userStore.uuid updateState { currentState -> currentState.copy( isSelf = action.args.isSelf, - uuid = uuid, - screen = MatchScreenState.Shimmer, - pagingState = PagingState.default() + uuid = action.args.uuid ?: userStore.uuid, + pagingState = currentState.pagingState.copy( + hasMore = true + ) ) } - loadItems(isForceLoad = true) + if (state.value.pagingState.result.isEmpty()) { + loadItems(isForceLoad = true) + } } private fun actionLoadMore() {