This commit is contained in:
SKILLISSUE1 2025-11-06 23:39:10 +07:00
parent 099c35f19a
commit 2677e3f16c
26 changed files with 113 additions and 51 deletions

View File

@ -1,7 +1,18 @@
Kalkulator BMI 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 Petunjuk lebih detil dapat dibaca di
https://docs.google.com/document/d/1iGiC0Bg3Bdcd2Maq45TYkCDUkZ5Ql51E/edit?rtpof=true https://docs.google.com/document/d/1iGiC0Bg3Bdcd2Maq45TYkCDUkZ5Ql51E/edit?rtpof=true

View File

@ -20,9 +20,9 @@
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/app_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/app_icon_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.TipTime" android:theme="@style/Theme.TipTime"
tools:targetApi="33"> tools:targetApi="33">

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -54,8 +54,9 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.tiptime.ui.theme.TipTimeTheme import com.example.tiptime.ui.theme.TipTimeTheme
import java.text.NumberFormat import java.text.DecimalFormat
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -75,14 +76,16 @@ class MainActivity : ComponentActivity() {
@Composable @Composable
fun TipTimeLayout() { fun TipTimeLayout() {
var amountInput by remember { mutableStateOf("") } var heightInput by remember { mutableStateOf("") }
var tipInput by remember { mutableStateOf("") } var weightInput by remember { mutableStateOf("") }
var roundUp by remember { mutableStateOf(false) } var useUSC by remember { mutableStateOf(false) }
val BmiHeight = amountInput.toDoubleOrNull() ?: 0.0 val height = heightInput.toDoubleOrNull() ?: 0.0
val BmiWeight = tipInput.toDoubleOrNull() ?: 0.0 val weight = weightInput.toDoubleOrNull() ?: 0.0
val bmi = calculateBMI(BmiHeight, BmiWeight, roundUp)
val category = calculateBMICategory(BmiHeight, BmiWeight, roundUp) val bmi = calculateBMI(height, weight, useUSC)
val category = calculateBMICategory(bmi)
val categoryColor = getCategoryColor(category)
Column( Column(
modifier = Modifier modifier = Modifier
@ -94,11 +97,14 @@ fun TipTimeLayout() {
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
Text( Text(
text = stringResource(R.string.calculate_tip), text = "Calculate BMI",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier modifier = Modifier
.padding(bottom = 16.dp, top = 40.dp) .padding(bottom = 16.dp, top = 40.dp)
.align(alignment = Alignment.Start) .align(alignment = Alignment.Start)
) )
EditNumberField( EditNumberField(
label = R.string.height, label = R.string.height,
leadingIcon = R.drawable.number, leadingIcon = R.drawable.number,
@ -106,10 +112,13 @@ fun TipTimeLayout() {
keyboardType = KeyboardType.Number, keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next imeAction = ImeAction.Next
), ),
value = amountInput, value = heightInput,
onValueChanged = { amountInput = it }, onValueChanged = { heightInput = it },
modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth(), modifier = Modifier
.padding(bottom = 32.dp)
.fillMaxWidth(),
) )
EditNumberField( EditNumberField(
label = R.string.weight, label = R.string.weight,
leadingIcon = R.drawable.number, leadingIcon = R.drawable.number,
@ -117,22 +126,30 @@ fun TipTimeLayout() {
keyboardType = KeyboardType.Number, keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done imeAction = ImeAction.Done
), ),
value = tipInput, value = weightInput,
onValueChanged = { tipInput = it }, onValueChanged = { weightInput = it },
modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth(), modifier = Modifier
.padding(bottom = 32.dp)
.fillMaxWidth(),
) )
RoundTheTipRow(
roundUp = roundUp, RoundTheUnitRow(
onRoundUpChanged = { roundUp = it }, useUSC = useUSC,
onUnitChanged = { useUSC = it },
modifier = Modifier.padding(bottom = 32.dp) modifier = Modifier.padding(bottom = 32.dp)
) )
Text( Text(
text = stringResource(R.string.bmi_calculation, bmi), text = "BMI Anda: $bmi",
style = MaterialTheme.typography.displaySmall style = MaterialTheme.typography.displaySmall,
color = MaterialTheme.colorScheme.onSurface
) )
Text( Text(
text = stringResource(R.string.bmi_category, category), text = "Kategori: $category",
style = MaterialTheme.typography.displaySmall fontSize = 20.sp,
color = categoryColor,
modifier = Modifier.padding(top = 8.dp)
) )
Spacer(modifier = Modifier.height(150.dp)) Spacer(modifier = Modifier.height(150.dp))
@ -160,51 +177,75 @@ fun EditNumberField(
} }
@Composable @Composable
fun RoundTheTipRow( fun RoundTheUnitRow(
roundUp: Boolean, useUSC: Boolean,
onRoundUpChanged: (Boolean) -> Unit, onUnitChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Row( Row(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text(text = stringResource(R.string.use_usc)) Text(
text = "Gunakan Unit (Metric/USC)",
color = MaterialTheme.colorScheme.onSurface
)
Switch( Switch(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentWidth(Alignment.End), .wrapContentWidth(Alignment.End),
checked = roundUp, checked = useUSC,
onCheckedChange = onRoundUpChanged onCheckedChange = onUnitChanged
) )
} }
} }
/** /**
* Calculates the BMI * Menghitung BMI berdasarkan rumus yang digunakan
*
* 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
*/ */
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 { val bmi = if (useUSC) {
var bmi = BmiWeight / 100 * BmiHeight // Rumus USC: 703 * (berat (lbs) / (tinggi (in)^2))
if (roundUp) { 703 * (weight / (height * height))
bmi = kotlin.math.ceil(bmi) } 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) @Preview(showBackground = true)
@Composable @Composable
fun TipTimeLayoutPreview() { fun TipTimeLayoutPreview() {

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/app_icon_background"/>
<foreground android:drawable="@mipmap/app_icon_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/app_icon_background"/>
<foreground android:drawable="@mipmap/app_icon_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB