diff --git a/.idea/misc.xml b/.idea/misc.xml index 0fc7958..46cbcc9 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,7 +6,9 @@ + + diff --git a/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt b/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt index c2a990e..4796abf 100644 --- a/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt +++ b/app/src/main/java/dev/baseio/composeplayground/MainActivity.kt @@ -20,6 +20,7 @@ import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.HorizontalPagerIndicator import com.google.accompanist.pager.rememberPagerState import dev.baseio.composeplayground.ui.animations.* +import dev.baseio.composeplayground.ui.animations.adityabhawsar.* import dev.baseio.composeplayground.ui.animations.anmolverma.BellAnimation import dev.baseio.composeplayground.ui.animations.anmolverma.ShootingStarsAnimation import dev.baseio.composeplayground.ui.animations.anmolverma.planetarysystem.PlanetarySystem @@ -64,7 +65,7 @@ class MainActivity : ComponentActivity() { ) { HorizontalPager( modifier = Modifier.fillMaxSize(), - count = 15, state = pagerState, + count = 21, state = pagerState, ) { page -> // Our page content when (page) { @@ -95,9 +96,27 @@ class MainActivity : ComponentActivity() { 14 -> { ShootingStarsAnimation() } + 15 -> { + BreatheAnimation() + } + 16 -> { + MicAnimation() + } + 17 -> { + CircleSquareAnimation() + } 0 -> { NetflixIntroAnimation() } + 18 -> { + FiSplashAnimation() + } + 20 -> { + BreatheRotatingAnimation() + } + 19 -> { + AlarmSliderAnimation() + } 11 -> { Box(modifier = Modifier.fillMaxSize()) { Github404(Modifier) diff --git a/app/src/main/java/dev/baseio/composeplayground/contributors/AdityaBhawsar.kt b/app/src/main/java/dev/baseio/composeplayground/contributors/AdityaBhawsar.kt new file mode 100644 index 0000000..234ac13 --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/contributors/AdityaBhawsar.kt @@ -0,0 +1,35 @@ +package dev.baseio.composeplayground.contributors + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import dev.baseio.composeplayground.R +import dev.baseio.composeplayground.ui.theme.Typography + +const val adityaImageUrl = "https://ca.slack-edge.com/T02TLUWLZ-U02CDNRLMSA-4aa8ad906c93-72" + +@Composable +fun AdityaBhawsar(modifier: Modifier = Modifier) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier.padding(4.dp)) { + CoilImageBox(Modifier.size(64.dp), adityaImageUrl) + Column(verticalArrangement = Arrangement.Center, modifier = Modifier.padding(8.dp)) { + Text( + text = stringResource(id = R.string.emp_mmh0329), + style = Typography.h6.copy(MaterialTheme.colors.onSurface), + ) + Text( + text = stringResource(id = R.string.emp_mmh0329_email), + style = Typography.subtitle1.copy(MaterialTheme.colors.onSurface), + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/AlarmSliderAnimation.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/AlarmSliderAnimation.kt new file mode 100644 index 0000000..de32900 --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/AlarmSliderAnimation.kt @@ -0,0 +1,501 @@ +package dev.baseio.composeplayground.ui.animations.adityabhawsar + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.baseio.composeplayground.R +import dev.baseio.composeplayground.contributors.AdityaBhawsar +import kotlinx.coroutines.* +import kotlin.math.roundToInt + +@Composable +fun AlarmSliderAnimation() { + + Box( + modifier = Modifier + .fillMaxSize() + .background(Color(0xff1f231f)) + ) { + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + .align(Alignment.Center) + ) + { + AlarmSlider() + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.BottomEnd) + ) { + AdityaBhawsar( + Modifier + .align(Alignment.Center) + .background(Color.LightGray) + ) + } + } + +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun AlarmSlider() { + + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .height(80.dp) + ) { + + val boxAlpha = remember { Animatable(0f) } + val leftWeight = remember { Animatable(0.45f) } + val rightWeight = remember { Animatable(0.45f) } + val clockRotation = remember { Animatable(0f) } + + val swipeableState = rememberSwipeableState(0.5f) { state -> true } + + val swipeCenter: Float = (constraints.maxWidth / 2).toFloat() - ((constraints.maxHeight * 1.35f) / 2) + val swipeRight: Float = constraints.maxWidth - (constraints.maxHeight * 1.35f) + val swipeLeft = 0f + + LaunchedEffect(swipeableState.offset) { + if(swipeableState.offset.value == swipeCenter) { + boxAlpha.snapTo(0f) + leftWeight.snapTo(0.45f) + rightWeight.snapTo(0.45f) + clockRotation.snapTo(0f) + + runInactiveAnimation( + this, + boxAlpha, + leftWeight, + rightWeight, + clockRotation + ) + } else { + boxAlpha.snapTo(0f) + leftWeight.snapTo(0.45f) + rightWeight.snapTo(0.45f) + clockRotation.snapTo(0f) + } + } + + val anchors = mapOf( + swipeLeft to 0f, + swipeCenter to 0.5f, + swipeRight to 1f + ) + + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(40.dp)) + .background(Color(0xff353a3d)) + .swipeable( + state = swipeableState, + anchors = anchors, + thresholds = { _, _ -> FractionalThreshold(0.7f) }, + orientation = Orientation.Horizontal + ) + ) { + + AnimatedVisibility( + visible = (swipeableState.offset.value == swipeCenter), + enter = fadeIn(), + exit = fadeOut() + ) { + Row(modifier = Modifier + .fillMaxSize() + .align(Alignment.Center)) { + + Box(modifier = Modifier.weight(leftWeight.value)) + Box( + modifier = Modifier + .fillMaxHeight() + .alpha(boxAlpha.value) + .weight(1 - (leftWeight.value + rightWeight.value)) + .padding(8.dp) + .clip(RoundedCornerShape(40.dp)) + .background(Color(0xff626972)) + ) + Box(modifier = Modifier.weight(rightWeight.value)) + } + } + + Text( + modifier = Modifier + .align(Alignment.CenterStart) + .padding(16.dp), + text = "Snooze", + style = TextStyle( + color = Color.White, + fontSize = 18.sp + ) + ) + + Text( + modifier = Modifier + .align(Alignment.CenterEnd) + .padding(16.dp), + text = "Stop", + style = TextStyle( + color = Color.White, + fontSize = 18.sp + ) + ) + + Box( + modifier = Modifier + .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) } + .fillMaxHeight() + .aspectRatio(1.35f, true) + .padding(8.dp) + .clip(RoundedCornerShape(40.dp)) + .background(Color(0xffd6e8fb)) + ) { + Icon( + painter = painterResource(id = R.drawable.ic_alarm), + modifier = Modifier + .rotate(clockRotation.value) + .alpha(if (swipeableState.offset.value == swipeCenter) 1f else 0f) + .size(24.dp) + .align(Alignment.Center), + contentDescription = "", + tint = Color.Black + ) + + Icon( + painter = painterResource(id = R.drawable.ic_alarm), + modifier = Modifier + .rotate(rotationClock( + swipeableState.offset.value, + swipeCenter, + swipeLeft, + swipeRight + )) + .alpha(alphaClock( + swipeableState.offset.value, + swipeCenter, + swipeLeft, + swipeRight + )) + .size(24.dp) + .align(Alignment.Center), + contentDescription = "", + tint = Color.Black + ) + + Icon( + painter = painterResource(id = R.drawable.ic_check), + modifier = Modifier + .rotate(rotationCheck( + swipeableState.offset.value, + swipeCenter, + swipeLeft, + swipeRight + )) + .scale(scaleCheck( + swipeableState.offset.value, + swipeCenter, + swipeLeft, + swipeRight + )) + .alpha(alphaCheck( + swipeableState.offset.value, + swipeCenter + )) + .size(24.dp) + .align(Alignment.Center), + contentDescription = "", + tint = Color.Black + ) + } + } + } +} + +fun rotationClock( + currentPos: Float, + center: Float, + left: Float, + right: Float +): Float { + when { + currentPos == center -> { + return 0f + } + currentPos > center -> { + // to right + val progressMade = currentPos - center + val total = right - center + + val per = (progressMade/total) * 100 + + return if(per > 25) { + 270f + } else { + (per * 10.8f) + } + } + currentPos < center -> { + //to left + + val progressMade = center - currentPos + val total = center - left + + val per = (progressMade/total) * 100 + + return if(per > 25) { + -270f + } else { + (per * 10.8f)*-1 + } + } + else -> { + return 0f + } + } +} + +fun alphaClock( + currentPos: Float, + center: Float, + left: Float, + right: Float +): Float { + when { + currentPos == center -> { + return 0f + } + currentPos > center -> { + // to right + val progressMade = currentPos - center + val total = right - center + val per = (progressMade/total) * 100 + + return if(per > 25) { + 0f + } else { + 1 - (per * .04f) + } + } + currentPos < center -> { + //to left + val progressMade = center - currentPos + val total = center - left + val per = (progressMade/total) * 100 + + return if(per > 25) { + 0f + } else { + 1 - (per * 0.04f) + } + } + else -> { + return 0f + } + } +} + +fun rotationCheck( + currentPos: Float, + center: Float, + left: Float, + right: Float +): Float { + when { + currentPos == center -> { + return 90f + } + currentPos > center -> { + val progressMade = currentPos - center + val total = right - center + val per = (progressMade/total) * 100 + + return if(per <= 16.5){ + 90f + (per * 10.9f) + } else if(per > 16.5 && per <= 50) { + (270f + (90f * (per - 16.5f)/33.5f)) + } else { + 0f + } + } + currentPos < center -> { + val progressMade = center - currentPos + val total = center - left + val per = (progressMade/total) * 100 + + return if(per <= 16.5){ + 90f + ((per * 10.9f)* -1) + } else if(per > 16.5 && per <= 50) { + (-90f + (270f * ((per - 16.5f)/33.5f)*-1)) + } else { + 0f + } + } + else -> { return 0f} + } +} + +fun alphaCheck( + currentPos: Float, + center: Float, +): Float { + if(currentPos == center){ + return 0f + } + return 1f +} + +fun scaleCheck( + currentPos: Float, + center: Float, + left: Float, + right: Float +): Float { + when { + currentPos == center -> { + return 0.4f + } + currentPos > center -> { + val progressMade = currentPos - center + val total = right - center + val per = (progressMade/total) * 100 + + return if(per <= 25){ + 0.4f + } else if(per > 25 && per <= 50) { + (0.4f + (0.6f * (per - 25)/25)) + } else { + 1f + } + } + currentPos < center -> { + val progressMade = center - currentPos + val total = center - left + val per = (progressMade/total) * 100 + return if(per <= 25){ + 0.4f + } else if(per > 25 && per <= 50) { + (0.4f + (0.6f * (per - 25)/25)) + } else { + 1f + } + } + else -> { return 1f } + } +} + + +fun runInactiveAnimation( + coroutineScope: CoroutineScope, + boxAlpha: Animatable, + leftWeight: Animatable, + rightWeight: Animatable, + clockRotation: Animatable +) { + coroutineScope.launch{ + + boxAlpha.snapTo(1f) + + leftWeight.animateTo( + targetValue = 0.01f, + animationSpec = tween(750, easing = LinearEasing) + ) + + delay(50) + + coroutineScope.launch { + clockRotation.animateTo( + targetValue = 30f, + animationSpec = tween(50, easing = LinearEasing) + ) + + clockRotation.animateTo( + targetValue = -30f, + animationSpec = tween(100, easing = LinearEasing) + ) + + clockRotation.animateTo( + targetValue = 0f, + animationSpec = tween(50, easing = LinearEasing) + ) + } + + boxAlpha.animateTo( + targetValue = 0f, + animationSpec = tween(200, easing = LinearEasing) + ) + + leftWeight.snapTo(0.45f) + boxAlpha.snapTo(1f) + + rightWeight.animateTo( + targetValue = 0.01f, + animationSpec = tween(750, easing = LinearEasing) + ) + + delay(50) + + coroutineScope.launch { + clockRotation.animateTo( + targetValue = 30f, + animationSpec = tween(50, easing = LinearEasing) + ) + + clockRotation.animateTo( + targetValue = -30f, + animationSpec = tween(100, easing = LinearEasing) + ) + + clockRotation.animateTo( + targetValue = 0f, + animationSpec = tween(50, easing = LinearEasing) + ) + } + + boxAlpha.animateTo( + targetValue = 0f, + animationSpec = tween(200, easing = LinearEasing) + ) + + rightWeight.snapTo(0.45f) + boxAlpha.snapTo(1f) + + runInactiveAnimation( + coroutineScope, + boxAlpha, + leftWeight, + rightWeight, + clockRotation + ) + } +} diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/BreatheAnimation.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/BreatheAnimation.kt new file mode 100644 index 0000000..73c4b2d --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/BreatheAnimation.kt @@ -0,0 +1,238 @@ +package dev.baseio.composeplayground.ui.animations.adityabhawsar + +import dev.baseio.composeplayground.contributors.AdityaBhawsar +import androidx.compose.animation.core.* +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@Composable +fun BreatheAnimation(modifier: Modifier = Modifier) { + + Box( + modifier + .fillMaxSize() + .background(Color.Black) + ) { + + Column( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + AnimatedCircles(6) + Spacer(modifier = Modifier.padding(24.dp)) + AnimatedText() + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.BottomCenter) + ) { + AdityaBhawsar( + Modifier + .align(Alignment.Center) + .background(Color.LightGray) + ) + } + } +} + +@Composable +fun AnimatedCircles(numCircles: Int) { + Box(modifier = Modifier.fillMaxWidth()) { + for (circleNumber in 0 until numCircles) { + AnimatedCircle( + modifier = Modifier + .padding(16.dp) + .align(Alignment.Center), + rotationQuota = 360f / numCircles, + circleNumber = circleNumber + ) + } + } +} + +@Composable +fun AnimatedCircle( + modifier: Modifier, + rotationQuota: Float, + circleNumber: Int +) { + + val circleRotation = remember { Animatable(0f) } + val circleScale = remember { Animatable(0.1f) } + + LaunchedEffect(key1 = true) { + runAnimatedCircleScale( + coroutineScope = this, + scaleFactor = circleScale + ) + } + + LaunchedEffect(key1 = true) { + runAnimatedCircleRotation( + coroutineScope = this, + rotationFactor = circleRotation, + rotationTarget = rotationQuota * circleNumber, + ) + } + + Column( + modifier = modifier + .rotate(circleRotation.value) + .scale(circleScale.value), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Canvas( + modifier = Modifier + .size(120.dp) + .alpha(0.3f) + ) { + drawCircle(color = Color.Cyan) + } + Canvas( + modifier = Modifier + .size(125.dp) + .alpha(0f) + ) { + drawRect(color = Color.Red) + } + } +} + +fun runAnimatedCircleRotation( + coroutineScope: CoroutineScope, + rotationFactor: Animatable, + rotationTarget: Float +) { + coroutineScope.launch { + + rotationFactor.animateTo( + targetValue = rotationTarget, + animationSpec = tween(5000, easing = LinearEasing) + ) + + delay(500) + + rotationFactor.animateTo( + targetValue = 0f, + animationSpec = tween(5000, easing = LinearEasing) + ) + + delay(500) + + runAnimatedCircleRotation( + coroutineScope = coroutineScope, + rotationFactor = rotationFactor, + rotationTarget = rotationTarget + ) + } + +} + +fun runAnimatedCircleScale( + coroutineScope: CoroutineScope, + scaleFactor: Animatable +) { + coroutineScope.launch { + + scaleFactor.animateTo( + targetValue = 1f, + animationSpec = tween(5000, easing = LinearEasing) + ) + + delay(500) + + scaleFactor.animateTo( + targetValue = 0.1f, + animationSpec = tween(5000, easing = LinearEasing) + ) + + delay(500) + + runAnimatedCircleScale(coroutineScope = coroutineScope, scaleFactor = scaleFactor) + } +} + +@Composable +fun AnimatedText() { + + val animatedValue = remember { Animatable(1f)} + + LaunchedEffect(key1 = true) { + runAnimationText( + coroutineScope = this, + scaleFactor = animatedValue + ) + } + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Breathe Out", + textAlign = TextAlign.Center, + style = TextStyle(color = Color.LightGray, fontSize = 20.sp), + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.Center) + .alpha(if(animatedValue.value == 0.1f) 0f else animatedValue.value) + ) + Text( + text = "Breathe In", + textAlign = TextAlign.Center, + style = TextStyle(color = Color.LightGray, fontSize = 20.sp), + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.Center) + .alpha(if(animatedValue.value >= 0.7f) 0f else 1f) + .scale((1-animatedValue.value)) + ) + } + +} + +fun runAnimationText( + coroutineScope: CoroutineScope, + scaleFactor: Animatable +) { + coroutineScope.launch { + + scaleFactor.animateTo( + targetValue = 0.1f, + animationSpec = tween(5000, easing = LinearEasing) + ) + + delay(500) + + scaleFactor.animateTo( + targetValue = 1f, + animationSpec = tween(5000, easing = LinearEasing) + ) + + delay(500) + + runAnimationText(coroutineScope = coroutineScope, scaleFactor = scaleFactor) + } +} diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/BreatheRotatingAnimation.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/BreatheRotatingAnimation.kt new file mode 100644 index 0000000..71c3579 --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/BreatheRotatingAnimation.kt @@ -0,0 +1,263 @@ +package dev.baseio.composeplayground.ui.animations.adityabhawsar + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.Canvas +import dev.baseio.composeplayground.contributors.AdityaBhawsar +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.rotate +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@Composable +fun BreatheRotatingAnimation(modifier: Modifier = Modifier) { + + val rotationIndicator = remember { Animatable(0f) } + val dialScale = remember { Animatable(1f) } + + LaunchedEffect(key1 = true) { + runDialAnimation( + this, + rotationIndicator, + dialScale + ) + } + + Box( + modifier + .fillMaxSize() + .background(Color.Black) + ) { + + Canvas( + modifier = Modifier + .size(250.dp) + .scale(dialScale.value) + .align(Alignment.Center) + ) { + + drawCircle( + color = Color.LightGray + ) + drawArc( + color = Color.Blue, + useCenter = true, + startAngle = 270f, + sweepAngle = 90f + ) + drawArc( + color = Color.Cyan, + useCenter = true, + startAngle = 90f, + sweepAngle = 90f + ) + drawCircle( + color = Color.Black, + radius = (size.maxDimension / 2.0f) - 10f + ) + rotate( + 45f + ) { + drawCircle( + brush = Brush.verticalGradient( + listOf( + Color.Blue, + Color.Cyan + ) + ), + radius = (size.maxDimension / 2.0f) - 40f + ) + } + + drawArc( + color = Color.White, + startAngle = 180f, + sweepAngle = 180f, + useCenter = true, + topLeft = Offset(x = this.size.width.times(0.47f), y = this.size.height.times(.96f)), + size = Size(width = 50f, height = 52f) + ) + + rotate(90f) { + drawArc( + color = Color.White, + startAngle = 180f, + sweepAngle = 180f, + useCenter = true, + topLeft = Offset(x = this.size.width.times(0.47f), y = this.size.height.times(.96f)), + size = Size(width = 50f, height = 52f) + ) + } + + rotate(180f) { + drawArc( + color = Color.White, + startAngle = 180f, + sweepAngle = 180f, + useCenter = true, + topLeft = Offset(x = this.size.width.times(0.47f), y = this.size.height.times(.96f)), + size = Size(width = 50f, height = 52f) + ) + } + + rotate(270f) { + drawArc( + color = Color.White, + startAngle = 180f, + sweepAngle = 180f, + useCenter = true, + topLeft = Offset(x = this.size.width.times(0.47f), y = this.size.height.times(.96f)), + size = Size(width = 50f, height = 52f) + ) + } + + rotate(rotationIndicator.value) { + drawArc( + color = Color.Blue, + startAngle = 180f, + sweepAngle = 180f, + useCenter = true, + topLeft = Offset(x = this.size.width.times(0.47f), y = this.size.height.times(.96f)), + size = Size(width = 50f, height = 52f) + ) + } + + } + + Box(modifier = Modifier.align(Alignment.Center)){ + + AnimatedVisibility( + visible = ( + (rotationIndicator.value >= 90f && rotationIndicator.value < 180f) + || + (rotationIndicator.value >= 270f && rotationIndicator.value < 360f) + ), + enter = fadeIn(), + exit = fadeOut() + ) { + Text( + modifier = Modifier.fillMaxWidth().align(Alignment.Center), + text = "Hold", + style = TextStyle( + color = Color.White, + textAlign = TextAlign.Center, + fontSize = 18.sp + ) + ) + } + + AnimatedVisibility( + visible = (rotationIndicator.value >= 0f && rotationIndicator.value < 90f), + enter = fadeIn(), + exit = fadeOut() + ) { + Text( + modifier = Modifier.fillMaxWidth().align(Alignment.Center), + text = "Breathe In", + style = TextStyle( + color = Color.White, + textAlign = TextAlign.Center, + fontSize = 18.sp + ) + ) + } + + AnimatedVisibility( + visible = (rotationIndicator.value >= 180f && rotationIndicator.value < 270f), + enter = fadeIn(), + exit = fadeOut() + ) { + Text( + modifier = Modifier.fillMaxWidth().align(Alignment.Center), + text = "Breathe Out", + style = TextStyle( + color = Color.White, + textAlign = TextAlign.Center, + fontSize = 18.sp + ), + ) + } + + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.BottomCenter) + ) { + AdityaBhawsar( + Modifier + .align(Alignment.Center) + .background(Color.LightGray) + ) + } + } +} + +fun runDialAnimation( + coroutineScope: CoroutineScope, + rotationIndicator: Animatable, + dialScale: Animatable +) { + coroutineScope.launch { + + coroutineScope.launch { + rotationIndicator.animateTo( + targetValue = 360f, + animationSpec = tween( + durationMillis = 10000, + easing = LinearEasing + ) + ) + rotationIndicator.snapTo(0f) + } + + dialScale.animateTo( + targetValue = 1.25f, + animationSpec = tween( + durationMillis = 2500, + easing = LinearEasing + ) + ) + + delay(2500) + + dialScale.animateTo( + targetValue = 1f, + animationSpec = tween( + durationMillis = 2500, + easing = LinearEasing + ) + ) + + delay(2500) + + + runDialAnimation( + coroutineScope, + rotationIndicator, + dialScale + ) + } +} diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/CircleSquareAnimation.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/CircleSquareAnimation.kt new file mode 100644 index 0000000..968c19a --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/CircleSquareAnimation.kt @@ -0,0 +1,159 @@ +package dev.baseio.composeplayground.ui.animations.adityabhawsar + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import dev.baseio.composeplayground.contributors.AdityaBhawsar +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@Composable +fun CircleSquareAnimation(modifier: Modifier = Modifier) { + + val rotationBox = remember { + Animatable(0f) + } + val rotationCircle = remember { + Animatable(0f) + } + + LaunchedEffect(key1 = true){ + runAnimation( + coroutineScope = this, + rotationBox = rotationBox, + rotationCircle = rotationCircle + ) + } + + Box( + modifier + .fillMaxSize() + .background(Color.Black) + ) { + + Row(modifier = Modifier + .size(300.dp) + .rotate(rotationBox.value) + .align(Alignment.Center)) { + Column(modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(0.5f)) { + Canvas(modifier = Modifier + .fillMaxHeight(0.5f) + .fillMaxWidth() + .rotate(rotationCircle.value) + .padding(12.dp), onDraw = { + drawCircle(Color.White) + drawRect( + color = Color.Black, + topLeft = Offset(size.width/2, size.height/2), + size = Size(size.width/2, size.height/2) + ) + }) + Canvas(modifier = Modifier + .fillMaxHeight() + .fillMaxWidth() + .rotate(rotationCircle.value) + .padding(12.dp), onDraw = { + drawCircle(Color.White) + drawRect( + color = Color.Black, + topLeft = Offset(size.width/2, 0f), + size = Size(size.width/2, size.height/2) + ) + }) + } + Column(modifier = Modifier + .fillMaxHeight() + .fillMaxWidth()) { + Canvas(modifier = Modifier + .fillMaxHeight(0.5f) + .fillMaxWidth() + .rotate(rotationCircle.value) + .padding(12.dp), onDraw = { + drawCircle(Color.White) + drawRect( + color = Color.Black, + topLeft = Offset(0f, size.height/2), + size = Size(size.width/2, size.height/2) + ) + }) + Canvas(modifier = Modifier + .fillMaxHeight() + .fillMaxWidth() + .rotate(rotationCircle.value) + .padding(12.dp), onDraw = { + drawCircle(Color.White) + drawRect( + color = Color.Black, + topLeft = Offset(0f, 0f), + size = Size(size.width/2, size.height/2) + ) + }) + } + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.BottomCenter) + ) { + AdityaBhawsar( + Modifier + .align(Alignment.Center) + .background(Color.LightGray)) + } + } +} + +fun runAnimation( + coroutineScope: CoroutineScope, + rotationBox: Animatable, + rotationCircle: Animatable +){ + coroutineScope.launch { + + delay(1000) + + rotationBox.animateTo( + 90f, + tween(easing = FastOutSlowInEasing, durationMillis = 1000) + ) + + delay(500) + + coroutineScope.launch { + rotationBox.animateTo( + 0f, + tween(easing = FastOutSlowInEasing, durationMillis = 1000) + ) + } + + rotationCircle.animateTo( + 360f, + tween(easing = FastOutSlowInEasing, durationMillis = 1000) + ) + + rotationCircle.snapTo(0f) + + runAnimation( + coroutineScope = this, + rotationBox = rotationBox, + rotationCircle = rotationCircle + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/FiSplashAnimation.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/FiSplashAnimation.kt new file mode 100644 index 0000000..3e15772 --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/FiSplashAnimation.kt @@ -0,0 +1,296 @@ +package dev.baseio.composeplayground.ui.animations.adityabhawsar + +import android.graphics.Paint +import androidx.compose.animation.core.* +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.scale +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.drawscope.rotate +import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.unit.dp +import dev.baseio.composeplayground.contributors.AdityaBhawsar +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@Composable +fun FiSplashAnimation() { + + val ballOffset = remember { Animatable(-280f) } + val ballScale = remember { Animatable(0f) } + val textAlpha = remember { Animatable(0f) } + val textScale = remember { Animatable(1.35f) } + val circleAlpha = remember { Animatable(1f) } + val squareAlpha = remember { Animatable(0f) } + val squareRotation = remember { Animatable(45f) } + val heightRatio = remember { Animatable(.27f) } + + LaunchedEffect(key1 = true){ + runFiAnimation( + this, + ballOffset, + ballScale, + textScale, + textAlpha, + circleAlpha, + squareAlpha, + squareRotation, + heightRatio + ) + } + + Box( + Modifier + .fillMaxSize() + .background(Color.White) + ) { + + Canvas( + modifier = Modifier + .size(16.dp) + .scale(ballScale.value) + .align(Alignment.Center) + .offset(y = ballOffset.value.dp), + onDraw = { + drawCircle(color = Color(0xFF00B899)) + } + ) + + Canvas( + modifier = Modifier + .size(100.dp) + .alpha(textAlpha.value) + .scale(textScale.value) + .align(Alignment.Center) + ){ + + val fPath = Path().let { + it.moveTo( x= this.size.width.times(.50f) , y= this.size.height.times(.25f)) + it.lineTo(x = this.size.width.times(0.30f), y = this.size.height.times(.25f)) + it.quadraticBezierTo( + x1 = this.size.width.times(0.07f), y1 = this.size.height.times(.25f), + x2 = this.size.width.times(0.07f), y2 = this.size.height.times(.45f) + ) + it.lineTo(x = this.size.width.times(0.07f), y = this.size.height.times(.95f)) + it.lineTo(x = this.size.width.times(0.25f), y = this.size.height.times(.95f)) + it.lineTo(x = this.size.width.times(0.25f), y = this.size.height.times(.85f)) + it.quadraticBezierTo( + x1 = this.size.width.times(0.25f), y1 = this.size.height.times(0.70f), + x2 = this.size.width.times(0.35f), y2 = this.size.height.times(0.70f) + ) + it.lineTo(x = this.size.width.times(0.5f), y = this.size.height.times(.70f)) + it.lineTo(x = this.size.width.times(0.5f), y = this.size.height.times(.55f)) + it.lineTo(x = this.size.width.times(0.25f), y = this.size.height.times(.55f)) + it.lineTo(x = this.size.width.times(0.25f), y = this.size.height.times(.47f)) + it.quadraticBezierTo( + x1 = this.size.width.times(0.25f), y1 = this.size.height.times(0.4f), + x2 = this.size.width.times(0.4f), y2 = this.size.height.times(0.4f) + ) + it.lineTo(x = this.size.width.times(0.5f), y = this.size.height.times(.4f)) + it.close() + it + } + + val iPath = Path().let { + it.moveTo(x = this.size.width.times(0.6f), y = this.size.height.times(.57f)) + it.lineTo(x = this.size.width.times(0.8f), y = this.size.height.times(.57f)) + it.lineTo(x = this.size.width.times(0.8f), y = this.size.height.times(.7f)) + it.quadraticBezierTo( + x1 = this.size.width.times(0.8f), y1 = this.size.height.times(0.77f), + x2 = this.size.width.times(0.9f), y2 = this.size.height.times(0.77f) + ) + it.lineTo(x = this.size.width.times(0.9f), y = this.size.height.times(.95f)) + it.lineTo(x = this.size.width.times(0.77f), y = this.size.height.times(.95f)) + it.quadraticBezierTo( + x1 = this.size.width.times(0.6f), y1 = this.size.height.times(0.95f), + x2 = this.size.width.times(0.6f), y2 = this.size.height.times(0.75f) + ) + it.close() + it + } + + drawPath(path = fPath, color = Color.White) + + drawPath(path = iPath, color = Color.White) + + drawCircle( + alpha = circleAlpha.value, + color = Color.White, + radius = 27f, + center = Offset(x = this.size.width.times(.7f), y = this.size.height.times(0.10f + heightRatio.value)) + ) + + rotate( + degrees = squareRotation.value, + pivot = Offset(this.size.width.times(.7f), this.size.height.times(0.10f + heightRatio.value)) + ) { + drawRoundRect( + alpha = squareAlpha.value, + cornerRadius = CornerRadius( + x= 4.dp.toPx(), + y= 4.dp.toPx(), + ), + color = Color.White, + topLeft = Offset(this.size.width.times(.6f), this.size.height.times(heightRatio.value)), + size = Size(54f, 54f) + ) + } + + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.TopCenter) + ) { + AdityaBhawsar( + Modifier + .align(Alignment.Center) + .background(Color.LightGray) + ) + } + } +} + +fun runFiAnimation( + coroutineScope: CoroutineScope, + ballOffset: Animatable, + ballScale: Animatable, + textScale: Animatable, + textAlpha: Animatable, + circleAlpha: Animatable, + squareAlpha: Animatable, + squareRotation: Animatable, + heightRatio: Animatable +) { + coroutineScope.launch { + + ballScale.snapTo(.2f) + + coroutineScope.launch { + ballScale.animateTo( + targetValue = 1f, + animationSpec = tween(300, easing = FastOutSlowInEasing) + ) + } + + ballOffset.animateTo( + targetValue = -300f, + animationSpec = tween(300, easing = FastOutSlowInEasing) + ) + + coroutineScope.launch { + ballScale.animateTo( + targetValue = 1.75f, + animationSpec = tween(600, easing = FastOutSlowInEasing) + ) + } + + ballOffset.animateTo( + targetValue = 0f, + animationSpec = tween(600, easing = FastOutSlowInEasing) + ) + + textAlpha.snapTo(1f) + + coroutineScope.launch { + textScale.animateTo( + targetValue = 1f, + animationSpec = tween(600, easing = LinearEasing) + ) + } + + coroutineScope.launch { + ballScale.animateTo( + targetValue = 75f, + animationSpec = tween( 400, easing = FastOutSlowInEasing ) + ) + } + + bounceAnimation( + coroutineScope, + circleAlpha, + squareAlpha, + heightRatio, + squareRotation + ) + } +} + +fun bounceAnimation( + coroutineScope: CoroutineScope, + circleAlpha: Animatable, + squareAlpha: Animatable, + heightRatio: Animatable, + squareRotation: Animatable +) { + coroutineScope.launch { + + heightRatio.animateTo( + targetValue = 0f, + animationSpec = tween(300, easing = FastOutSlowInEasing) + ) + + delay(50) + + heightRatio.animateTo( + targetValue = .27f, + animationSpec = tween(300, easing = FastOutLinearInEasing) + ) + + circleAlpha.snapTo(0f) + squareAlpha.snapTo(1f) + + coroutineScope.launch { + squareRotation.animateTo( + targetValue = 135f, + animationSpec = tween(300, easing = FastOutSlowInEasing) + ) + } + + heightRatio.animateTo( + targetValue = 0f, + animationSpec = tween(300, easing = FastOutSlowInEasing) + ) + + delay(50) + + coroutineScope.launch { + squareRotation.animateTo( + targetValue = 225f, + animationSpec = tween(300, easing = FastOutSlowInEasing) + ) + } + + heightRatio.animateTo( + targetValue = .27f, + animationSpec = tween(300, easing = FastOutLinearInEasing) + ) + + squareRotation.snapTo(45f) + circleAlpha.snapTo(1f) + squareAlpha.snapTo(0f) + + bounceAnimation( + coroutineScope, + circleAlpha, + squareAlpha, + heightRatio, + squareRotation + ) + } +} diff --git a/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/MicAnimation.kt b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/MicAnimation.kt new file mode 100644 index 0000000..1e8ac05 --- /dev/null +++ b/app/src/main/java/dev/baseio/composeplayground/ui/animations/adityabhawsar/MicAnimation.kt @@ -0,0 +1,144 @@ +package dev.baseio.composeplayground.ui.animations.adityabhawsar + +import dev.baseio.composeplayground.contributors.AdityaBhawsar +import androidx.compose.animation.core.* +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import dev.baseio.composeplayground.R + +@Composable +fun MicAnimation(modifier: Modifier = Modifier) { + + val alphaCircle = remember { Animatable(0f) } + val scaleFactorLightGreyBg = remember { Animatable(1f) } + val scaleFactorGreyBg = remember { Animatable(1f) } + val scaleFactorRedBg = remember { Animatable(1f) } + + LaunchedEffect(alphaCircle){ + alphaCircle.animateTo( + targetValue = 1f, + animationSpec = infiniteRepeatable( + tween(1500, easing = LinearEasing), + repeatMode = RepeatMode.Reverse + ) + ) + } + + LaunchedEffect(scaleFactorLightGreyBg){ + scaleFactorLightGreyBg.animateTo( + targetValue = 3f, + animationSpec = infiniteRepeatable( + tween(700, easing = FastOutLinearInEasing), + repeatMode = RepeatMode.Reverse + ) + ) + } + + LaunchedEffect(scaleFactorGreyBg){ + scaleFactorGreyBg.animateTo( + targetValue = 2f, + animationSpec = infiniteRepeatable( + tween(1000, easing = LinearOutSlowInEasing), + repeatMode = RepeatMode.Reverse + ) + ) + } + + LaunchedEffect(scaleFactorRedBg){ + scaleFactorRedBg.animateTo( + targetValue = 1.2f, + animationSpec = infiniteRepeatable( + tween(500, easing = FastOutSlowInEasing), + repeatMode = RepeatMode.Reverse + ) + ) + } + + Box( + modifier + .fillMaxSize() + .background(Color.Black) + ) { + + Surface( + shape = CircleShape, + color = Color.Black, + border = BorderStroke(3.dp, Color.LightGray), + modifier = Modifier + .size(210.dp) + .alpha(alphaCircle.value) + .align(Alignment.Center) + ) {} + + Canvas( + modifier = Modifier + .size(70.dp) + .align(Alignment.Center) + .scale(scaleFactorLightGreyBg.value) + .alpha(0.3f), + onDraw = { + drawCircle(color = Color.LightGray) + } + ) + + Canvas( + modifier = Modifier + .size(70.dp) + .align(Alignment.Center) + .scale(scaleFactorGreyBg.value), + onDraw = { + drawCircle(color = Color.Gray) + } + ) + + Canvas( + modifier = Modifier + .size(70.dp) + .align(Alignment.Center) + .scale(scaleFactorRedBg.value), + onDraw = { + drawCircle(color = Color.Red) + } + ) + + FloatingActionButton( + onClick = {}, + content = { + Icon( + painter = androidx.compose.ui.res.painterResource(id = R.drawable.ic_mic_white_40), + contentDescription = "Mic" + ) + }, + elevation = FloatingActionButtonDefaults.elevation(0.dp), + backgroundColor = Color.Red, + contentColor = Color.White, + modifier = Modifier + .size(70.dp) + .align(Alignment.Center) + .scale(1f) + ) + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp) + .align(Alignment.BottomCenter) + ) { + AdityaBhawsar( + Modifier + .align(Alignment.Center) + .background(Color.LightGray)) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000..a49bea7 --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_mic_white_40.xml b/app/src/main/res/drawable/ic_mic_white_40.xml new file mode 100644 index 0000000..b152428 --- /dev/null +++ b/app/src/main/res/drawable/ic_mic_white_40.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a144b92..4857007 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,6 +2,8 @@ Compose Playground Anmol Verma anmol.verma@mutualmobile.com\nanmol.verma4@gmail.com + Aditya Bhawsar + aditya.bhawsar@mutualmobile.com\naditya.bhawsar.work@gmail.com LOADING \ No newline at end of file