Skip to content

Commit

Permalink
feat: add an easter egg - heart animation
Browse files Browse the repository at this point in the history
  • Loading branch information
aslansari committed May 17, 2024
1 parent aed6d7c commit 367f675
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
package com.aslansari.spiritvisor.cocktail.component

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateOffsetAsState
import androidx.compose.animation.core.animateSizeAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.aslansari.spiritvisor.theme.icon.HeartSharp
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.map

@Composable
fun CreditText(modifier: Modifier = Modifier) {
fun CreditText(
modifier: Modifier = Modifier,
onLoveSurge: () -> Unit = {},
) {
Row(
modifier = modifier.padding(12.dp),
verticalAlignment = Alignment.CenterVertically,
Expand All @@ -41,12 +48,44 @@ fun CreditText(modifier: Modifier = Modifier) {
onClick = { uriHandler.openUri("https://bento.me/aslansari") },
interactionSource = remember { MutableInteractionSource() },
indication = null,
) ,
),
text = creditText,
style = MaterialTheme.typography.body2.copy(color = Color(0xFF697077))
)
Spacer(Modifier.size(2.dp))
var anim by remember { mutableStateOf(false) }
LaunchedEffect(anim) {
delay(200)
anim = false
}
val heartIconSize by animateDpAsState(targetValue = if (anim) 48.dp else 16.dp)
val heardIconOffset by animateDpAsState(targetValue = if (anim) 0.dp.unaryMinus() else 0.dp)

val lotsOfLoveCounter = remember { mutableStateOf(0) }
LaunchedEffect(Unit) {
snapshotFlow { lotsOfLoveCounter.value }
.map {
if (it > 3) { onLoveSurge() }
it
}
.debounce(1000)
.collect {
lotsOfLoveCounter.value = 0
}
}

Icon(
modifier = Modifier
.offset(y = heardIconOffset)
.size(heartIconSize)
.clickable(
onClick = {
anim = true
lotsOfLoveCounter.value++
},
interactionSource = remember { MutableInteractionSource() },
indication = null,
),
imageVector = Icons.HeartSharp,
contentDescription = null,
tint = Color(0xFFDA1E28)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,27 @@

package com.aslansari.spiritvisor.home

import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.zIndex
import androidx.lifecycle.viewmodel.compose.viewModel
import com.aslansari.spiritvisor.cocktail.component.CreditText
import com.aslansari.spiritvisor.theme.icon.HeartSharp
import kotlinx.coroutines.delay

@Composable
internal fun HomeRoute(
Expand Down Expand Up @@ -53,6 +55,8 @@ internal fun HomeScreen(
}
val windowSizeClass = calculateWindowSizeClass()
Box(modifier = modifier.fillMaxSize()) {
var showLove by remember { mutableStateOf(false) }
HeartAnimation(showLove = showLove) { showLove = false }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
Expand Down Expand Up @@ -82,7 +86,10 @@ internal fun HomeScreen(
}
}
}
CreditText(modifier = Modifier.align(Alignment.BottomCenter))
CreditText(
modifier = Modifier.align(Alignment.BottomCenter),
onLoveSurge = { showLove = true }
)
}
}

Expand All @@ -105,3 +112,29 @@ private fun RowScope.FlavorCategoryButton(
)
}
}

@Composable
internal fun BoxScope.HeartAnimation(
modifier: Modifier = Modifier,
showLove: Boolean = false,
onFinished: () -> Unit = {},
) {
val anim by rememberUpdatedState(showLove)
LaunchedEffect(anim) {
delay(1000)
onFinished()
}
val heartIconSize by animateDpAsState(targetValue = if (anim) 400.dp else 32.dp, animationSpec = tween(800))
val animateAlpha by animateFloatAsState(targetValue = if (anim) 1f else 0f, animationSpec = tween(600))
if (anim) {
Icon(
modifier = modifier.zIndex(1f)
.align(Alignment.Center)
.alpha(animateAlpha)
.size(heartIconSize),
imageVector = Icons.HeartSharp,
contentDescription = null,
tint = Color(0xFFDA1E28)
)
}
}

0 comments on commit 367f675

Please sign in to comment.