package com.craigvg.lichun_android.ui.screens.character.components import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.craigvg.lichun_android.domain.models.Person import com.craigvg.lichun_android.ui.components.images.CharacterAvatar import com.craigvg.lichun_android.ui.components.stats.CozyStatBar import com.craigvg.lichun_android.ui.navigation.personAvatarSharedKey import com.craigvg.lichun_android.ui.navigation.sharedElementKey import com.craigvg.lichun_android.ui.theme.AppColors import com.craigvg.lichun_android.ui.theme.AppSpacing import com.craigvg.lichun_android.ui.theme.AppTypography /** * Profile header with avatar, name, affinity bar, and info pills. * Ported from iOS ProfileHeader.swift */ @Composable fun ProfileHeader( person: Person, modifier: Modifier = Modifier ) { Column( modifier = modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(AppSpacing.lg) ) { // Avatar with mood overlay Box(contentAlignment = Alignment.BottomEnd) { CharacterAvatar( imageUrl = person.image, firstName = person.firstname, lastName = person.lastname, size = AppSpacing.avatarLarge, modifier = Modifier.sharedElementKey(personAvatarSharedKey(person.id)) ) if (person.mood.isNotEmpty()) { Text( text = moodEmoji(person.mood), fontSize = 28.sp, modifier = Modifier.offset(x = 8.dp, y = 8.dp) ) } } // Name and relationship Column(horizontalAlignment = Alignment.CenterHorizontally) { Text( text = person.fullName, fontSize = 28.sp, fontWeight = FontWeight.Bold, color = AppColors.primaryText, textAlign = TextAlign.Center ) Row( horizontalArrangement = Arrangement.spacedBy(AppSpacing.sm), verticalAlignment = Alignment.CenterVertically ) { val relType = primaryRelationshipType(person.relationships) if (relType.isNotEmpty()) { Text(text = relType, style = AppTypography.body, color = AppColors.primary, fontWeight = FontWeight.Medium) Text(text = "•", style = AppTypography.caption, color = AppColors.secondaryText.copy(alpha = 0.5f)) } Text(text = "${person.ageYears} years old", style = AppTypography.body, color = AppColors.secondaryText) } } // Affinity bar Column( modifier = Modifier.padding(horizontal = AppSpacing.xl), verticalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp)) { Icon(Icons.Default.Favorite, contentDescription = null, tint = AppColors.primary, modifier = Modifier.size(14.dp)) Text("Affinity", style = AppTypography.captionBold, color = AppColors.secondaryText) } Text("${person.affinity}%", style = AppTypography.captionBold, fontWeight = FontWeight.Bold, color = affinityColor(person.affinity)) } CozyStatBar( label = "", value = person.affinity / 100f, color = affinityColor(person.affinity) ) } // Info pills Row( modifier = Modifier.padding(horizontal = AppSpacing.md), horizontalArrangement = Arrangement.spacedBy(AppSpacing.sm) ) { InfoPill(icon = Icons.Default.Person, text = lifeStage(person.ageYears)) InfoPill(icon = Icons.Default.LocationOn, text = person.location.ifEmpty { "Unknown" }) InfoPill(icon = Icons.Default.Schedule, text = person.intraDayMessage.ifEmpty { "Idle" }) } } } @Composable private fun InfoPill(icon: ImageVector, text: String) { Row( modifier = Modifier .background(AppColors.surfaceElevated, RoundedCornerShape(50)) .border(1.dp, AppColors.primary.copy(alpha = 0.2f), RoundedCornerShape(50)) .padding(horizontal = AppSpacing.sm, vertical = AppSpacing.xs), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Icon(icon, contentDescription = null, tint = AppColors.primary, modifier = Modifier.size(12.dp)) Text(text, style = AppTypography.caption, color = AppColors.primaryText, maxLines = 1) } } private fun moodEmoji(mood: String): String = when (mood.lowercase()) { "happy" -> "😊"; "calm" -> "😌"; "stressed" -> "😰"; "exhausted" -> "😩" "fulfilled" -> "🥰"; "depressed" -> "😢"; "angry" -> "😠"; "excited" -> "🤩" "anxious" -> "😬"; "content" -> "😊"; else -> "😐" } private fun affinityColor(affinity: Int) = when { affinity >= 80 -> AppColors.success affinity >= 50 -> AppColors.primary affinity >= 25 -> AppColors.warning else -> AppColors.error } private fun primaryRelationshipType(relationships: List): String { val map = mapOf( "partner" to "Partner", "spouse" to "Partner", "parent" to "Parent", "child" to "Child", "sibling" to "Sibling", "friend" to "Friend", "classmate" to "Classmate", "coworker" to "Coworker", "crush" to "Crush" ) for ((key, label) in map) { if (relationships.any { it.contains(key) }) return label } return relationships.firstOrNull()?.replaceFirstChar { it.uppercase() } ?: "Acquaintance" } private fun lifeStage(age: Int): String = when (age) { in 0..0 -> "Baby"; in 1..3 -> "Toddler"; in 4..12 -> "Child" in 13..17 -> "Teen"; in 18..29 -> "Young Adult"; in 30..59 -> "Adult" in 60..79 -> "Senior"; else -> "Elder" }