From eb1f62d90f4c491d838d783da52670826c5f7521 Mon Sep 17 00:00:00 2001 From: DatLag Date: Fri, 26 Apr 2024 16:47:34 +0200 Subject: [PATCH] make sure the favorite information is available --- .../aniflow/anilist/CharacterStateMachine.kt | 6 +++ .../aniflow/anilist/MediumStateMachine.kt | 7 +++ .../screen/medium/MediumComponent.kt | 2 + .../navigation/screen/medium/MediumScreen.kt | 1 + .../screen/medium/MediumScreenComponent.kt | 2 +- .../medium/component/CollapsingToolbar.kt | 46 ++++++++++++------- .../dialog/character/CharacterDialog.kt | 33 +++++++------ 7 files changed, 66 insertions(+), 31 deletions(-) diff --git a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/CharacterStateMachine.kt b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/CharacterStateMachine.kt index 53d1c95..498557e 100644 --- a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/CharacterStateMachine.kt +++ b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/CharacterStateMachine.kt @@ -82,6 +82,12 @@ class CharacterStateMachine( } sealed interface State { + val isLoading: Boolean + get() = this is Loading + + val isSuccess: Boolean + get() = this is Success + data class Loading(internal val query: CharacterQuery) : State { constructor(id: Int) : this( query = CharacterQuery( diff --git a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/MediumStateMachine.kt b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/MediumStateMachine.kt index f103148..6864a0c 100644 --- a/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/MediumStateMachine.kt +++ b/anilist/src/commonMain/kotlin/dev/datlag/aniflow/anilist/MediumStateMachine.kt @@ -80,6 +80,13 @@ class MediumStateMachine( } sealed interface State { + + val isLoading: Boolean + get() = this is Loading + + val isSuccess: Boolean + get() = this is Success + data class Loading( internal val query: MediumQuery ) : State { diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt index c38d16e..3b8b7b3 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumComponent.kt @@ -2,6 +2,7 @@ package dev.datlag.aniflow.ui.navigation.screen.medium import com.arkivanov.decompose.router.slot.ChildSlot import com.arkivanov.decompose.value.Value +import dev.datlag.aniflow.anilist.MediumStateMachine import dev.datlag.aniflow.anilist.model.Character import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.anilist.type.MediaFormat @@ -14,6 +15,7 @@ import kotlinx.coroutines.flow.StateFlow interface MediumComponent : ContentHolderComponent { val initialMedium: Medium + val mediumState: StateFlow val bannerImage: StateFlow val coverImage: StateFlow val title: StateFlow diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt index edad900..79b867b 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreen.kt @@ -111,6 +111,7 @@ fun MediumScreen(component: MediumComponent) { CollapsingToolbar( state = appBarState, scrollBehavior = scrollState, + mediumStateFlow = component.mediumState, bannerImageFlow = component.bannerImage, coverImage = coverImage, titleFlow = component.title, diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt index 03fadb1..653139e 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/MediumScreenComponent.kt @@ -58,7 +58,7 @@ class MediumScreenComponent( crashlytics = di.nullableFirebaseInstance()?.crashlytics, id = initialMedium.id ) - private val mediumState = mediumStateMachine.state.flowOn( + override val mediumState = mediumStateMachine.state.flowOn( context = ioDispatcher() ).stateIn( scope = ioScope(), diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt index dcad8da..303d3ca 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/component/CollapsingToolbar.kt @@ -1,5 +1,8 @@ package dev.datlag.aniflow.ui.navigation.screen.medium.component +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -26,6 +29,7 @@ import dev.chrisbanes.haze.hazeChild import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.HazeMaterials import dev.datlag.aniflow.LocalHaze +import dev.datlag.aniflow.anilist.MediumStateMachine import dev.datlag.aniflow.anilist.model.Medium import dev.datlag.aniflow.common.notPreferred import dev.datlag.aniflow.common.preferred @@ -39,6 +43,7 @@ import kotlin.math.min fun CollapsingToolbar( state: TopAppBarState, scrollBehavior: TopAppBarScrollBehavior, + mediumStateFlow: StateFlow, bannerImageFlow: StateFlow, coverImage: Medium.CoverImage, titleFlow: StateFlow, @@ -141,30 +146,37 @@ fun CollapsingToolbar( } }, actions = { + val mediumState by mediumStateFlow.collectAsStateWithLifecycle() val isFavoriteBlocked by isFavoriteBlockedFlow.collectAsStateWithLifecycle() val isFavorite by isFavoriteFlow.collectAsStateWithLifecycle() var favoriteChanged by remember(isFavorite) { mutableStateOf(null) } - IconButton( - modifier = if (isCollapsed) { - Modifier - } else { - Modifier.background(MaterialTheme.colorScheme.surface.copy(alpha = 0.75F), CircleShape) - }, - onClick = { - favoriteChanged = !(favoriteChanged ?: isFavorite) - onToggleFavorite() - }, - enabled = !isFavoriteBlocked + AnimatedVisibility( + visible = mediumState.isSuccess, + enter = fadeIn(), + exit = fadeOut() ) { - Icon( - imageVector = if (favoriteChanged ?: isFavorite) { - Icons.Default.Favorite + IconButton( + modifier = if (isCollapsed) { + Modifier } else { - Icons.Default.FavoriteBorder + Modifier.background(MaterialTheme.colorScheme.surface.copy(alpha = 0.75F), CircleShape) }, - contentDescription = null - ) + onClick = { + favoriteChanged = !(favoriteChanged ?: isFavorite) + onToggleFavorite() + }, + enabled = !isFavoriteBlocked + ) { + Icon( + imageVector = if (favoriteChanged ?: isFavorite) { + Icons.Default.Favorite + } else { + Icons.Default.FavoriteBorder + }, + contentDescription = null + ) + } } }, scrollBehavior = scrollBehavior, diff --git a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialog.kt b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialog.kt index 0e82746..8ec3844 100644 --- a/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialog.kt +++ b/composeApp/src/commonMain/kotlin/dev/datlag/aniflow/ui/navigation/screen/medium/dialog/character/CharacterDialog.kt @@ -59,6 +59,7 @@ fun CharacterDialog(component: CharacterComponent) { contentAlignment = Alignment.Center ) { val image by component.image.collectAsStateWithLifecycle() + val state by component.state.collectAsStateWithLifecycle() val isFavoriteBlocked by component.isFavoriteBlocked.collectAsStateWithLifecycle() val isFavorite by component.isFavorite.collectAsStateWithLifecycle() var favoriteChanged by remember(isFavorite) { mutableStateOf(null) } @@ -95,22 +96,28 @@ fun CharacterDialog(component: CharacterComponent) { contentDescription = component.initialChar.preferredName() ) - IconButton( + this@ModalBottomSheet.AnimatedVisibility( modifier = Modifier.align(Alignment.CenterEnd), - onClick = { - favoriteChanged = !(favoriteChanged ?: isFavorite) - component.toggleFavorite() - }, - enabled = !isFavoriteBlocked + visible = state.isSuccess, + enter = fadeIn(), + exit = fadeOut() ) { - Icon( - imageVector = if (favoriteChanged ?: isFavorite) { - Icons.Default.Favorite - } else { - Icons.Default.FavoriteBorder + IconButton( + onClick = { + favoriteChanged = !(favoriteChanged ?: isFavorite) + component.toggleFavorite() }, - contentDescription = null, - ) + enabled = !isFavoriteBlocked + ) { + Icon( + imageVector = if (favoriteChanged ?: isFavorite) { + Icons.Default.Favorite + } else { + Icons.Default.FavoriteBorder + }, + contentDescription = null, + ) + } } }