Pertemuan 10 - APLIKASI WORD SCRAMBLE

 Nama : Armadya Hermawan

NRP : 5025211243

Kelas  : PPB A

@Composable
fun WordGuessingGameScreen(viewModel: WordGameViewModel = viewModel()) {
    val uiState by viewModel.gameState.collectAsState()
    val largePadding = dimensionResource(R.dimen.padding_large)
    val smallPadding = dimensionResource(R.dimen.padding_small)

    Box(
        modifier = Modifier
            .fillMaxSize()
            .statusBarsPadding()
            .safeDrawingPadding()
            .padding(largePadding)
    ) {
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.SpaceBetween
        ) {
            item {
                GameHeaderSection(
                    appTitle = stringResource(R.string.app_name),
                    currentRound = uiState.roundNumber,
                    totalRounds = uiState.totalRounds
                )
            }
            
            item {
                WordDisplayCard(
                    scrambledWord = uiState.scrambledWord,
                    wordHint = uiState.wordHint,
                    isAnimating = uiState.isWordAnimating,
                    modifier = Modifier.padding(vertical = smallPadding)
                )
            }
            
            item {
                UserInputSection(
                    playerAnswer = uiState.playerInput,
                    onAnswerChange = { viewModel.updatePlayerInput(it) },
                    onSubmitAnswer = { viewModel.validateAnswer() },
                    hasError = uiState.hasInputError,
                    errorMessage = uiState.errorMessage,
                    isEnabled = !uiState.isProcessing
                )
            }
            
            item {
                ActionButtonsRow(
                    onSubmit = { viewModel.validateAnswer() },
                    onSkip = { viewModel.skipCurrentWord() },
                    onHint = { viewModel.showHint() },
                    isProcessing = uiState.isProcessing,
                    canShowHint = uiState.hintsRemaining > 0
                )
            }
            
            item {
                ScoreboardCard(
                    currentScore = uiState.playerScore,
                    hintsUsed = uiState.hintsUsed,
                    wordsCompleted = uiState.wordsCompleted,
                    modifier = Modifier.padding(top = largePadding)
                )
            }
        }
        
        if (uiState.showGameOverDialog) {
            GameCompletionDialog(
                finalScore = uiState.playerScore,
                totalWords = uiState.wordsCompleted,
                onRestart = { viewModel.restartGame() },
                onExit = { viewModel.exitGame() }
            )
        }
    }
}

@Composable
fun GameHeaderSection(
    appTitle: String,
    currentRound: Int,
    totalRounds: Int,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = appTitle,
            style = typography.headlineLarge,
            color = colorScheme.primary,
            fontWeight = FontWeight.Bold
        )
        
        Spacer(modifier = Modifier.height(8.dp))
        
        LinearProgressIndicator(
            progress = currentRound.toFloat() / totalRounds.toFloat(),
            modifier = Modifier
                .fillMaxWidth()
                .height(4.dp)
                .clip(RoundedCornerShape(2.dp)),
            color = colorScheme.secondary
        )
        
        Text(
            text = "Round $currentRound of $totalRounds",
            style = typography.labelMedium,
            color = colorScheme.onSurfaceVariant,
            modifier = Modifier.padding(top = 4.dp)
        )
    }
}

@Composable
fun WordDisplayCard(
    scrambledWord: String,
    wordHint: String?,
    isAnimating: Boolean,
    modifier: Modifier = Modifier
) {
    Card(
        modifier = modifier.fillMaxWidth(),
        shape = RoundedCornerShape(16.dp),
        colors = CardDefaults.cardColors(
            containerColor = colorScheme.primaryContainer
        ),
        elevation = CardDefaults.cardElevation(
            defaultElevation = 8.dp
        )
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(24.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "Guess this word:",
                style = typography.titleSmall,
                color = colorScheme.onPrimaryContainer
            )
            
            Spacer(modifier = Modifier.height(16.dp))
            
            AnimatedContent(
                targetState = scrambledWord,
                transitionSpec = {
                    if (isAnimating) {
                        slideInHorizontally { it } with slideOutHorizontally { -it }
                    } else {
                        fadeIn() with fadeOut()
                    }
                }
            ) { word ->
                Text(
                    text = word,
                    style = typography.displaySmall,
                    color = colorScheme.onPrimaryContainer,
                    fontWeight = FontWeight.Bold,
                    textAlign = TextAlign.Center
                )
            }
            
            if (wordHint != null) {
                Spacer(modifier = Modifier.height(16.dp))
                
                Surface(
                    color = colorScheme.secondary,
                    shape = RoundedCornerShape(8.dp)
                ) {
                    Text(
                        text = "Hint: $wordHint",
                        style = typography.bodySmall,
                        color = colorScheme.onSecondary,
                        modifier = Modifier.padding(8.dp)
                    )
                }
            }
        }
    }
}

@Composable
fun UserInputSection(
    playerAnswer: String,
    onAnswerChange: (String) -> Unit,
    onSubmitAnswer: () -> Unit,
    hasError: Boolean,
    errorMessage: String?,
    isEnabled: Boolean,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier.fillMaxWidth()
    ) {
        OutlinedTextField(
            value = playerAnswer,
            onValueChange = onAnswerChange,
            modifier = Modifier.fillMaxWidth(),
            placeholder = {
                Text(
                    text = stringResource(R.string.type_your_answer),
                    style = typography.bodyMedium
                )
            },
            singleLine = true,
            enabled = isEnabled,
            isError = hasError,
            shape = RoundedCornerShape(12.dp),
            colors = OutlinedTextFieldDefaults.colors(
                focusedBorderColor = colorScheme.primary,
                unfocusedBorderColor = colorScheme.outline,
                errorBorderColor = colorScheme.error
            ),
            keyboardOptions = KeyboardOptions(
                capitalization = KeyboardCapitalization.None,
                imeAction = ImeAction.Go
            ),
            keyboardActions = KeyboardActions(
                onGo = { onSubmitAnswer() }
            )
        )
        
        if (hasError && errorMessage != null) {
            Text(
                text = errorMessage,
                color = colorScheme.error,
                style = typography.bodySmall,
                modifier = Modifier.padding(start = 16.dp, top = 4.dp)
            )
        }
    }
}

@Composable
fun ActionButtonsRow(
    onSubmit: () -> Unit,
    onSkip: () -> Unit,
    onHint: () -> Unit,
    isProcessing: Boolean,
    canShowHint: Boolean,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        Button(
            onClick = onSubmit,
            enabled = !isProcessing,
            modifier = Modifier.weight(1f),
            colors = ButtonDefaults.buttonColors(
                containerColor = colorScheme.primary
            )
        ) {
            if (isProcessing) {
                CircularProgressIndicator(
                    modifier = Modifier.size(16.dp),
                    color = colorScheme.onPrimary,
                    strokeWidth = 2.dp
                )
            } else {
                Text(
                    text = stringResource(R.string.check_answer),
                    style = typography.labelLarge
                )
            }
        }
        
        OutlinedButton(
            onClick = onSkip,
            enabled = !isProcessing,
            modifier = Modifier.weight(1f)
        ) {
            Text(
                text = stringResource(R.string.skip_word),
                style = typography.labelLarge
            )
        }
        
        if (canShowHint) {
            IconButton(
                onClick = onHint,
                enabled = !isProcessing
            ) {
                Icon(
                    imageVector = Icons.Default.Lightbulb,
                    contentDescription = "Show hint",
                    tint = colorScheme.secondary
                )
            }
        }
    }
}

@Composable
fun ScoreboardCard(
    currentScore: Int,
    hintsUsed: Int,
    wordsCompleted: Int,
    modifier: Modifier = Modifier
) {
    Card(
        modifier = modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        colors = CardDefaults.cardColors(
            containerColor = colorScheme.secondaryContainer
        )
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
            horizontalArrangement = Arrangement.SpaceEvenly
        ) {
            StatItem(
                label = "Score",
                value = currentScore.toString(),
                icon = Icons.Default.Star
            )
            
            StatItem(
                label = "Words",
                value = wordsCompleted.toString(),
                icon = Icons.Default.CheckCircle
            )
            
            StatItem(
                label = "Hints",
                value = hintsUsed.toString(),
                icon = Icons.Default.Lightbulb
            )
        }
    }
}

@Composable
fun StatItem(
    label: String,
    value: String,
    icon: ImageVector,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Icon(
            imageVector = icon,
            contentDescription = label,
            tint = colorScheme.onSecondaryContainer,
            modifier = Modifier.size(24.dp)
        )
        
        Text(
            text = value,
            style = typography.headlineSmall,
            color = colorScheme.onSecondaryContainer,
            fontWeight = FontWeight.Bold
        )
        
        Text(
            text = label,
            style = typography.labelSmall,
            color = colorScheme.onSecondaryContainer
        )
    }
}

@Composable
fun GameCompletionDialog(
    finalScore: Int,
    totalWords: Int,
    onRestart: () -> Unit,
    onExit: () -> Unit,
    modifier: Modifier = Modifier
) {
    val context = LocalContext.current
    
    AlertDialog(
        onDismissRequest = { /* Prevent dismissing by clicking outside */ },
        modifier = modifier,
        title = {
            Text(
                text = stringResource(R.string.game_completed),
                style = typography.headlineSmall,
                textAlign = TextAlign.Center
            )
        },
        text = {
            Column(
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = stringResource(R.string.final_score_text, finalScore),
                    style = typography.bodyLarge,
                    textAlign = TextAlign.Center
                )
                
                Spacer(modifier = Modifier.height(8.dp))
                
                Text(
                    text = stringResource(R.string.words_completed_text, totalWords),
                    style = typography.bodyMedium,
                    color = colorScheme.onSurfaceVariant,
                    textAlign = TextAlign.Center
                )
            }
        },
        confirmButton = {
            Button(
                onClick = onRestart,
                colors = ButtonDefaults.buttonColors(
                    containerColor = colorScheme.primary
                )
            ) {
                Text(stringResource(R.string.play_again))
            }
        },
        dismissButton = {
            TextButton(
                onClick = {
                    onExit()
                    if (context is Activity) {
                        context.finish()
                    }
                }
            ) {
                Text(stringResource(R.string.exit_game))
            }
        },
        shape = RoundedCornerShape(16.dp)
    )
}

@Preview(showBackground = true)
@Composable
fun WordGuessingGamePreview() {
    UnscrambleTheme {
        WordGuessingGameScreen()
    }
}

@Preview(showBackground = true)
@Composable
fun GameHeaderPreview() {
    UnscrambleTheme {
        GameHeaderSection(
            appTitle = "Word Scramble",
            currentRound = 3,
            totalRounds = 10
        )
    }
}

Comments

Popular posts from this blog

ETS PPB

EAS PBB