package com.example.ppb_kelompok2 // Yosep import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color 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 androidx.navigation.NavController import androidx.navigation.NavHostController import androidx.navigation.compose.* import com.example.ppb_kelompok2.ui.theme.PPB_Kelompok2Theme import kotlinx.coroutines.delay import kotlin.math.roundToInt import kotlin.random.Random // --- Main Activity --- class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { PPB_Kelompok2Theme { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { AppNavigationGraph() } } } } } // --- Navigation Graph --- @Composable fun AppNavigationGraph() { val navController = rememberNavController() NavHost(navController = navController, startDestination = "login") { composable("login") { LoginScreen(navController = navController) } composable("main") { MainAppScreen() } } } // --- Login Screen --- @Composable fun LoginScreen(navController: NavController) { Column( modifier = Modifier .fillMaxSize() .padding(16.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text("MindTrack AI", style = MaterialTheme.typography.headlineLarge, fontWeight = FontWeight.Bold) Spacer(modifier = Modifier.height(8.dp)) Text( "Lacak kesehatan mental Anda dengan kekuatan AI.", style = MaterialTheme.typography.bodyLarge, textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = 32.dp) ) Spacer(modifier = Modifier.height(32.dp)) Button( onClick = { navController.navigate("main") { popUpTo("login") { inclusive = true } } }, modifier = Modifier .fillMaxWidth() .padding(horizontal = 32.dp) ) { Icon(Icons.Default.AccountCircle, contentDescription = "Google Icon") // Placeholder for Google Icon Spacer(modifier = Modifier.width(8.dp)) Text("Masuk dengan Google") } } } // --- Main App Structure (with Bottom Navigation) --- sealed class Screen(val route: String, val label: String, val icon: ImageVector) { object Journal : Screen("journal", "Jurnal", Icons.Default.Book) object Assessment : Screen("assessment", "Penilaian", Icons.Default.Checklist) object CognitiveTest : Screen("cognitive_test", "Tes Kognitif", Icons.Default.SportsEsports) object History : Screen("history", "Riwayat & Grafik", Icons.Default.BarChart) } val bottomNavItems = listOf( Screen.Journal, Screen.Assessment, Screen.CognitiveTest, Screen.History ) @Composable fun MainAppScreen() { val navController = rememberNavController() Scaffold( bottomBar = { AppBottomNavigation(navController = navController) } ) { innerPadding -> AppNavHost(navController = navController, modifier = Modifier.padding(innerPadding)) } } @Composable fun AppBottomNavigation(navController: NavHostController) { NavigationBar { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route bottomNavItems.forEach { screen -> NavigationBarItem( icon = { Icon(screen.icon, contentDescription = screen.label) }, label = { Text(screen.label) }, selected = currentRoute == screen.route, onClick = { navController.navigate(screen.route) { popUpTo(navController.graph.startDestinationId) { saveState = true } launchSingleTop = true restoreState = true } } ) } } } @Composable fun AppNavHost(navController: NavHostController, modifier: Modifier = Modifier) { NavHost( navController = navController, startDestination = Screen.Journal.route, modifier = modifier.fillMaxSize() ) { composable(Screen.Journal.route) { JournalScreen() } composable(Screen.Assessment.route) { AssessmentScreen() } composable(Screen.CognitiveTest.route) { CognitiveTestScreen(navController) } composable(Screen.History.route) { HistoryScreen() } composable("memory_test") { MemoryTestScreen(navController) } composable("focus_test") { FocusTestScreen(navController) } composable("reaction_test") { ReactionSpeedTestScreen(navController) } } } // --- App Screens --- @Composable fun JournalScreen() { var journalText by remember { mutableStateOf("") } Column( modifier = Modifier .fillMaxSize() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Card(modifier = Modifier .fillMaxWidth() .padding(bottom = 16.dp)) { Column(modifier = Modifier.padding(16.dp)) { Text("Analisis AI", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) Spacer(modifier = Modifier.height(8.dp)) Text("Sentimen: Netral") Text("Emosi Terdeteksi: Tenang") } } OutlinedTextField( value = journalText, onValueChange = { journalText = it }, label = { Text("Tuliskan perasaanmu di sini...") }, modifier = Modifier .fillMaxWidth() .weight(1f) ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = { /* TODO: Implement save logic */ }, modifier = Modifier.fillMaxWidth() ) { Text("Simpan Jurnal") } } } @OptIn(ExperimentalMaterial3Api::class) @Composable fun AssessmentScreen() { val indicators = remember { listOf( "Mood Sedih", "Rasa Bersalah", "Menarik Diri Sosial", "Sulit Konsentrasi", "Kelelahan", "Pikiran Bunuh Diri" ) } val sliderValues = remember { mutableStateMapOf().apply { indicators.forEach { indicator -> put(indicator, 0f) } } } val totalScore = sliderValues.values.sum().toInt() val assessmentLevel = when (totalScore) { in 0..4 -> "Normal" in 5..9 -> "Ringan" in 10..14 -> "Sedang" else -> "Berat" } Scaffold( topBar = { TopAppBar(title = { Text("Penilaian Harian") }) } ) { innerPadding -> LazyColumn( modifier = Modifier .fillMaxSize() .padding(innerPadding) .padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { item { Card( modifier = Modifier.fillMaxWidth(), colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer) ) { Column( modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.Start ) { Text("Ringkasan Skor", style = MaterialTheme.typography.titleMedium) Spacer(modifier = Modifier.height(8.dp)) Text("Total Skor: $totalScore", style = MaterialTheme.typography.headlineMedium) Text("Tingkat: $assessmentLevel", style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold) } } } items(indicators) { indicatorName -> IndicatorItem( indicatorName = indicatorName, value = sliderValues[indicatorName] ?: 0f, onValueChange = { sliderValues[indicatorName] = it.roundToInt().toFloat() } ) } item { Button( onClick = { /* TODO: Implement finish logic */ }, modifier = Modifier.fillMaxWidth() ) { Text("Selesai") } } } } } @Composable fun IndicatorItem(indicatorName: String, value: Float, onValueChange: (Float) -> Unit) { val description = when (value.toInt()) { 0 -> "Tidak sama sekali" 1 -> "Beberapa hari" 2 -> "Lebih dari separuh hari" 3 -> "Hampir setiap hari" else -> "" } Card(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.padding(16.dp)) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Text(indicatorName, style = MaterialTheme.typography.titleMedium) Text( text = value.toInt().toString(), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.primary ) } Spacer(modifier = Modifier.height(8.dp)) Slider( value = value, onValueChange = onValueChange, valueRange = 0f..3f, steps = 2, modifier = Modifier.fillMaxWidth() ) Spacer(modifier = Modifier.height(4.dp)) Text( text = description, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.align(Alignment.CenterHorizontally) ) } } } @OptIn(ExperimentalMaterial3Api::class) @Composable fun CognitiveTestScreen(navController: NavController) { Column( modifier = Modifier .fillMaxSize() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { Text("Pilih Tes Kognitif", style = MaterialTheme.typography.headlineSmall) @Composable fun TestCard(title: String, description: String, icon: ImageVector, route: String) { Card( onClick = { navController.navigate(route) }, modifier = Modifier.fillMaxWidth() ) { Row( modifier = Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically ) { Icon(icon, contentDescription = null, modifier = Modifier.size(40.dp)) Spacer(Modifier.width(16.dp)) Column { Text(title, style = MaterialTheme.typography.titleMedium) Text(description, style = MaterialTheme.typography.bodySmall, color = Color.Gray) } } } } TestCard( title = "Tes Memori", description = "Uji memori jangka pendek Anda", icon = Icons.Default.Memory, route = "memory_test" ) TestCard( title = "Tes Fokus", description = "Uji kemampuan fokus & atensi", icon = Icons.Default.CenterFocusStrong, route = "focus_test" ) TestCard( title = "Tes Kecepatan Reaksi", description = "Uji kecepatan reaksi visual Anda", icon = Icons.Default.Speed, route = "reaction_test" ) } } // --- Cognitive Test Screens --- data class MemoryCard(val id: Int, val icon: ImageVector, var isFaceUp: Boolean = false, var isMatched: Boolean = false) enum class MemoryGameState { READY, PLAYING, FINISHED } @OptIn(ExperimentalMaterial3Api::class) @Composable fun MemoryTestScreen(navController: NavController) { val icons = listOf( Icons.Default.Favorite, Icons.Default.Star, Icons.Default.ThumbUp, Icons.Default.Spa, Icons.Default.Cloud, Icons.Default.Anchor ) var cards by remember { mutableStateOf(createShuffledCards(icons)) } var selectedCards by remember { mutableStateOf(listOf()) } var moves by remember { mutableIntStateOf(0) } var bestScore by remember { mutableStateOf(null) } var gameState by remember { mutableStateOf(MemoryGameState.READY) } LaunchedEffect(cards.all { it.isMatched }) { if (cards.all { it.isMatched } && gameState == MemoryGameState.PLAYING) { gameState = MemoryGameState.FINISHED if (bestScore == null || moves < bestScore!!) { bestScore = moves } } } LaunchedEffect(selectedCards) { if (selectedCards.size == 2) { val (first, second) = selectedCards if (first.icon == second.icon) { cards = cards.map { if (it.id == first.id || it.id == second.id) it.copy(isMatched = true) else it } } else { delay(1000) cards = cards.map { if (it.id == first.id || it.id == second.id) it.copy(isFaceUp = false) else it } } selectedCards = listOf() } } fun restartGame() { moves = 0 cards = createShuffledCards(icons) gameState = MemoryGameState.PLAYING } Scaffold( topBar = { TopAppBar( title = { Text("Tes Memori") }, navigationIcon = { IconButton(onClick = { navController.popBackStack() }) { Icon(Icons.Default.ArrowBack, contentDescription = "Kembali") } } ) } ) { innerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(innerPadding) .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { when (gameState) { MemoryGameState.READY -> { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { Text("Tes Memori", style = MaterialTheme.typography.headlineMedium) bestScore?.let { Text("Skor Terbaik: $it gerakan", style = MaterialTheme.typography.titleMedium) } Text( "Tes ini menguji memori jangka pendek Anda. Cocokkan semua kartu dengan jumlah gerakan sesedikit mungkin.", textAlign = TextAlign.Center ) Button(onClick = { gameState = MemoryGameState.PLAYING }) { Text("Mulai") } } } MemoryGameState.PLAYING, MemoryGameState.FINISHED -> { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) { Text("Gerakan: $moves", style = MaterialTheme.typography.bodyLarge) bestScore?.let { Text("Skor Terbaik: $it", style = MaterialTheme.typography.bodyLarge) } } Spacer(modifier = Modifier.height(16.dp)) LazyVerticalGrid( columns = GridCells.Fixed(3), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { items(cards) { card -> MemoryCardView(card = card, onCardClicked = { if (gameState == MemoryGameState.PLAYING && !card.isFaceUp && !card.isMatched && selectedCards.size < 2) { cards = cards.map { if (it.id == card.id) it.copy(isFaceUp = true) else it } selectedCards = selectedCards + card if (selectedCards.size == 1) moves++ } }) } } Spacer(modifier = Modifier.weight(1f)) if (gameState == MemoryGameState.FINISHED) { Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp)){ Text("Selesai!", style = MaterialTheme.typography.headlineMedium, color = MaterialTheme.colorScheme.primary) Button(onClick = { restartGame() }) { Icon(Icons.Default.Refresh, contentDescription = "Coba Lagi") Spacer(modifier = Modifier.width(8.dp)) Text("Coba Lagi") } } } } } } } } fun createShuffledCards(icons: List): List { return (icons + icons).mapIndexed { index, icon -> MemoryCard(id = index, icon = icon) }.shuffled() } @OptIn(ExperimentalMaterial3Api::class) @Composable fun MemoryCardView(card: MemoryCard, onCardClicked: () -> Unit) { Card( onClick = onCardClicked, modifier = Modifier.aspectRatio(1f), enabled = !card.isMatched, colors = CardDefaults.cardColors( containerColor = if (card.isFaceUp || card.isMatched) MaterialTheme.colorScheme.surfaceVariant else MaterialTheme.colorScheme.primary ) ) { Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { if (card.isFaceUp || card.isMatched) { Icon(card.icon, contentDescription = null, modifier = Modifier.size(40.dp)) } } } } enum class FocusGameState { READY, PLAYING, FINISHED } @OptIn(ExperimentalMaterial3Api::class) @Composable fun FocusTestScreen(navController: NavController) { var score by remember { mutableIntStateOf(0) } var highScore by remember { mutableIntStateOf(0) } val normalColor = MaterialTheme.colorScheme.onSurface var gridItems by remember { mutableStateOf(generateFocusGrid(normalColor)) } var gameState by remember { mutableStateOf(FocusGameState.READY) } var selectedDuration by remember { mutableIntStateOf(15) } var timeLeft by remember { mutableIntStateOf(selectedDuration) } LaunchedEffect(gameState) { if (gameState == FocusGameState.PLAYING) { timeLeft = selectedDuration while (timeLeft > 0) { delay(1000) timeLeft-- } if (timeLeft == 0) gameState = FocusGameState.FINISHED } else if (gameState == FocusGameState.FINISHED) { if (score > highScore) { highScore = score } } } fun newLevel() { gridItems = generateFocusGrid(normalColor) } fun restartGame() { score = 0 gameState = FocusGameState.READY newLevel() } Scaffold( topBar = { TopAppBar( title = { Text("Tes Fokus") }, navigationIcon = { IconButton(onClick = { navController.popBackStack() }) { Icon(Icons.Default.ArrowBack, contentDescription = "Kembali") } } ) } ) { innerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(innerPadding) .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { when (gameState) { FocusGameState.READY -> { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { Text("Tes Fokus", style = MaterialTheme.typography.headlineMedium) if (highScore > 0) { Text("Skor Tertinggi: $highScore", style = MaterialTheme.typography.titleMedium) } Text( "Tes ini menguji kemampuan fokus dan atensi Anda untuk mengidentifikasi perbedaan visual dengan cepat.", textAlign = TextAlign.Center ) Text("Pilih durasi waktu:") Row( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { val durations = listOf(15, 30, 60, 120) durations.forEach { duration -> val isSelected = selectedDuration == duration OutlinedButton( onClick = { selectedDuration = duration }, colors = if (isSelected) ButtonDefaults.outlinedButtonColors(containerColor = MaterialTheme.colorScheme.primaryContainer) else ButtonDefaults.outlinedButtonColors() ) { Text("${duration}s") } } } Button(onClick = { gameState = FocusGameState.PLAYING }) { Text("Mulai") } } } FocusGameState.PLAYING -> { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround, verticalAlignment = Alignment.CenterVertically ) { Text("Skor: $score", style = MaterialTheme.typography.bodyLarge) Text("Waktu: $timeLeft", style = MaterialTheme.typography.bodyLarge) } Spacer(modifier = Modifier.height(16.dp)) LazyVerticalGrid( columns = GridCells.Fixed(5), verticalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { items(gridItems.indices.toList()) { index -> val item = gridItems[index] Icon( imageVector = item.icon, contentDescription = null, modifier = Modifier .size(40.dp) .rotate(item.rotation) .clickable { if (item.isDistractor) { score++ newLevel() } else { if (score > 0) score-- } }, tint = item.color ) } } } FocusGameState.FINISHED -> { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { Text("Waktu Habis!", style = MaterialTheme.typography.headlineMedium) Text("Skor Akhir: $score", style = MaterialTheme.typography.bodyLarge) Text("Skor Tertinggi: $highScore", style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold) Button(onClick = { restartGame() }) { Text("Coba Lagi") } } } } } } } data class FocusItem(val icon: ImageVector, val color: Color, val rotation: Float, val isDistractor: Boolean) private fun generateFocusGrid(normalColor: Color): List { val gridSize = 25 val normalIcon = Icons.Default.Circle val distractorIndex = Random.nextInt(gridSize) val distractorType = Random.nextInt(3) val distractor: FocusItem val items = MutableList(gridSize) { FocusItem(normalIcon, normalColor, 0f, false) } when (distractorType) { 0 -> { // Different Icon distractor = FocusItem(Icons.Default.Star, normalColor, 0f, true) } 1 -> { // Different Color distractor = FocusItem(normalIcon, Color.Red, 0f, true) } else -> { // Different Rotation distractor = FocusItem(normalIcon, normalColor, 90f, true) // Use an icon that shows rotation items.replaceAll { it.copy(icon = Icons.Default.Navigation) } } } items[distractorIndex] = distractor return items } enum class ReactionGameState { READY, WAITING, ACTION, FINISHED } @OptIn(ExperimentalMaterial3Api::class) @Composable fun ReactionSpeedTestScreen(navController: NavController) { var state by remember { mutableStateOf(ReactionGameState.READY) } var startTime by remember { mutableLongStateOf(0L) } var reactionTime by remember { mutableLongStateOf(0L) } var bestTime by remember { mutableStateOf(null) } val backgroundColor by animateColorAsState( targetValue = when (state) { ReactionGameState.WAITING -> Color.Red.copy(alpha = 0.8f) ReactionGameState.ACTION -> Color.Green.copy(alpha = 0.8f) else -> MaterialTheme.colorScheme.surface }, animationSpec = tween(300), label = "ReactionBackgroundColor" ) val onScreenClick = { when (state) { ReactionGameState.WAITING -> { reactionTime = -1 // Too soon state = ReactionGameState.FINISHED } ReactionGameState.ACTION -> { val newReactionTime = System.currentTimeMillis() - startTime reactionTime = newReactionTime if (bestTime == null || newReactionTime < bestTime!!) { bestTime = newReactionTime } state = ReactionGameState.FINISHED } else -> { /* Clicks handled by buttons in READY and FINISHED states */ } } } LaunchedEffect(state) { if (state == ReactionGameState.WAITING) { delay(Random.nextLong(1500, 5500)) if (state == ReactionGameState.WAITING) { // Ensure state hasn't changed startTime = System.currentTimeMillis() state = ReactionGameState.ACTION } } } Scaffold( topBar = { TopAppBar( title = { Text("Tes Kecepatan Reaksi") }, navigationIcon = { IconButton(onClick = { navController.popBackStack() }) { Icon(Icons.Default.ArrowBack, contentDescription = "Kembali") } } ) } ) { innerPadding -> Box( modifier = Modifier .fillMaxSize() .padding(innerPadding) .background(backgroundColor) .clickable( enabled = state == ReactionGameState.WAITING || state == ReactionGameState.ACTION, onClick = onScreenClick ), contentAlignment = Alignment.Center ) { when (state) { ReactionGameState.READY -> { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.padding(16.dp) ) { Text("Tes Kecepatan Reaksi", style = MaterialTheme.typography.headlineMedium, color = MaterialTheme.colorScheme.onSurface) bestTime?.let { Text("Waktu Terbaik: $it ms", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface) } Text( "Tes ini mengukur kecepatan reaksi visual Anda. Tunggu layar berubah menjadi hijau, lalu tekan secepat mungkin.", textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.onSurface ) Button(onClick = { state = ReactionGameState.WAITING }) { Text("Mulai") } } } ReactionGameState.WAITING -> { Text("Tunggu sampai hijau...", fontSize = 24.sp, color = Color.White, fontWeight = FontWeight.Bold) } ReactionGameState.ACTION -> { Text("Tekan Sekarang!", fontSize = 24.sp, color = Color.White, fontWeight = FontWeight.Bold) } ReactionGameState.FINISHED -> { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.padding(16.dp) ) { val resultText = if (reactionTime == -1L) "Terlalu Cepat!" else "${reactionTime} ms" Text(resultText, fontSize = 48.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onSurface) bestTime?.let { Text("Waktu Terbaik: $it ms", fontSize = 20.sp, color = MaterialTheme.colorScheme.onSurface) } Button(onClick = { state = ReactionGameState.READY }) { Text("Coba Lagi") } } } } } } } @Composable fun HistoryScreen() { LazyColumn( modifier = Modifier .fillMaxSize() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp) ) { item { Text("Riwayat & Grafik", style = MaterialTheme.typography.headlineSmall) } item { GraphCard(title = "Tren Mood Mingguan") } item { GraphCard(title = "Perkembangan Skor Depresi") } item { Card(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.padding(16.dp)) { Text("Insight AI", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) Spacer(modifier = Modifier.height(8.dp)) Text("AI menemukan pola bahwa mood Anda cenderung menurun di akhir pekan.", style = MaterialTheme.typography.bodyMedium) } } } } } @Composable fun GraphCard(title: String) { Card(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.padding(16.dp)) { Text(title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) Spacer(modifier = Modifier.height(8.dp)) Box( modifier = Modifier .fillMaxWidth() .height(150.dp) .background(Color.LightGray.copy(alpha = 0.5f)) ) { Text("Area Grafik", modifier = Modifier.align(Alignment.Center), color = Color.Gray) } } } }