package com.craigvg.lichun_android.ui.screens.character import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.hilt.navigation.compose.hiltViewModel import com.craigvg.lichun_android.ui.screens.character.components.* 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.PlayerViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle /** * Detail view for viewing NPC character information and interactions. * Ported from iOS PersonDetailView.swift */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun PersonDetailScreen( personId: String, playerViewModel: PlayerViewModel = hiltViewModel(), onBack: () -> Unit = {}, onStartChat: (String) -> Unit = {} ) { val player by playerViewModel.player.collectAsStateWithLifecycle() val person = remember(player.r, personId) { player.r.find { it.id == personId } } LaunchedEffect(personId) { playerViewModel.retrievePerson(personId) } Scaffold( topBar = { TopAppBar( title = { Text("Profile", style = AppTypography.headline) }, navigationIcon = { IconButton(onClick = onBack) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back", tint = AppColors.primaryText ) } }, colors = TopAppBarDefaults.topAppBarColors( containerColor = AppColors.surfaceElevated ) ) }, containerColor = AppColors.background ) { paddingValues -> if (person == null) { var showTimeout by remember { mutableStateOf(false) } LaunchedEffect(Unit) { kotlinx.coroutines.delay(5000) showTimeout = true } Box( modifier = Modifier .fillMaxSize() .padding(paddingValues), contentAlignment = Alignment.Center ) { if (showTimeout) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text("Person not found", style = AppTypography.headline, color = AppColors.secondaryText) Spacer(modifier = Modifier.height(AppSpacing.sm)) Button(onClick = onBack) { Text("Go Back") } } } else { CircularProgressIndicator(color = AppColors.primary) } } } else { LazyColumn( modifier = Modifier .fillMaxSize() .padding(paddingValues) .background( Brush.verticalGradient( colors = listOf(AppColors.background, AppColors.surfaceSubtle) ) ), horizontalAlignment = Alignment.CenterHorizontally, contentPadding = PaddingValues(AppSpacing.lg), verticalArrangement = Arrangement.spacedBy(AppSpacing.lg) ) { item { Spacer(modifier = Modifier.height(AppSpacing.md)) } // Profile header with avatar, name, affinity, info pills item { ProfileHeader(person = person) } // Bio if (person.bio.isNotEmpty()) { item { Text( text = person.bio, style = AppTypography.body, color = AppColors.secondaryText, modifier = Modifier.padding(horizontal = AppSpacing.md) ) } } // Life story (about, education, career) item { AccordionSection(title = "About", initiallyExpanded = true) { LifeStorySection(person = person) } } // Stats & health item { AccordionSection(title = "Stats & Health") { StatsHealthSection(person = person) } } // Personality & interests item { AccordionSection(title = "Personality & Interests") { PersonalitySection(person = person) } } // Relationships if (person.relationships.isNotEmpty()) { item { AccordionSection(title = "Relationships") { RelationshipSection(relationships = person.relationships) } } } // Items / inventory if (person.items.isNotEmpty()) { item { AccordionSection(title = "Inventory") { ItemsSection(person = person) } } } // Actions item { ActionsSection(personId = person.id, onStartChat = onStartChat) } item { Spacer(modifier = Modifier.height(AppSpacing.xl)) } } } } }