@@ -7,6 +7,11 @@ import android.graphics.Rect
77import android.net.Uri
88import androidx.compose.animation.AnimatedVisibility
99import androidx.compose.animation.core.Animatable
10+ import androidx.compose.animation.core.FastOutSlowInEasing
11+ import androidx.compose.animation.core.RepeatMode
12+ import androidx.compose.animation.core.animateFloat
13+ import androidx.compose.animation.core.infiniteRepeatable
14+ import androidx.compose.animation.core.rememberInfiniteTransition
1015import androidx.compose.animation.core.tween
1116import androidx.compose.animation.fadeIn
1217import androidx.compose.animation.fadeOut
@@ -63,6 +68,7 @@ import androidx.compose.ui.Modifier
6368import androidx.compose.ui.draw.shadow
6469import androidx.compose.ui.geometry.Offset
6570import androidx.compose.ui.graphics.Color
71+ import androidx.compose.ui.graphics.graphicsLayer
6672import androidx.compose.ui.input.pointer.pointerInput
6773import androidx.compose.ui.layout.onGloballyPositioned
6874import androidx.compose.ui.layout.positionInRoot
@@ -782,37 +788,57 @@ private fun RecordingTooltip(
782788 }
783789 TextButton (onClick = onDismiss) { Text (" Close" ) }
784790 }
785- ActiveRecordingCard (durationMs)
786791 ActiveTimelinePreview (state.intent, durationMs)
787- Button (
788- modifier = Modifier .fillMaxWidth().height(48 .dp),
789- colors = ButtonDefaults .buttonColors(containerColor = BuddyRed ),
790- onClick = onStopAndAnalyze,
791- ) {
792- BuddyButtonText (" Stop and Analyze" )
793- }
792+ BreathingStopButton (onClick = onStopAndAnalyze)
794793 }
795794 }
796795}
797796
798797@Composable
799- private fun ActiveRecordingCard (durationMs : Long ) {
800- Card (
801- colors = CardDefaults .cardColors(containerColor = BuddyRed .copy(alpha = 0.10f )),
802- border = CardDefaults .outlinedCardBorder(),
803- ) {
804- Row (
805- modifier = Modifier .fillMaxWidth().padding(16 .dp),
806- horizontalArrangement = Arrangement .SpaceBetween ,
807- verticalAlignment = Alignment .CenterVertically ,
798+ private fun BreathingStopButton (onClick : () -> Unit ) {
799+ val transition = rememberInfiniteTransition(label = " buddy-stop-button" )
800+ val haloScale by
801+ transition.animateFloat(
802+ initialValue = 1.0f ,
803+ targetValue = 1.04f ,
804+ animationSpec =
805+ infiniteRepeatable(
806+ animation = tween(durationMillis = 1400 , easing = FastOutSlowInEasing ),
807+ repeatMode = RepeatMode .Reverse ,
808+ ),
809+ label = " buddy-stop-button-halo-scale" ,
810+ )
811+ val haloAlpha by
812+ transition.animateFloat(
813+ initialValue = 0.12f ,
814+ targetValue = 0.24f ,
815+ animationSpec =
816+ infiniteRepeatable(
817+ animation = tween(durationMillis = 1400 , easing = FastOutSlowInEasing ),
818+ repeatMode = RepeatMode .Reverse ,
819+ ),
820+ label = " buddy-stop-button-halo-alpha" ,
821+ )
822+ val shape = RoundedCornerShape (24 .dp)
823+
824+ Box (modifier = Modifier .fillMaxWidth().height(48 .dp)) {
825+ Box (
826+ modifier =
827+ Modifier .fillMaxSize()
828+ .graphicsLayer {
829+ scaleX = haloScale
830+ scaleY = haloScale
831+ alpha = haloAlpha
832+ }
833+ .background(BuddyRed , shape)
834+ )
835+ Button (
836+ modifier = Modifier .fillMaxSize(),
837+ colors = ButtonDefaults .buttonColors(containerColor = BuddyRed ),
838+ shape = shape,
839+ onClick = onClick,
808840 ) {
809- Text (" ● Recording" , color = BuddyRed , fontWeight = FontWeight .Bold )
810- Text (
811- formatElapsed(durationMs),
812- fontFamily = FontFamily .Monospace ,
813- fontWeight = FontWeight .Bold ,
814- color = BuddyInk ,
815- )
841+ BuddyButtonText (" Stop and Analyze" )
816842 }
817843 }
818844}
0 commit comments