package com.craigvg.lichun_android.ui.components.overlays import androidx.compose.animation.core.* import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.rotate import kotlin.math.cos import kotlin.math.sin import kotlin.random.Random private data class ConfettiParticle( val color: Color, val startX: Float, val speed: Float, val angle: Float, val spin: Float, val size: Float, val isHeart: Boolean = false ) @Composable fun ConfettiView( modifier: Modifier = Modifier, isActive: Boolean = true ) { if (!isActive) return val particles = remember { val colors = listOf( Color(0xFFFFB4D2), // Soft pink Color(0xFFFFD4AA), // Soft orange Color(0xFFFFF0AA), // Soft yellow Color(0xFFC4B5FD), // Soft purple Color(0xFFFF9BBD), // Pink Color(0xFFFFA0C4) // Rose ) List(60) { ConfettiParticle( color = colors.random(), startX = Random.nextFloat(), speed = Random.nextFloat() * 200f + 100f, angle = Random.nextFloat() * 0.5f - 0.25f, spin = Random.nextFloat() * 720f - 360f, size = Random.nextFloat() * 8f + 4f, isHeart = Random.nextFloat() < 0.15f ) } } val infiniteTransition = rememberInfiniteTransition(label = "confetti") val progress by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(4000, easing = LinearEasing), repeatMode = RepeatMode.Restart ), label = "confettiProgress" ) Canvas(modifier = modifier.fillMaxSize()) { val w = size.width val h = size.height particles.forEach { p -> val y = (progress * p.speed * 4f) % (h + 100f) - 50f val x = p.startX * w + sin(y / 80f + p.angle * 10f) * 40f val rotation = progress * p.spin rotate(rotation, pivot = Offset(x, y)) { if (p.isHeart) { // Simple heart as two overlapping circles + triangle drawCircle( color = p.color.copy(alpha = (1f - y / h).coerceIn(0.2f, 0.9f)), radius = p.size / 2f, center = Offset(x, y) ) } else { drawRect( color = p.color.copy(alpha = (1f - y / h).coerceIn(0.2f, 0.9f)), topLeft = Offset(x - p.size / 2, y - p.size / 2), size = Size(p.size, p.size * 1.3f) ) } } } } }