package com.craigvg.lichun_android.ui.screens.retention import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import com.craigvg.lichun_android.domain.models.Achievement import com.craigvg.lichun_android.ui.theme.AppColors import com.craigvg.lichun_android.ui.theme.AppSpacing import com.craigvg.lichun_android.ui.theme.AppTypography import com.craigvg.lichun_android.viewmodel.GameStateViewModel import java.text.SimpleDateFormat import java.util.* import androidx.lifecycle.compose.collectAsStateWithLifecycle /** * Achievement detail screen showing full achievement info with progress * Ported from iOS AchievementDetailView.swift */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun AchievementDetailScreen( achievementId: String, gameStateViewModel: GameStateViewModel = hiltViewModel(), onBack: () -> Unit = {} ) { val achievements by gameStateViewModel.achievements.collectAsStateWithLifecycle() val achievement = achievements.find { it.id == achievementId } Scaffold( topBar = { TopAppBar( title = {}, navigationIcon = { IconButton(onClick = onBack) { Icon( imageVector = Icons.Default.Close, contentDescription = "Close", tint = AppColors.secondaryText ) } }, colors = TopAppBarDefaults.topAppBarColors( containerColor = AppColors.background ) ) }, containerColor = AppColors.background ) { paddingValues -> if (achievement == null) { Box( modifier = Modifier .fillMaxSize() .padding(paddingValues), contentAlignment = Alignment.Center ) { CircularProgressIndicator(color = AppColors.primary) } } else { Column( modifier = Modifier .fillMaxSize() .padding(paddingValues) .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(modifier = Modifier.height(AppSpacing.xl)) // Icon with glow AchievementIcon(achievement) Spacer(modifier = Modifier.height(AppSpacing.lg)) // Name Text( text = achievement.name, style = AppTypography.displayTitle.copy(fontSize = 28.sp), color = AppColors.primaryText, textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = AppSpacing.lg) ) // Congrats text for unlocked if (achievement.unlocked) { Spacer(modifier = Modifier.height(AppSpacing.xs)) Text( text = "Congratulations! You earned this!", style = AppTypography.body.copy(fontStyle = FontStyle.Italic), color = achievement.category.color ) } Spacer(modifier = Modifier.height(AppSpacing.sm)) // Category badge CategoryBadge(achievement) Spacer(modifier = Modifier.height(AppSpacing.md)) // Description Text( text = achievement.description, style = AppTypography.body, color = AppColors.secondaryText, textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = AppSpacing.lg) ) Spacer(modifier = Modifier.height(AppSpacing.md)) HorizontalDivider( modifier = Modifier.padding(horizontal = AppSpacing.lg), color = AppColors.surfaceSubtle ) Spacer(modifier = Modifier.height(AppSpacing.md)) // Requirement card RequirementCard(achievement) // Progress card (unlocked achievements skip this) if (!achievement.unlocked && achievement.progress != null && achievement.progressRequired != null) { Spacer(modifier = Modifier.height(AppSpacing.md)) ProgressCard(achievement) } Spacer(modifier = Modifier.height(AppSpacing.md)) // Reward card RewardCard(achievement) // Unlock date if (achievement.unlocked && achievement.unlockedAt != null) { Spacer(modifier = Modifier.height(AppSpacing.md)) UnlockDateSection(achievement.unlockedAt) } Spacer(modifier = Modifier.height(AppSpacing.xl)) } } } } @Composable private fun AchievementIcon(achievement: Achievement) { Box(contentAlignment = Alignment.Center) { // Outer glow for unlocked if (achievement.unlocked) { Box( modifier = Modifier .size(140.dp) .clip(CircleShape) .background(achievement.category.color.copy(alpha = 0.15f)) ) } // Circle background Box( modifier = Modifier .size(120.dp) .clip(CircleShape) .background( Brush.linearGradient( colors = if (achievement.unlocked) { listOf( achievement.category.color.copy(alpha = 0.2f), achievement.category.color.copy(alpha = 0.1f) ) } else { listOf( Color(0xFFF2F2F2), Color(0xFFEBEBEB) ) } ) ), contentAlignment = Alignment.Center ) { Icon( imageVector = if (achievement.unlocked) Icons.Default.EmojiEvents else Icons.Default.Lock, contentDescription = null, tint = if (achievement.unlocked) achievement.category.color else AppColors.disabledText.copy(alpha = 0.4f), modifier = Modifier.size(60.dp) ) } // Sparkles for unlocked if (achievement.unlocked) { val offsets = listOf( Pair(-50f, -50f), Pair(50f, -40f), Pair(-40f, 50f) ) offsets.forEach { (x, y) -> Icon( imageVector = Icons.Default.AutoAwesome, contentDescription = null, tint = Color(0xFFFFD700).copy(alpha = 0.8f), modifier = Modifier .size(16.dp) .offset(x = x.dp, y = y.dp) ) } } } } @Composable private fun CategoryBadge(achievement: Achievement) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(AppSpacing.xs), modifier = Modifier .clip(RoundedCornerShape(AppSpacing.pillCornerRadius)) .background(achievement.category.color.copy(alpha = 0.15f)) .padding(horizontal = AppSpacing.md, vertical = AppSpacing.sm) ) { Icon( imageVector = when (achievement.category) { com.craigvg.lichun_android.domain.models.AchievementCategory.CAREER -> Icons.Default.Work com.craigvg.lichun_android.domain.models.AchievementCategory.RELATIONSHIPS -> Icons.Default.Favorite com.craigvg.lichun_android.domain.models.AchievementCategory.EDUCATION -> Icons.Default.School com.craigvg.lichun_android.domain.models.AchievementCategory.WEALTH -> Icons.Default.AttachMoney com.craigvg.lichun_android.domain.models.AchievementCategory.ACTIVITIES -> Icons.Default.DirectionsRun }, contentDescription = null, tint = achievement.category.color, modifier = Modifier.size(14.dp) ) Text( text = achievement.category.displayName, style = AppTypography.body, color = achievement.category.color ) } } @Composable private fun RequirementCard(achievement: Achievement) { Card( modifier = Modifier .fillMaxWidth() .padding(horizontal = AppSpacing.md), shape = RoundedCornerShape(AppSpacing.cornerRadius), colors = CardDefaults.cardColors(containerColor = AppColors.surfaceElevated) ) { Column( modifier = Modifier.padding(AppSpacing.md) ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Icon( imageVector = Icons.Default.CheckCircle, contentDescription = null, tint = AppColors.primary, modifier = Modifier.size(20.dp) ) Text( text = "Requirement", style = AppTypography.headline, color = AppColors.primaryText ) } Spacer(modifier = Modifier.height(AppSpacing.sm)) Text( text = achievement.requirement, style = AppTypography.body, color = AppColors.secondaryText ) } } } @Composable private fun ProgressCard(achievement: Achievement) { val progress = achievement.progress ?: 0 val required = achievement.progressRequired ?: 1 val percentage = achievement.progressPercentage Card( modifier = Modifier .fillMaxWidth() .padding(horizontal = AppSpacing.md), shape = RoundedCornerShape(AppSpacing.cornerRadius), colors = CardDefaults.cardColors( containerColor = achievement.category.color.copy(alpha = 0.05f) ), border = CardDefaults.outlinedCardBorder().copy( brush = Brush.linearGradient( colors = listOf( achievement.category.color.copy(alpha = 0.2f), achievement.category.color.copy(alpha = 0.1f) ) ) ) ) { Column( modifier = Modifier.padding(AppSpacing.md), horizontalAlignment = Alignment.CenterHorizontally ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp) ) { Icon( imageVector = Icons.Default.BarChart, contentDescription = null, tint = achievement.category.color, modifier = Modifier.size(14.dp) ) Text( text = "Your Progress", style = AppTypography.headline, color = AppColors.primaryText ) } Spacer(modifier = Modifier.height(AppSpacing.sm)) Text( text = "$progress / $required", style = AppTypography.displayTitle.copy(fontSize = 36.sp), color = AppColors.primaryText ) Spacer(modifier = Modifier.height(AppSpacing.sm)) // Progress bar Box( modifier = Modifier .fillMaxWidth() .height(16.dp) .clip(RoundedCornerShape(8.dp)) .background(Color(0xFFF2F2F2)) ) { Box( modifier = Modifier .fillMaxWidth(percentage) .fillMaxHeight() .clip(RoundedCornerShape(8.dp)) .background( Brush.horizontalGradient( colors = listOf( achievement.category.color, achievement.category.color.copy(alpha = 0.7f) ) ) ) .shadow(4.dp, RoundedCornerShape(8.dp)) ) } Spacer(modifier = Modifier.height(AppSpacing.sm)) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Text( text = "${(percentage * 100).toInt()}% Complete", style = AppTypography.body, color = AppColors.primaryText ) Text( text = "Keep going!", style = AppTypography.caption.copy(fontStyle = FontStyle.Italic), color = achievement.category.color ) } } } } @Composable private fun RewardCard(achievement: Achievement) { val goldColors = listOf(Color(0xFFFFD700), Color(0xFFD9A613)) Card( modifier = Modifier .fillMaxWidth() .padding(horizontal = AppSpacing.md) .shadow( elevation = 8.dp, shape = RoundedCornerShape(AppSpacing.cornerRadius), ambientColor = Color(0xFFFFD700).copy(alpha = 0.2f) ), shape = RoundedCornerShape(AppSpacing.cornerRadius), colors = CardDefaults.cardColors( containerColor = Color.Transparent ) ) { Box( modifier = Modifier .background( Brush.linearGradient( colors = listOf( Color(0xFFFFD700).copy(alpha = 0.15f), Color(0xFFFFA500).copy(alpha = 0.1f) ) ) ) ) { Column( modifier = Modifier .fillMaxWidth() .padding(AppSpacing.md), horizontalAlignment = Alignment.CenterHorizontally ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp) ) { Icon( imageVector = Icons.Default.Star, contentDescription = null, tint = Color(0xFFFFD700), modifier = Modifier.size(16.dp) ) Text( text = "Reward", style = AppTypography.headline, color = AppColors.primaryText ) } Spacer(modifier = Modifier.height(AppSpacing.sm)) Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { Text( text = "${achievement.reward}", style = AppTypography.displayTitle.copy(fontSize = 40.sp), color = Color(0xFFFFD700) ) Icon( imageVector = Icons.Default.Diamond, contentDescription = null, tint = Color(0xFFFFD700), modifier = Modifier.size(32.dp) ) } } } } } @Composable private fun UnlockDateSection(unlockedAt: Long) { val dateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()) val dateString = dateFormat.format(Date(unlockedAt)) Column( horizontalAlignment = Alignment.CenterHorizontally ) { Icon( imageVector = Icons.Default.CalendarToday, contentDescription = null, tint = AppColors.secondaryText, modifier = Modifier.size(20.dp) ) Spacer(modifier = Modifier.height(4.dp)) Text( text = "Unlocked", style = AppTypography.caption, color = AppColors.secondaryText ) Text( text = dateString, style = AppTypography.body, color = AppColors.primaryText ) } }