From bb77f5608dee15585f1404b7f774a4879106a69c Mon Sep 17 00:00:00 2001 From: abdullahalhakimi Date: Sat, 31 Aug 2024 20:28:34 +0300 Subject: [PATCH] Add New Features --- .idea/kotlinc.xml | 2 +- .../smoothmotion/MainActivity.kt | 247 +++++++----------- .../smoothmotion/animations/AnimatedButton.kt | 62 ----- .../animations/AnimatingArcsProgress.kt | 14 +- .../AnimatingCircleWithArcsProgress.kt | 10 +- ...DotsProgress.kt => CircledDotsProgress.kt} | 8 +- ...dArcsProgress.kt => DropCircleProgress.kt} | 66 ++--- .../smoothmotion/animations/ExpandingCard.kt | 75 ------ ...ngAnimation.kt => LoadingDotsAnimation.kt} | 2 +- .../animations/LoadingIndicator.kt | 42 --- .../OutlinedLoadingDotsAnimation.kt | 82 ++++++ .../animations/PageTransitions.kt | 75 ------ .../smoothmotion/animations/RotatingIcon.kt | 46 ---- .../utils/{ProgressTitle.kt => Title.kt} | 4 +- 14 files changed, 226 insertions(+), 509 deletions(-) delete mode 100644 library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatedButton.kt rename library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/{DroppingDotsProgress.kt => CircledDotsProgress.kt} (97%) rename library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/{ScatteredArcsProgress.kt => DropCircleProgress.kt} (77%) delete mode 100644 library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ExpandingCard.kt rename library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/{AppLoadingAnimation.kt => LoadingDotsAnimation.kt} (99%) delete mode 100644 library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingIndicator.kt create mode 100644 library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/OutlinedLoadingDotsAnimation.kt delete mode 100644 library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/PageTransitions.kt delete mode 100644 library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/RotatingIcon.kt rename library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/{ProgressTitle.kt => Title.kt} (82%) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d99..8d81632 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/app/src/main/java/com/abdullahalhakimi/smoothmotion/MainActivity.kt b/app/src/main/java/com/abdullahalhakimi/smoothmotion/MainActivity.kt index 819d36a..d42bc04 100644 --- a/app/src/main/java/com/abdullahalhakimi/smoothmotion/MainActivity.kt +++ b/app/src/main/java/com/abdullahalhakimi/smoothmotion/MainActivity.kt @@ -1,195 +1,130 @@ package com.abdullahalhakimi.smoothmotion +import android.annotation.SuppressLint import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Refresh -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import com.abdullahalhakimi.smoothmotion.animations.AnimatedButton -import com.abdullahalhakimi.smoothmotion.animations.AppLoadingAnimation -import com.abdullahalhakimi.smoothmotion.animations.DroppingDotsProgress -import com.abdullahalhakimi.smoothmotion.animations.ExpandingCard -import com.abdullahalhakimi.smoothmotion.animations.PulsatingLoadingIndicator -import com.abdullahalhakimi.smoothmotion.animations.RotatingIcon -import com.abdullahalhakimi.smoothmotion.animations.ScatteredArcsProgress -import com.abdullahalhakimi.smoothmotion.animations.AnimatingArcsProgress -import com.abdullahalhakimi.smoothmotion.animations.AnimatingCircleWithArcsProgress -import com.abdullahalhakimi.smoothmotion.animations.SlideTransition -import com.abdullahalhakimi.smoothmotion.utils.ProgressTitle +import com.abdullahalhakimi.smoothmotion.animations.CircledDotsProgress +import com.abdullahalhakimi.smoothmotion.animations.DropCircleProgress +import com.abdullahalhakimi.smoothmotion.animations.LoadingDotsAnimation +import com.abdullahalhakimi.smoothmotion.animations.OutlinedLoadingDotsAnimation +import com.abdullahalhakimi.smoothmotion.animations.RotatingCircleProgress +import com.abdullahalhakimi.smoothmotion.animations.RotatingFilledCircleProgress +import com.abdullahalhakimi.smoothmotion.utils.Title class MainActivity : ComponentActivity() { + @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { - ExampleMainActivityContent() + ExampleMainActivityContent(modifier = Modifier) } } } @Composable -fun ExampleMainActivityContent() { - var isExpanded by remember { mutableStateOf(false) } - var showSlide by remember { mutableStateOf(true) } - +fun ExampleMainActivityContent(modifier: Modifier = Modifier) { Column( - modifier = Modifier + modifier .fillMaxSize() - .padding(16.dp), + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) + verticalArrangement = Arrangement.Center, ) { - Spacer(modifier = Modifier.height(10.dp)) - // AnimatedButton Example - AnimatedButton( - onClick = { - Log.d("A:","Ali") - }, - modifier = Modifier, + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), ) { - Text("Animated Button") + DropCircleProgress( + modifier = Modifier.size(90.dp), + backgroundColor = Color.Gray.copy(alpha = 0.2f), + color = MaterialTheme.colorScheme.primary + ) + CircledDotsProgress( + modifier = Modifier.size(90.dp), + backgroundColor = Color.Gray.copy(alpha = 0.2f), + color = MaterialTheme.colorScheme.primary + ) } - - // SlideTransition Example - SlideTransition(targetState = showSlide) { - Text("Slide In Content", modifier = Modifier.padding(16.dp)) + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), + ) { + Title(title = "Drop Circle Progress") + Title(title = "Circled Dots Progress") } - Button(onClick = { showSlide = !showSlide }) { - Text(if (showSlide) "Hide Slide" else "Show Slide") + Spacer(modifier = Modifier.height(100.dp)) + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), + ) { + RotatingCircleProgress( + modifier = Modifier.size(90.dp), + color = MaterialTheme.colorScheme.primary + ) + RotatingFilledCircleProgress( + modifier = Modifier.size(90.dp), + color = MaterialTheme.colorScheme.primary + ) } - - // PulsatingLoadingIndicator Example - PulsatingLoadingIndicator() - - // ExpandingCard Example - ExpandingCard( - headerContent = { Text("Expanding Card Header") }, - expandedContent = { Text("This is the expanded content of the card.") }, - isExpanded = isExpanded, - onClick = { isExpanded = !isExpanded } - ) - - // RotatingIcon Example - RotatingIcon( - modifier = Modifier.size(60.dp), - icon = { Icon(Icons.Default.Refresh, contentDescription = "Rotating Icon") }, - color = Color.Blue - ) - - AppLoadingAnimation() - } -} - -@Composable - -fun AppLoadingExample() { - var isExpanded by remember { mutableStateOf(false) } - var showSlide by remember { mutableStateOf(true) } - - Column( - modifier = Modifier - .fillMaxSize() - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - Spacer(modifier = Modifier.height(10.dp)) - // AnimatedButton Example - AnimatedButton( - onClick = { - Log.d("A:","Ali") - }, - modifier = Modifier, + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), ) { - Text("Animated Button") + Title(title = "Rotating Circle Progress") + Title(title = "Rotating Filled Circle Progress") } - - // SlideTransition Example - SlideTransition(targetState = showSlide) { - Text("Slide In Content", modifier = Modifier.padding(16.dp)) + Spacer(modifier = Modifier.height(100.dp)) + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), + ) { + LoadingDotsAnimation( + circleSize = 20.dp, + spaceBetween = 10.dp, + travelDistance = 15.dp, + circleColor = MaterialTheme.colorScheme.primary + ) + OutlinedLoadingDotsAnimation( + circleSize = 20.dp, + spaceBetween = 10.dp, + travelDistance = 15.dp, + circleColor = MaterialTheme.colorScheme.primary + ) } - Button(onClick = { showSlide = !showSlide }) { - Text(if (showSlide) "Hide Slide" else "Show Slide") + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth(), + ) { + Title(title = "Loading Dots Animation") + Title(title = "Outlined Loading Dots Animation") } - // PulsatingLoadingIndicator Example - PulsatingLoadingIndicator() - - // ExpandingCard Example - ExpandingCard( - headerContent = { Text("Expanding Card Header") }, - expandedContent = { Text("This is the expanded content of the card.") }, - isExpanded = isExpanded, - onClick = { isExpanded = !isExpanded } - ) - - // RotatingIcon Example - RotatingIcon( - modifier = Modifier.size(60.dp), - icon = { Icon(Icons.Default.Refresh, contentDescription = "Rotating Icon") }, - color = Color.Blue - ) - - AppLoadingAnimation() - } -} - - -@Composable -fun CircularProgressExample(modifier: Modifier = Modifier) { - Column( - modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - - ScatteredArcsProgress( - modifier = Modifier.size(100.dp), - backgroundColor = Color.Gray.copy(alpha = 0.2f), - activeColor = Color(0xFF0097ff) - ) - - ProgressTitle(title = "ScatteredArcsProgress") - Spacer(modifier = Modifier.height(32.dp)) - - DroppingDotsProgress( - modifier = Modifier.size(100.dp), - backgroundColor = Color.Gray.copy(alpha = 0.2f), - activeColor = Color(0xFF0097ff) - ) - - ProgressTitle(title = "DroppingDotsProgress") - Spacer(modifier = Modifier.height(32.dp)) - - AnimatingArcsProgress( - modifier = Modifier.size(100.dp), - activeColor = Color(0xFF0097ff) - ) - - ProgressTitle(title = "AnimatingArcsProgress") - Spacer(modifier = Modifier.height(32.dp)) - - AnimatingCircleWithArcsProgress( - modifier = Modifier.size(100.dp), - activeColor = Color(0xFF0097ff) - ) - ProgressTitle(title = "AnimatingCircleWithArcsProgress.kt") } } diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatedButton.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatedButton.kt deleted file mode 100644 index d08724d..0000000 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatedButton.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.abdullahalhakimi.smoothmotion.animations - -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.unit.dp -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch - - -@Composable -fun AnimatedButton( - onClick: () -> Unit, - modifier: Modifier = Modifier, - scaleDownValue: Float = 0.95f, - animationDuration: Int = 300, - cornerRadius: Int = 8, - padding: Int = 16, - content: @Composable () -> Unit -) { - val scope = rememberCoroutineScope() - var isPressed by remember { mutableStateOf(false) } - val scale by animateFloatAsState( - targetValue = if (isPressed) scaleDownValue else 1f, - animationSpec = tween(durationMillis = animationDuration), - label = "AnimatedButton", - ) - - Surface( - modifier = modifier - .graphicsLayer(scaleX = scale, scaleY = scale) - .clickable( - onClick = { - isPressed = true - onClick() - scope.launch { - delay(1000) - } - isPressed = false - } - ), - shape = RoundedCornerShape(cornerRadius.dp), - color = MaterialTheme.colorScheme.primary - ) { - Box(modifier = Modifier.padding(padding.dp)) { - content() - } - } -} diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingArcsProgress.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingArcsProgress.kt index 5275484..5a30104 100644 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingArcsProgress.kt +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingArcsProgress.kt @@ -22,8 +22,8 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @Composable -fun AnimatingArcsProgress( - activeColor: Color, +fun RotatingCircleProgress( + color: Color, modifier: Modifier = Modifier, arcsWidth: Dp = 4.dp, arcsLayerPadding: Dp = 16.dp, @@ -84,7 +84,7 @@ fun AnimatingArcsProgress( Box(modifier = modifier) { Canvas(modifier = Modifier.fillMaxSize().rotate(canvasRotation.value)) { drawArc( - color = activeColor, + color = color, startAngle = outerArcsStartAngleProgress.value * arcSweepOffset, sweepAngle = outerArcsSweepProgress.value * arcSweepOffset, useCenter = false, @@ -95,7 +95,7 @@ fun AnimatingArcsProgress( ) drawArc( - color = activeColor, + color = color, startAngle = 180f + outerArcsStartAngleProgress.value * arcSweepOffset, sweepAngle = outerArcsSweepProgress.value * arcSweepOffset, useCenter = false, @@ -110,7 +110,7 @@ fun AnimatingArcsProgress( modifier = Modifier.fillMaxSize().padding(arcsLayerPadding).rotate(canvasRotation.value) ) { drawArc( - color = activeColor, + color = color, startAngle = arcSweepOffset + outerArcsStartAngleProgress.value * arcSweepOffset, sweepAngle = outerArcsSweepProgress.value * arcSweepOffset, useCenter = false, @@ -120,7 +120,7 @@ fun AnimatingArcsProgress( ) ) drawArc( - color = activeColor, + color = color, startAngle = 270f + outerArcsStartAngleProgress.value * arcSweepOffset, sweepAngle = outerArcsSweepProgress.value * arcSweepOffset, useCenter = false, @@ -135,7 +135,7 @@ fun AnimatingArcsProgress( val radius = size.width / 2 drawCircle( alpha = innerCircleRadiusProgress.value, - color = activeColor, + color = color, radius = radius * innerCircleRadiusProgress.value, style = Stroke( width = arcsWidthInPx, diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingCircleWithArcsProgress.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingCircleWithArcsProgress.kt index 80d166d..088d677 100644 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingCircleWithArcsProgress.kt +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AnimatingCircleWithArcsProgress.kt @@ -23,8 +23,8 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @Composable -fun AnimatingCircleWithArcsProgress( - activeColor: Color, +fun RotatingFilledCircleProgress( + color: Color, modifier: Modifier = Modifier, outerArcsWidth: Dp = 4.dp, innerCircleAnimationDuration: Int = 2000 @@ -99,13 +99,13 @@ fun AnimatingCircleWithArcsProgress( Canvas(modifier = Modifier.fillMaxSize().padding(8.dp)) { val radius = size.width / 2 drawCircle( - color = activeColor, + color = color, radius = radius * innerCircleRadiusProgress.value ) } Canvas(modifier = Modifier.fillMaxSize().rotate(arcsCanvasRotation.value)) { drawArc( - color = activeColor, + color = color, startAngle = arcsStartAngles.first() + outerArcsStartAngle.value * (sweepAngle - arcsStartAngles.first()), sweepAngle = sweepAngle * outerArcsSweepProgress.value, useCenter = false, @@ -115,7 +115,7 @@ fun AnimatingCircleWithArcsProgress( ) ) drawArc( - color = activeColor, + color = color, startAngle = arcsStartAngles[1] + outerArcsStartAngle.value * (arcsStartAngles[1] - sweepAngle), sweepAngle = sweepAngle * outerArcsSweepProgress.value, useCenter = false, diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/DroppingDotsProgress.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/CircledDotsProgress.kt similarity index 97% rename from library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/DroppingDotsProgress.kt rename to library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/CircledDotsProgress.kt index dc7452c..77d2169 100644 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/DroppingDotsProgress.kt +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/CircledDotsProgress.kt @@ -21,9 +21,9 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @Composable -fun DroppingDotsProgress( +fun CircledDotsProgress( backgroundColor: Color, - activeColor: Color, + color: Color, modifier: Modifier = Modifier, pathWidth: Dp = 6.dp, duration: Int = 1500 @@ -90,7 +90,7 @@ fun DroppingDotsProgress( ) ) drawArc( - color = activeColor, + color = color, startAngle = bigArcStartAngle.value, sweepAngle = bigCircleSweepAngle, style = Stroke( @@ -102,7 +102,7 @@ fun DroppingDotsProgress( if (isSmallArcsVisible.value) { smallArcsStartAngle.forEachIndexed { _, startAngel -> drawArc( - color = activeColor, + color = color, startAngle = (startAngel + smallArcsStartAngleProgress.value * (175f - startAngel)), sweepAngle = smallArcsSweepAngle, style = Stroke( diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ScatteredArcsProgress.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/DropCircleProgress.kt similarity index 77% rename from library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ScatteredArcsProgress.kt rename to library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/DropCircleProgress.kt index 7f4a7e9..4237fd5 100644 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ScatteredArcsProgress.kt +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/DropCircleProgress.kt @@ -6,7 +6,7 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate @@ -20,9 +20,9 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive @Composable -fun ScatteredArcsProgress( +fun DropCircleProgress( backgroundColor: Color, - activeColor: Color, + color: Color, modifier: Modifier = Modifier, pathWidth: Dp = 6.dp, duration: Int = 1000 @@ -30,12 +30,12 @@ fun ScatteredArcsProgress( val scatteredArcSweep = remember { 22.5f } val sweepOffset = remember { 45f } val pathWidthInPx = with(LocalDensity.current) { pathWidth.toPx() } - val topArcStartOffset = remember { mutableStateOf(45f) } - val topArcSweepAngle = remember { mutableStateOf(90f) } + val topArcStartOffset = remember { mutableFloatStateOf(45f) } + val topArcSweepAngle = remember { mutableFloatStateOf(90f) } val transferArcStart = remember { Animatable(0f) } val transferArcSweepAngle = remember { Animatable(0f) } - val bottomArcStart = remember { mutableStateOf(0f) } - val bottomArcSweepAngle = remember { mutableStateOf(0f) } + val bottomArcStart = remember { mutableFloatStateOf(0f) } + val bottomArcSweepAngle = remember { mutableFloatStateOf(0f) } LaunchedEffect(Unit) { while (isActive) { @@ -48,14 +48,14 @@ fun ScatteredArcsProgress( targetValue = scatteredArcSweep, animationSpec = tween(0) ) - topArcStartOffset.value += scatteredArcSweep - topArcSweepAngle.value -= scatteredArcSweep + topArcStartOffset.floatValue += scatteredArcSweep + topArcSweepAngle.floatValue -= scatteredArcSweep transferArcStart.animateTo( targetValue = -sweepOffset - scatteredArcSweep * 2, animationSpec = tween(duration / 8, easing = LinearEasing) ) - bottomArcStart.value = -sweepOffset - scatteredArcSweep * 2 - bottomArcSweepAngle.value = scatteredArcSweep + bottomArcStart.floatValue = -sweepOffset - scatteredArcSweep * 2 + bottomArcSweepAngle.floatValue = scatteredArcSweep transferArcStart.animateTo( targetValue = 0f, animationSpec = tween(0) @@ -75,13 +75,13 @@ fun ScatteredArcsProgress( targetValue = scatteredArcSweep, animationSpec = tween(0) ) - topArcSweepAngle.value -= scatteredArcSweep + topArcSweepAngle.floatValue -= scatteredArcSweep transferArcStart.animateTo( targetValue = sweepOffset + scatteredArcSweep * 9, animationSpec = tween(duration / 8, easing = LinearEasing) ) - bottomArcStart.value = 270f - scatteredArcSweep - bottomArcSweepAngle.value += scatteredArcSweep + bottomArcStart.floatValue = 270f - scatteredArcSweep + bottomArcSweepAngle.floatValue += scatteredArcSweep transferArcStart.animateTo( targetValue = 0f, animationSpec = tween(0) @@ -101,14 +101,14 @@ fun ScatteredArcsProgress( targetValue = scatteredArcSweep, animationSpec = tween(0) ) - topArcStartOffset.value += scatteredArcSweep - topArcSweepAngle.value -= scatteredArcSweep + topArcStartOffset.floatValue += scatteredArcSweep + topArcSweepAngle.floatValue -= scatteredArcSweep transferArcStart.animateTo( targetValue = -sweepOffset - scatteredArcSweep, animationSpec = tween(duration / 8, easing = LinearEasing) ) - bottomArcStart.value = 270f - scatteredArcSweep - bottomArcSweepAngle.value += scatteredArcSweep + bottomArcStart.floatValue = 270f - scatteredArcSweep + bottomArcSweepAngle.floatValue += scatteredArcSweep transferArcStart.animateTo( targetValue = 0f, animationSpec = tween(0) @@ -128,26 +128,26 @@ fun ScatteredArcsProgress( targetValue = scatteredArcSweep, animationSpec = tween(0) ) - topArcSweepAngle.value -= scatteredArcSweep + topArcSweepAngle.floatValue -= scatteredArcSweep transferArcStart.animateTo( targetValue = 180f + sweepOffset, animationSpec = tween(duration / 8, easing = LinearEasing) ) - bottomArcStart.value = 180f + sweepOffset - bottomArcSweepAngle.value += scatteredArcSweep + bottomArcStart.floatValue = 180f + sweepOffset + bottomArcSweepAngle.floatValue += scatteredArcSweep transferArcStart.animateTo( targetValue = 180f + sweepOffset, animationSpec = tween(0) ) transferArcSweepAngle.animateTo( - targetValue = bottomArcSweepAngle.value, + targetValue = bottomArcSweepAngle.floatValue, animationSpec = tween(0) ) } coroutineScope { - bottomArcStart.value = 0f - bottomArcSweepAngle.value = 0f + bottomArcStart.floatValue = 0f + bottomArcSweepAngle.floatValue = 0f transferArcStart.animateTo( targetValue = 405f, animationSpec = tween( @@ -155,8 +155,8 @@ fun ScatteredArcsProgress( easing = LinearEasing ) ) - topArcStartOffset.value = sweepOffset - topArcSweepAngle.value = sweepOffset * 2 + topArcStartOffset.floatValue = sweepOffset + topArcSweepAngle.floatValue = sweepOffset * 2 transferArcStart.animateTo( targetValue = 0f, animationSpec = tween(0) @@ -179,9 +179,9 @@ fun ScatteredArcsProgress( ) drawArc( - color = activeColor, - startAngle = topArcStartOffset.value, - sweepAngle = topArcSweepAngle.value, + color = color, + startAngle = topArcStartOffset.floatValue, + sweepAngle = topArcSweepAngle.floatValue, style = Stroke( width = pathWidthInPx, cap = StrokeCap.Round @@ -190,7 +190,7 @@ fun ScatteredArcsProgress( ) drawArc( - color = if (transferArcStart.value == 0f) Color.Transparent else activeColor, + color = if (transferArcStart.value == 0f) Color.Transparent else color, startAngle = transferArcStart.value, sweepAngle = transferArcSweepAngle.value, style = Stroke( @@ -201,9 +201,9 @@ fun ScatteredArcsProgress( ) drawArc( - color = activeColor, - startAngle = bottomArcStart.value, - sweepAngle = bottomArcSweepAngle.value, + color = color, + startAngle = bottomArcStart.floatValue, + sweepAngle = bottomArcSweepAngle.floatValue, style = Stroke( width = pathWidthInPx, cap = StrokeCap.Round diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ExpandingCard.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ExpandingCard.kt deleted file mode 100644 index 9a7dce7..0000000 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/ExpandingCard.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.abdullahalhakimi.smoothmotion.animations - -import androidx.compose.animation.animateContentSize -import androidx.compose.animation.core.tween -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp - -@Composable -fun ExpandingCard( - headerContent: @Composable () -> Unit, - expandedContent: @Composable () -> Unit, - modifier: Modifier = Modifier, - isExpanded: Boolean = false, - onClick: () -> Unit = {}, - animationDuration: Int = 300, - cornerRadius: Int = 8, - padding: Int = 16 -) { - Surface( - modifier = modifier - .fillMaxWidth() - .padding(padding.dp) - .clickable { onClick() } - .animateContentSize(tween(durationMillis = animationDuration)), - shape = RoundedCornerShape(cornerRadius.dp), - color = MaterialTheme.colorScheme.surface, - tonalElevation = 4.dp - ) { - Column(modifier = Modifier.padding(padding.dp)) { - headerContent() - if (isExpanded) { - Spacer(modifier = Modifier.height(8.dp)) - expandedContent() - } - } - } -} - - - -//@Composable -//fun ExpandingCard( -// headerContent: @Composable () -> Unit, -// expandedContent: @Composable () -> Unit, -// modifier: Modifier = Modifier, -// animationDuration: Int = 300, -// cornerRadius: Int = 8, -// padding: Int = 16 -//) { -// var expanded by remember { mutableStateOf(false) } -// -// Surface( -// modifier = modifier -// .fillMaxWidth() -// .padding(padding.dp) -// .clickable { expanded = !expanded } -// .animateContentSize(tween(durationMillis = animationDuration)), -// shape = RoundedCornerShape(cornerRadius.dp), -// color = MaterialTheme.colorScheme.surface, -// tonalElevation = 4.dp -// ) { -// Column(modifier = Modifier.padding(padding.dp)) { -// headerContent() -// if (expanded) { -// Spacer(modifier = Modifier.height(8.dp)) -// expandedContent() -// } -// } -// } -//} \ No newline at end of file diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AppLoadingAnimation.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingDotsAnimation.kt similarity index 99% rename from library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AppLoadingAnimation.kt rename to library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingDotsAnimation.kt index 0d97267..237ee16 100644 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/AppLoadingAnimation.kt +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingDotsAnimation.kt @@ -24,7 +24,7 @@ import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay @Composable -fun AppLoadingAnimation( +fun LoadingDotsAnimation( modifier: Modifier = Modifier, circleSize: Dp = 20.dp, spaceBetween: Dp = 10.dp, diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingIndicator.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingIndicator.kt deleted file mode 100644 index e001058..0000000 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/LoadingIndicator.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.abdullahalhakimi.smoothmotion.animations - -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.animation.core.* -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp - -@Composable -fun PulsatingLoadingIndicator( - modifier: Modifier = Modifier, - color: Color = Color.Blue, - size: Int = 50, - minScale: Float = 0.8f, - maxScale: Float = 1.2f, - pulsationDuration: Int = 1000, - easing: Easing = LinearEasing -) { - val infiniteTransition = rememberInfiniteTransition(label = "LoadingIndicator") - val scale by infiniteTransition.animateFloat( - initialValue = minScale, - targetValue = maxScale, - animationSpec = infiniteRepeatable( - animation = tween(pulsationDuration, easing = easing), - repeatMode = RepeatMode.Reverse - ), - label = "LoadingIndicator", - ) - - Surface( - modifier = modifier - .size(size.dp) - .graphicsLayer(scaleX = scale, scaleY = scale), - color = color, - shape = CircleShape - ) {} -} diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/OutlinedLoadingDotsAnimation.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/OutlinedLoadingDotsAnimation.kt new file mode 100644 index 0000000..ecd2a54 --- /dev/null +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/OutlinedLoadingDotsAnimation.kt @@ -0,0 +1,82 @@ +package com.abdullahalhakimi.smoothmotion.animations + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.LinearOutSlowInEasing +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.keyframes +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.delay + +@Composable +fun OutlinedLoadingDotsAnimation( + modifier: Modifier = Modifier, + circleSize: Dp = 20.dp, + spaceBetween: Dp = 10.dp, + travelDistance: Dp = 15.dp, + circleColor: Color = MaterialTheme.colorScheme.primary +) { + val circles = listOf( + remember { Animatable(initialValue = 0F) }, + remember { Animatable(initialValue = 0F) }, + remember { Animatable(initialValue = 0F) } + ) + + circles.forEachIndexed { index, animation -> + LaunchedEffect(key1 = animation) { + delay(timeMillis = index * 100L) + + animation.animateTo( + targetValue = 1F, + animationSpec = infiniteRepeatable( + animation = keyframes { + durationMillis = 1200 + 0.0F at 0 using LinearOutSlowInEasing + 1.0F at 300 using LinearOutSlowInEasing + 0.0F at 600 using LinearOutSlowInEasing + 0.0F at 1200 using LinearOutSlowInEasing + }, + repeatMode = RepeatMode.Restart + ) + ) + } + } + + val circlesValue = circles.map { it.value } + + val distance = LocalDensity.current.run { travelDistance.toPx() } + + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(spaceBetween) + ) { + circlesValue.forEach { value -> + Box(modifier = Modifier + .size(size = circleSize) + .graphicsLayer { + translationY = -value * distance + } + .border( + color = circleColor, + shape = CircleShape, + width = 1.dp, + ) + ) + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/PageTransitions.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/PageTransitions.kt deleted file mode 100644 index 1c6b29e..0000000 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/PageTransitions.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.abdullahalhakimi.smoothmotion.animations - -import androidx.compose.animation.core.LinearEasing -import androidx.compose.ui.Modifier -import androidx.compose.animation.* -import androidx.compose.animation.core.Easing -import androidx.compose.animation.core.tween -import androidx.compose.runtime.Composable - -@Composable -fun SlideTransition( - targetState: Boolean, - modifier: Modifier = Modifier, - enterDuration: Int = 300, - exitDuration: Int = 300, - enterEasing: Easing = LinearEasing, - exitEasing: Easing = LinearEasing, - content: @Composable () -> Unit -) { - AnimatedVisibility( - visible = targetState, - enter = slideInHorizontally( - initialOffsetX = { it }, - animationSpec = tween(enterDuration, easing = enterEasing) - ) + fadeIn(), - exit = slideOutHorizontally( - targetOffsetX = { -it }, - animationSpec = tween(exitDuration, easing = exitEasing) - ) + fadeOut(), - ) { - content() - } -} - -@Composable -fun FadeTransition( - targetState: Boolean, - modifier: Modifier = Modifier, - enterDuration: Int = 300, - exitDuration: Int = 300, - enterEasing: Easing = LinearEasing, - exitEasing: Easing = LinearEasing, - content: @Composable () -> Unit -) { - AnimatedVisibility( - visible = targetState, - enter = fadeIn(animationSpec = tween(enterDuration, easing = enterEasing)), - exit = fadeOut(animationSpec = tween(exitDuration, easing = exitEasing)), - ) { - content() - } -} - -@Composable -fun ZoomTransition( - targetState: Boolean, - modifier: Modifier = Modifier, - enterDuration: Int = 300, - exitDuration: Int = 300, - enterEasing: Easing = LinearEasing, - exitEasing: Easing = LinearEasing, - content: @Composable () -> Unit -) { - AnimatedVisibility( - visible = targetState, - enter = scaleIn( - animationSpec = tween(enterDuration, easing = enterEasing) - ) + fadeIn(), - exit = scaleOut( - animationSpec = tween(exitDuration, easing = exitEasing) - ) + fadeOut(), - ) { - content() - } -} diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/RotatingIcon.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/RotatingIcon.kt deleted file mode 100644 index 4ed0016..0000000 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/animations/RotatingIcon.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.abdullahalhakimi.smoothmotion.animations - -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Refresh -import androidx.compose.material3.Icon -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.unit.dp -import androidx.compose.animation.core.* - -@Composable -fun RotatingIcon( - modifier: Modifier = Modifier, - icon: @Composable () -> Unit = { Icon(Icons.Default.Refresh, contentDescription = null) }, - color: Color = Color.Red, - size: Int = 50, - rotationDuration: Int = 2000, - easing: Easing = LinearEasing -) { - val infiniteTransition = rememberInfiniteTransition(label = "RotatingIcon") - val rotation by infiniteTransition.animateFloat( - initialValue = 0f, - targetValue = 360f, - animationSpec = infiniteRepeatable( - animation = tween(rotationDuration, easing = easing), - repeatMode = RepeatMode.Restart - ), - label = "RotatingIcon", - ) - - Surface( - modifier = modifier - .size(size.dp) - .graphicsLayer(rotationZ = rotation), - color = color, - shape = CircleShape - ) { - icon() // This is where the icon content is displayed - } -} \ No newline at end of file diff --git a/library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/ProgressTitle.kt b/library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/Title.kt similarity index 82% rename from library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/ProgressTitle.kt rename to library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/Title.kt index 6bd161a..0016606 100644 --- a/library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/ProgressTitle.kt +++ b/library/src/main/java/com/abdullahalhakimi/smoothmotion/utils/Title.kt @@ -10,11 +10,11 @@ import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.dp @Composable -fun ProgressTitle(modifier: Modifier = Modifier, title: String) { +fun Title(modifier: Modifier = Modifier, title: String) { Text( modifier = modifier.padding(top = 15.dp), text = title, color = MaterialTheme.colorScheme.onBackground, - fontSize = TextUnit(16f, TextUnitType.Sp) + fontSize = TextUnit(14f, TextUnitType.Sp) ) } \ No newline at end of file