diff --git a/README.md b/README.md index 08d4aa4..765610b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,18 @@ Kalkulator BMI =============== +Langkah-langkah: -Silahkan kembangkan aplikasi ini untuk melakukan perhitungan BMI +1. Clone Repository Project +Saya meng-clone repository project dari GitHub menggunakan Android Studio untuk dijadikan dasar pengerjaan tugas. + +2. Modifikasi Tampilan Aplikasi +Saya meminta bantuan ChatGPT dan DeepSeek untuk memberikan saran tampilan aplikasi agar lebih menarik. Setelah itu, saya menyesuaikan tampilan sesuai arahan yang diberikan. + +3. Mengubah Icon Aplikasi (APK) +Saya mengganti icon aplikasi melalui fitur Image Asset di Android Studio dengan icon baru sesuai arahan dari ChatGPT. + +4. Review dan Uji Coba +Setelah perubahan selesai, saya menjalankan aplikasi untuk memastikan tampilan dan icon sudah berubah dengan baik. Petunjuk lebih detil dapat dibaca di https://docs.google.com/document/d/1iGiC0Bg3Bdcd2Maq45TYkCDUkZ5Ql51E/edit?rtpof=true diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e897dec..82f8cad 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,9 +20,9 @@ diff --git a/app/src/main/app_icon-playstore.png b/app/src/main/app_icon-playstore.png new file mode 100644 index 0000000..3cd8332 Binary files /dev/null and b/app/src/main/app_icon-playstore.png differ diff --git a/app/src/main/java/com/example/tiptime/MainActivity.kt b/app/src/main/java/com/example/tiptime/MainActivity.kt index d0fdd80..8ecd965 100644 --- a/app/src/main/java/com/example/tiptime/MainActivity.kt +++ b/app/src/main/java/com/example/tiptime/MainActivity.kt @@ -54,8 +54,9 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.example.tiptime.ui.theme.TipTimeTheme -import java.text.NumberFormat +import java.text.DecimalFormat class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -75,14 +76,16 @@ class MainActivity : ComponentActivity() { @Composable fun TipTimeLayout() { - var amountInput by remember { mutableStateOf("") } - var tipInput by remember { mutableStateOf("") } - var roundUp by remember { mutableStateOf(false) } + var heightInput by remember { mutableStateOf("") } + var weightInput by remember { mutableStateOf("") } + var useUSC by remember { mutableStateOf(false) } - val BmiHeight = amountInput.toDoubleOrNull() ?: 0.0 - val BmiWeight = tipInput.toDoubleOrNull() ?: 0.0 - val bmi = calculateBMI(BmiHeight, BmiWeight, roundUp) - val category = calculateBMICategory(BmiHeight, BmiWeight, roundUp) + val height = heightInput.toDoubleOrNull() ?: 0.0 + val weight = weightInput.toDoubleOrNull() ?: 0.0 + + val bmi = calculateBMI(height, weight, useUSC) + val category = calculateBMICategory(bmi) + val categoryColor = getCategoryColor(category) Column( modifier = Modifier @@ -94,11 +97,14 @@ fun TipTimeLayout() { verticalArrangement = Arrangement.Center ) { Text( - text = stringResource(R.string.calculate_tip), + text = "Calculate BMI", + style = MaterialTheme.typography.headlineMedium, + color = MaterialTheme.colorScheme.primary, modifier = Modifier .padding(bottom = 16.dp, top = 40.dp) .align(alignment = Alignment.Start) ) + EditNumberField( label = R.string.height, leadingIcon = R.drawable.number, @@ -106,10 +112,13 @@ fun TipTimeLayout() { keyboardType = KeyboardType.Number, imeAction = ImeAction.Next ), - value = amountInput, - onValueChanged = { amountInput = it }, - modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth(), + value = heightInput, + onValueChanged = { heightInput = it }, + modifier = Modifier + .padding(bottom = 32.dp) + .fillMaxWidth(), ) + EditNumberField( label = R.string.weight, leadingIcon = R.drawable.number, @@ -117,22 +126,30 @@ fun TipTimeLayout() { keyboardType = KeyboardType.Number, imeAction = ImeAction.Done ), - value = tipInput, - onValueChanged = { tipInput = it }, - modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth(), + value = weightInput, + onValueChanged = { weightInput = it }, + modifier = Modifier + .padding(bottom = 32.dp) + .fillMaxWidth(), ) - RoundTheTipRow( - roundUp = roundUp, - onRoundUpChanged = { roundUp = it }, + + RoundTheUnitRow( + useUSC = useUSC, + onUnitChanged = { useUSC = it }, modifier = Modifier.padding(bottom = 32.dp) ) + Text( - text = stringResource(R.string.bmi_calculation, bmi), - style = MaterialTheme.typography.displaySmall + text = "BMI Anda: $bmi", + style = MaterialTheme.typography.displaySmall, + color = MaterialTheme.colorScheme.onSurface ) + Text( - text = stringResource(R.string.bmi_category, category), - style = MaterialTheme.typography.displaySmall + text = "Kategori: $category", + fontSize = 20.sp, + color = categoryColor, + modifier = Modifier.padding(top = 8.dp) ) Spacer(modifier = Modifier.height(150.dp)) @@ -160,51 +177,75 @@ fun EditNumberField( } @Composable -fun RoundTheTipRow( - roundUp: Boolean, - onRoundUpChanged: (Boolean) -> Unit, +fun RoundTheUnitRow( + useUSC: Boolean, + onUnitChanged: (Boolean) -> Unit, modifier: Modifier = Modifier ) { Row( modifier = modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - Text(text = stringResource(R.string.use_usc)) + Text( + text = "Gunakan Unit (Metric/USC)", + color = MaterialTheme.colorScheme.onSurface + ) Switch( modifier = Modifier .fillMaxWidth() .wrapContentWidth(Alignment.End), - checked = roundUp, - onCheckedChange = onRoundUpChanged + checked = useUSC, + onCheckedChange = onUnitChanged ) } } /** - * Calculates the BMI - * - * Catatan: tambahkan unit test untuk kalkulasi BMI ini - */ -private fun calculateBMI(BmiHeight: Double, BmiWeight: Double = 15.0, roundUp: Boolean): String { - var bmi = BmiWeight / 100 * BmiHeight - if (roundUp) { - bmi = kotlin.math.ceil(bmi) - } - return NumberFormat.getNumberInstance().format(bmi) -} -/** - * Calculates the BMI Category - * - * Catatan: tambahkan unit test untuk kalkulasi BMI ini + * Menghitung BMI berdasarkan rumus yang digunakan */ +internal fun calculateBMI(height: Double, weight: Double, useUSC: Boolean): String { + if (height == 0.0 || weight == 0.0) return "0.0" -private fun calculateBMICategory(BmiHeight: Double, BmiWeight: Double = 15.0, roundUp: Boolean): String { - var bmi = BmiWeight / 100 * BmiHeight - if (roundUp) { - bmi = kotlin.math.ceil(bmi) + val bmi = if (useUSC) { + // Rumus USC: 703 * (berat (lbs) / (tinggi (in)^2)) + 703 * (weight / (height * height)) + } else { + // Rumus Metric: berat (kg) / (tinggi (m)^2) + val heightInMeter = height / 100 + weight / (heightInMeter * heightInMeter) } - return NumberFormat.getNumberInstance().format(bmi) + + return DecimalFormat("#.0").format(bmi) } + +/** + * Menentukan kategori BMI + */ +internal fun calculateBMICategory(bmiString: String): String { + val bmi = bmiString.toDoubleOrNull() ?: 0.0 + return when { + bmi < 18.5 -> "Underweight" + bmi < 25.0 -> "Normal weight" + bmi < 30.0 -> "Overweight" + bmi >= 30.0 -> "Obese" + else -> "Tidak diketahui" + } +} + +/** + * Memberikan warna berdasarkan kategori BMI - menggunakan warna dari tema + */ +@Composable +fun getCategoryColor(category: String): androidx.compose.ui.graphics.Color { + return when (category) { + "Underweight" -> androidx.compose.ui.graphics.Color(0xFF2196F3) // Biru + "Normal weight" -> androidx.compose.ui.graphics.Color(0xFF4CAF50) // Hijau + "Overweight" -> androidx.compose.ui.graphics.Color(0xFFFF9800) // Orange + "Obese" -> androidx.compose.ui.graphics.Color(0xFFF44336) // Merah + else -> MaterialTheme.colorScheme.onSurface + } +} + @Preview(showBackground = true) @Composable fun TipTimeLayoutPreview() { diff --git a/app/src/main/res/mipmap-anydpi-v26/app_icon.xml b/app/src/main/res/mipmap-anydpi-v26/app_icon.xml new file mode 100644 index 0000000..60b0b70 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/app_icon.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/app_icon_round.xml b/app/src/main/res/mipmap-anydpi-v26/app_icon_round.xml new file mode 100644 index 0000000..60b0b70 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/app_icon_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/app_icon.webp b/app/src/main/res/mipmap-hdpi/app_icon.webp new file mode 100644 index 0000000..589484b Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/app_icon.webp differ diff --git a/app/src/main/res/mipmap-hdpi/app_icon_background.webp b/app/src/main/res/mipmap-hdpi/app_icon_background.webp new file mode 100644 index 0000000..f769b95 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/app_icon_background.webp differ diff --git a/app/src/main/res/mipmap-hdpi/app_icon_foreground.webp b/app/src/main/res/mipmap-hdpi/app_icon_foreground.webp new file mode 100644 index 0000000..f769b95 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/app_icon_foreground.webp differ diff --git a/app/src/main/res/mipmap-hdpi/app_icon_round.webp b/app/src/main/res/mipmap-hdpi/app_icon_round.webp new file mode 100644 index 0000000..99cba91 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/app_icon_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/app_icon.webp b/app/src/main/res/mipmap-mdpi/app_icon.webp new file mode 100644 index 0000000..2b96e3d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/app_icon.webp differ diff --git a/app/src/main/res/mipmap-mdpi/app_icon_background.webp b/app/src/main/res/mipmap-mdpi/app_icon_background.webp new file mode 100644 index 0000000..24ff5bf Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/app_icon_background.webp differ diff --git a/app/src/main/res/mipmap-mdpi/app_icon_foreground.webp b/app/src/main/res/mipmap-mdpi/app_icon_foreground.webp new file mode 100644 index 0000000..24ff5bf Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/app_icon_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/app_icon_round.webp b/app/src/main/res/mipmap-mdpi/app_icon_round.webp new file mode 100644 index 0000000..2347506 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/app_icon_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/app_icon.webp b/app/src/main/res/mipmap-xhdpi/app_icon.webp new file mode 100644 index 0000000..2c97e96 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/app_icon.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/app_icon_background.webp b/app/src/main/res/mipmap-xhdpi/app_icon_background.webp new file mode 100644 index 0000000..f63c38f Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/app_icon_background.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/app_icon_foreground.webp b/app/src/main/res/mipmap-xhdpi/app_icon_foreground.webp new file mode 100644 index 0000000..f63c38f Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/app_icon_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/app_icon_round.webp b/app/src/main/res/mipmap-xhdpi/app_icon_round.webp new file mode 100644 index 0000000..4a5eaee Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/app_icon_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/app_icon.webp b/app/src/main/res/mipmap-xxhdpi/app_icon.webp new file mode 100644 index 0000000..28e3b03 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/app_icon.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/app_icon_background.webp b/app/src/main/res/mipmap-xxhdpi/app_icon_background.webp new file mode 100644 index 0000000..cbcb2d9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/app_icon_background.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/app_icon_foreground.webp b/app/src/main/res/mipmap-xxhdpi/app_icon_foreground.webp new file mode 100644 index 0000000..cbcb2d9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/app_icon_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/app_icon_round.webp b/app/src/main/res/mipmap-xxhdpi/app_icon_round.webp new file mode 100644 index 0000000..9cae7ac Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/app_icon_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/app_icon.webp b/app/src/main/res/mipmap-xxxhdpi/app_icon.webp new file mode 100644 index 0000000..3c44f63 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/app_icon.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/app_icon_background.webp b/app/src/main/res/mipmap-xxxhdpi/app_icon_background.webp new file mode 100644 index 0000000..353b46b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/app_icon_background.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/app_icon_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/app_icon_foreground.webp new file mode 100644 index 0000000..353b46b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/app_icon_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/app_icon_round.webp b/app/src/main/res/mipmap-xxxhdpi/app_icon_round.webp new file mode 100644 index 0000000..e6d8695 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/app_icon_round.webp differ