Skip to content

Commit

Permalink
added animation when achievement images are clicked
Browse files Browse the repository at this point in the history
  • Loading branch information
Aniokrait committed Sep 16, 2023
1 parent 0164f74 commit 737f67b
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package io.github.droidkaigi.confsched2023.achievements

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
Expand All @@ -16,6 +18,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
Expand All @@ -31,8 +34,11 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import io.github.droidkaigi.confsched2023.achievements.ClickedAchievementState.Clicked
import io.github.droidkaigi.confsched2023.achievements.component.GetAchievementAnimation
import io.github.droidkaigi.confsched2023.achievements.section.AchievementList
import io.github.droidkaigi.confsched2023.achievements.section.AchievementListUiState
import io.github.droidkaigi.confsched2023.model.Achievement
import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect

const val achievementsScreenRoute = "achievements"
Expand Down Expand Up @@ -83,51 +89,80 @@ fun AchievementsScreen(
snackbarHostState = snackbarHostState,
contentPadding = contentPadding,
onReset = viewModel::onReset,
showAnimation = { achievement -> viewModel.onClickAchievement(achievement) },
finishAnimation = viewModel::onFinishAnimation,
onDisplayedInitialDialog = viewModel::onDisplayedInitialDialog,
)
}

data class AchievementsScreenUiState(
val achievementListUiState: AchievementListUiState,
val isShowInitialDialog: Boolean,
val clickedAchievement: ClickedAchievementState,
)

sealed interface ClickedAchievementState {
data class Clicked(
val achievement: Achievement,
val animationRawId: Int,
) : ClickedAchievementState
data object NotClicked : ClickedAchievementState
}

@Composable
private fun AchievementsScreen(
uiState: AchievementsScreenUiState,
snackbarHostState: SnackbarHostState,
contentPadding: PaddingValues,
onReset: () -> Unit,
showAnimation: (Achievement) -> Unit,
finishAnimation: () -> Unit,
onDisplayedInitialDialog: () -> Unit,
) {
val layoutDirection = LocalLayoutDirection.current
Scaffold(
modifier = Modifier.testTag(AchievementsScreenTestTag),
snackbarHost = { SnackbarHost(snackbarHostState) },
contentWindowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
bottom = contentPadding.calculateBottomPadding(),
),
content = { innerPadding ->
if (uiState.isShowInitialDialog) {
AchievementScreenDialog(
onDismissRequest = onDisplayedInitialDialog,
Box {
Scaffold(
modifier = Modifier.testTag(AchievementsScreenTestTag),
snackbarHost = { SnackbarHost(snackbarHostState) },
contentWindowInsets = WindowInsets(
left = contentPadding.calculateLeftPadding(layoutDirection),
top = contentPadding.calculateTopPadding(),
right = contentPadding.calculateRightPadding(layoutDirection),
bottom = contentPadding.calculateBottomPadding(),
),
content = { innerPadding ->
if (uiState.isShowInitialDialog) {
AchievementScreenDialog(
onDismissRequest = onDisplayedInitialDialog,
)
}
AchievementList(
uiState = uiState.achievementListUiState,
contentPadding = innerPadding,
onReset = onReset,
showAnimation = showAnimation,
modifier = Modifier.padding(
top = innerPadding.calculateTopPadding(),
start = innerPadding.calculateStartPadding(layoutDirection),
end = innerPadding.calculateEndPadding(layoutDirection),
),
)
},
)
if (uiState.clickedAchievement is Clicked) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background.copy(alpha = 0.6F),
) {
GetAchievementAnimation(
animationRawId = uiState.clickedAchievement.animationRawId,
onFinishAnimation = {
finishAnimation()
},
)
}
AchievementList(
uiState = uiState.achievementListUiState,
contentPadding = innerPadding,
onReset = onReset,
modifier = Modifier.padding(
top = innerPadding.calculateTopPadding(),
start = innerPadding.calculateStartPadding(layoutDirection),
end = innerPadding.calculateEndPadding(layoutDirection),
),
)
},
)
}
}
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import io.github.droidkaigi.confsched2023.ui.handleErrorAndRetry
import kotlinx.collections.immutable.PersistentSet
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
Expand Down Expand Up @@ -120,13 +121,17 @@ class AchievementsScreenViewModel @Inject constructor(
)
}

private val clickedAchievement = MutableStateFlow<ClickedAchievementState>(ClickedAchievementState.NotClicked)

val uiState = buildUiState(
achievementAnimationListState,
isInitialDialogDisplayFlow,
) { achievementListUiState, isDisplayedInitialDialog ->
clickedAchievement,
) { achievementListUiState, isDisplayedInitialDialog, clickedAchievement ->
AchievementsScreenUiState(
achievementListUiState = achievementListUiState,
isShowInitialDialog = isDisplayedInitialDialog?.not() ?: false,
clickedAchievement = clickedAchievement,
)
}

Expand All @@ -141,4 +146,22 @@ class AchievementsScreenViewModel @Inject constructor(
achievementRepository.displayedInitialDialog()
}
}

fun onClickAchievement(clickedAchievement: Achievement) {
val animationRawId: Int = when (clickedAchievement) {
Achievement.ArcticFox -> R.raw.achievement_a_lottie
Achievement.Bumblebee -> R.raw.achievement_b_lottie
Achievement.Chipmunk -> R.raw.achievement_c_lottie
Achievement.Dolphin -> R.raw.achievement_d_lottie
Achievement.ElectricEel -> R.raw.achievement_e_lottie
}
this.clickedAchievement.value = ClickedAchievementState.Clicked(
achievement = clickedAchievement,
animationRawId = animationRawId,
)
}

fun onFinishAnimation() {
this.clickedAchievement.value = ClickedAchievementState.NotClicked
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec.RawRes
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import io.github.droidkaigi.confsched2023.achievements.component.GetAchievementAnimation
import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect

data class AnimationScreenUiState(
Expand Down Expand Up @@ -59,19 +56,12 @@ fun AchievementAnimationScreen(
.fillMaxSize(),
) {
if (uiState.rawId != null) {
val lottieComposition by rememberLottieComposition(RawRes(uiState.rawId))
val progress by animateLottieCompositionAsState(
composition = lottieComposition,
isPlaying = true,
restartOnPlay = true,
)
if (progress == 1f) {
onReachAnimationEnd()
onFinished()
}
LottieAnimation(
composition = lottieComposition,
progress = { progress },
GetAchievementAnimation(
animationRawId = uiState.rawId,
onFinishAnimation = {
onReachAnimationEnd()
onFinished()
},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
package io.github.droidkaigi.confsched2023.achievements.component

import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import io.github.droidkaigi.confsched2023.model.Achievement
import io.github.droidkaigi.confsched2023.model.AchievementAnimation

@Composable
fun AchievementImage(
achievementAnimation: AchievementAnimation,
modifier: Modifier = Modifier,
showAnimation: (Achievement) -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
Image(
painter = painterResource(id = achievementAnimation.getDrawableResId()),
contentDescription = achievementAnimation.contentDescription,
modifier = modifier
.padding(horizontal = 21.dp),
.padding(horizontal = 21.dp)
.clickable(
interactionSource = interactionSource,
indication = null,
) {
showAnimation(achievementAnimation.achievement)
},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.github.droidkaigi.confsched2023.achievements.component

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec.RawRes
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition

@Composable
fun GetAchievementAnimation(
animationRawId: Int,
onFinishAnimation: () -> Unit,
) {
val lottieComposition by rememberLottieComposition(RawRes(animationRawId))
val progress by animateLottieCompositionAsState(
composition = lottieComposition,
isPlaying = true,
restartOnPlay = true,
)
if (progress == 1f) {
onFinishAnimation()
}
LottieAnimation(
composition = lottieComposition,
progress = { progress },
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.dp
import io.github.droidkaigi.confsched2023.achievements.component.AchievementImage
import io.github.droidkaigi.confsched2023.achievements.component.AchievementsDetail
import io.github.droidkaigi.confsched2023.model.Achievement
import io.github.droidkaigi.confsched2023.model.AchievementAnimation
import kotlinx.collections.immutable.ImmutableList

Expand All @@ -37,6 +38,7 @@ fun AchievementList(
uiState: AchievementListUiState,
contentPadding: PaddingValues,
onReset: () -> Unit,
showAnimation: (Achievement) -> Unit,
modifier: Modifier = Modifier,
) {
val layoutDirection = LocalLayoutDirection.current
Expand Down Expand Up @@ -77,6 +79,7 @@ fun AchievementList(
) { achievementAnimation ->
AchievementImage(
achievementAnimation = achievementAnimation,
showAnimation = showAnimation,
)
}
if (uiState.isResetButtonEnabled) {
Expand Down

0 comments on commit 737f67b

Please sign in to comment.