package com.suno.android.common_ui.components.banner import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import com.suno.android.common_ui.components.aura.auraBackground const val DISMISS_DRAG_THRESHOLD = 50 enum class ExitDirection { Up, Left, Right } /** * Pure pill-shaped banner component with aura background and swipe-to-dismiss. * Just provides the styling and gesture handling - content is fully customizable. * * @param modifier Modifier to be applied to the banner * @param onClick Callback when the banner body is clicked * @param onDismiss Callback when the banner is swiped to dismiss (up, left, or right) * @param content Composable content for the entire banner interior with BoxScope for alignment */ @Composable fun AuraBanner( modifier: Modifier = Modifier, onClick: () -> Unit, onDismiss: (exitDirection: ExitDirection) -> Unit, content: @Composable BoxScope.() -> Unit, ) { Box( modifier = modifier .clip(RoundedCornerShape(100.dp)) .auraBackground() .background(Color.Black.copy(alpha = 0.5f)) .fillMaxWidth() .height(72.dp) .pointerInput(Unit) { var totalDragY = 0f var totalDragX = 0f detectDragGestures( onDragStart = { totalDragY = 0f totalDragX = 0f }, onDragEnd = { var dismissDirection: ExitDirection? = null if (totalDragY < -DISMISS_DRAG_THRESHOLD) { dismissDirection = ExitDirection.Up } else if (totalDragX < -DISMISS_DRAG_THRESHOLD) { dismissDirection = ExitDirection.Left } else if (totalDragX > DISMISS_DRAG_THRESHOLD) { dismissDirection = ExitDirection.Right } dismissDirection?.let { onDismiss.invoke(dismissDirection) } }, ) { _, dragAmount -> totalDragY += dragAmount.y totalDragX += dragAmount.x } } .clickable(onClick = onClick) .padding(horizontal = 16.dp), contentAlignment = Alignment.Center, ) { content() } }