package com.craigvg.lichun_android.ui.screens.home.components import androidx.compose.animation.core.* 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.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.craigvg.lichun_android.R import com.craigvg.lichun_android.ui.theme.AppColors import com.craigvg.lichun_android.ui.theme.AppSpacing import com.craigvg.lichun_android.ui.theme.AppTypography /** * Avatar + name + level display with floating/breathing animations * Ported from iOS AvatarCard.swift */ @Composable fun MainCharacterView( imageUrl: String, name: String, age: Int, mood: String, onTap: () -> Unit = {} ) { // Floating animation (2.5s easeInOut repeat) val infiniteTransition = rememberInfiniteTransition(label = "avatar") val floatingOffset by infiniteTransition.animateFloat( initialValue = 0f, targetValue = -5f, animationSpec = infiniteRepeatable( animation = tween(2500, easing = EaseInOut), repeatMode = RepeatMode.Reverse ), label = "floating" ) // Breathing animation (3.0s scale repeat) val breathingScale by infiniteTransition.animateFloat( initialValue = 1.0f, targetValue = 1.05f, animationSpec = infiniteRepeatable( animation = tween(3000, easing = EaseInOut), repeatMode = RepeatMode.Reverse ), label = "breathing" ) Card( modifier = Modifier .fillMaxWidth() .clickable(onClick = onTap), shape = RoundedCornerShape(AppSpacing.cornerRadius), colors = CardDefaults.cardColors(containerColor = AppColors.surfaceElevated) ) { Column( modifier = Modifier .fillMaxWidth() .padding(AppSpacing.md), horizontalAlignment = Alignment.CenterHorizontally ) { Box( modifier = Modifier .graphicsLayer { translationY = floatingOffset } .scale(breathingScale) ) { com.craigvg.lichun_android.ui.components.images.CharacterAvatar( imageUrl = imageUrl, firstName = name.split(" ").firstOrNull() ?: "", lastName = name.split(" ").getOrNull(1) ?: "", size = AppSpacing.avatarLarge ) } Spacer(modifier = Modifier.height(AppSpacing.sm)) Text( text = name.ifEmpty { stringResource(R.string.new_character) }, style = AppTypography.headline, color = AppColors.primaryText ) if (age > 0) { Text( text = stringResource(R.string.age_format, age), style = AppTypography.caption, color = AppColors.secondaryText ) } if (mood.isNotEmpty()) { Spacer(modifier = Modifier.height(4.dp)) Text( text = stringResource(R.string.feeling_format, mood), style = AppTypography.caption, color = AppColors.accent ) } } } }