diff --git a/app/src/main/java/com/example/tiptime/MainActivity.kt b/app/src/main/java/com/example/tiptime/MainActivity.kt index 4a0edce..b2c3711 100644 --- a/app/src/main/java/com/example/tiptime/MainActivity.kt +++ b/app/src/main/java/com/example/tiptime/MainActivity.kt @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -48,6 +48,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction @@ -63,8 +64,11 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { TipTimeTheme { + Surface( modifier = Modifier.fillMaxSize(), + // merubah warna latar belakang + color = Color(0xFF687FF5) ) { TipTimeLayout() } @@ -75,14 +79,17 @@ 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 + + // Perhitungan BMI dan Kategori harus menggunakan Double + val bmiValue = calculateBMIValue(height, weight, useUSC) + val formattedBMI = String.format("%.2f", bmiValue) // BMI diformat 2 desimal + val category = calculateBMICategory(bmiValue) // Kategori menggunakan nilai Double BMI Column( modifier = Modifier @@ -94,51 +101,61 @@ fun TipTimeLayout() { verticalArrangement = Arrangement.Center ) { Text( - text = stringResource(R.string.calculate_tip), + text = stringResource(R.string.calculate_bmi), + style = MaterialTheme.typography.headlineMedium, modifier = Modifier .padding(bottom = 16.dp, top = 40.dp) .align(alignment = Alignment.Start) ) EditNumberField( - label = R.string.height, + label = if (useUSC) R.string.height_usc else R.string.height_metric, // Teks dinamis leadingIcon = R.drawable.number, keyboardOptions = KeyboardOptions.Default.copy( 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, + label = if (useUSC) R.string.weight_usc else R.string.weight_metric, // Teks dinamis leadingIcon = R.drawable.number, keyboardOptions = KeyboardOptions.Default.copy( 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 }, + UnitSwitchRow( // Ganti RoundTheTipRow menjadi UnitSwitchRow + useUSC = useUSC, + onUseUSCChanged = { useUSC = it }, modifier = Modifier.padding(bottom = 32.dp) ) + // Menampilkan Hasil BMI Text( - text = stringResource(R.string.bmi_calculation, bmi), // rumus - style = MaterialTheme.typography.displaySmall + text = stringResource(R.string.bmi_calculation, formattedBMI), + style = MaterialTheme.typography.titleLarge // Ganti displaySmall ke titleLarge ) + Spacer(modifier = Modifier.height(8.dp)) + // Menampilkan Kategori BMI Text( - text = stringResource(R.string.bmi_category, category), // kategori - style = MaterialTheme.typography.displaySmall + text = stringResource(R.string.bmi_category, category), + style = MaterialTheme.typography.titleLarge ) Spacer(modifier = Modifier.height(150.dp)) } } + + @Composable fun EditNumberField( @StringRes label: Int, @@ -151,7 +168,7 @@ fun EditNumberField( TextField( value = value, singleLine = true, - leadingIcon = { Icon(painter = painterResource(id = leadingIcon), null) }, + leadingIcon = { Icon(painter = painterResource(id = leadingIcon), contentDescription = null) }, modifier = modifier, onValueChange = onValueChanged, label = { Text(stringResource(label)) }, @@ -160,9 +177,9 @@ fun EditNumberField( } @Composable -fun RoundTheTipRow( - roundUp: Boolean, - onRoundUpChanged: (Boolean) -> Unit, +fun UnitSwitchRow( // Nama fungsi diperbarui + useUSC: Boolean, + onUseUSCChanged: (Boolean) -> Unit, modifier: Modifier = Modifier ) { Row( @@ -174,46 +191,43 @@ fun RoundTheTipRow( modifier = Modifier .fillMaxWidth() .wrapContentWidth(Alignment.End), - checked = roundUp, - onCheckedChange = onRoundUpChanged + checked = useUSC, + onCheckedChange = onUseUSCChanged ) } } /** - * Calculates the BMI - * - * Catatan: tambahkan unit test untuk kalkulasi BMI ini + * Calculates the BMI value (Double). + * Catatan: Jika ingin menampilkan pembulatan di hasil, lakukan di formattedBMI. */ -private fun calculateBMI(BmiHeight: Double, BmiWeight: Double, useUSC: Boolean): String { - if (BmiHeight <= 0 || BmiWeight <= 0) return "0.0" +private fun calculateBMIValue(height: Double, weight: Double, useUSC: Boolean): Double { + if (height <= 0 || weight <= 0) return 0.0 - val bmi = if (useUSC) { - // USC: Berat dalam lbs, tinggi dalam inches - 703 * (BmiWeight*2.2) / ((BmiHeight*0.29) * (BmiHeight*0.29)) + return if (useUSC) { + // USC: Berat dalam lbs, Tinggi dalam inches. Rumus: (Berat / Tinggi^2) * 703 + (weight / (height * height)) * 703 } else { - // SI Metric: konversi cm ke meter - val heightInMeter = BmiHeight / 100 - BmiWeight / (heightInMeter * heightInMeter) + // SI Metric: Berat dalam kg, Tinggi dalam cm. Konversi cm ke meter. Rumus: Berat / Tinggi^2 (dalam m) + val heightInMeter = height / 100 + weight / (heightInMeter * heightInMeter) } - - return String.format("%.2f", bmi) } /** - * Calculates the BMI Category - * - * Catatan: tambahkan unit test untuk kalkulasi BMI ini + * Calculates the BMI Category (String) based on the BMI value (Double). */ - -private fun calculateBMICategory(BmiHeight: Double, BmiWeight: Double = 15.0, roundUp: Boolean): String { - var bmi = BmiWeight / 100 * BmiHeight - if (roundUp) { - bmi = kotlin.math.ceil(bmi) +private fun calculateBMICategory(bmiValue: Double): String { + return when { + bmiValue < 18.5 -> "Kurus (Underweight)" + bmiValue < 25.0 -> "Normal (Healthy Weight)" + bmiValue < 30.0 -> "Gemuk (Overweight)" + bmiValue >= 30.0 -> "Obesitas (Obese)" + else -> "Masukkan data yang valid" } - return NumberFormat.getNumberInstance().format(bmi) } + @Preview(showBackground = true) @Composable fun TipTimeLayoutPreview() { diff --git a/app/src/main/java/com/example/tiptime/ui/theme/Color.kt b/app/src/main/java/com/example/tiptime/ui/theme/Color.kt index bc21042..2870eb8 100644 --- a/app/src/main/java/com/example/tiptime/ui/theme/Color.kt +++ b/app/src/main/java/com/example/tiptime/ui/theme/Color.kt @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,62 +17,74 @@ package com.example.tiptime.ui.theme import androidx.compose.ui.graphics.Color -val md_theme_light_primary = Color(0xFF984061) +// Light Colors (Teal / Hijau Kebiruan) +val md_theme_light_primary = Color(0xFF006A6A) val md_theme_light_onPrimary = Color(0xFFFFFFFF) -val md_theme_light_primaryContainer = Color(0xFFFFD9E2) -val md_theme_light_onPrimaryContainer = Color(0xFF3E001D) -val md_theme_light_secondary = Color(0xFF754B9C) +val md_theme_light_primaryContainer = Color(0xFF70F7F7) +val md_theme_light_onPrimaryContainer = Color(0xFF002020) +val md_theme_light_secondary = Color(0xFF4A6363) val md_theme_light_onSecondary = Color(0xFFFFFFFF) -val md_theme_light_secondaryContainer = Color(0xFFF1DBFF) -val md_theme_light_onSecondaryContainer = Color(0xFF2D0050) -val md_theme_light_tertiary = Color(0xFF984060) +val md_theme_light_secondaryContainer = Color(0xFFCDE8E8) +val md_theme_light_onSecondaryContainer = Color(0xFF051F1F) +val md_theme_light_tertiary = Color(0xFF4A6363) val md_theme_light_onTertiary = Color(0xFFFFFFFF) -val md_theme_light_tertiaryContainer = Color(0xFFFFD9E2) -val md_theme_light_onTertiaryContainer = Color(0xFF3E001D) +val md_theme_light_tertiaryContainer = Color(0xFFCDE8E8) +val md_theme_light_onTertiaryContainer = Color(0xFF051F1F) val md_theme_light_error = Color(0xFFBA1A1A) val md_theme_light_errorContainer = Color(0xFFFFDAD6) val md_theme_light_onError = Color(0xFFFFFFFF) val md_theme_light_onErrorContainer = Color(0xFF410002) -val md_theme_light_background = Color(0xFFFAFCFF) -val md_theme_light_onBackground = Color(0xFF001F2A) -val md_theme_light_surface = Color(0xFFFAFCFF) -val md_theme_light_onSurface = Color(0xFF001F2A) -val md_theme_light_surfaceVariant = Color(0xFFF2DDE2) -val md_theme_light_onSurfaceVariant = Color(0xFF514347) -val md_theme_light_outline = Color(0xFF837377) -val md_theme_light_inverseOnSurface = Color(0xFFE1F4FF) -val md_theme_light_inverseSurface = Color(0xFF003547) -val md_theme_light_inversePrimary = Color(0xFFFFB0C8) -val md_theme_light_surfaceTint = Color(0xFF984061) -val md_theme_light_outlineVariant = Color(0xFFD5C2C6) + +// Background dengan sedikit warna (putih kebiruan lembut) +val md_theme_light_background = Color(0xFFF0F5F5) +val md_theme_light_onBackground = Color(0xFF191C1C) + +// Surface sedikit lebih putih dari background agar elemen menonjol +val md_theme_light_surface = Color(0xFFFAFDFD) +val md_theme_light_onSurface = Color(0xFF191C1C) + +val md_theme_light_surfaceVariant = Color(0xFFDAE5E4) +val md_theme_light_onSurfaceVariant = Color(0xFF3F4949) +val md_theme_light_outline = Color(0xFF6F7979) +val md_theme_light_inverseOnSurface = Color(0xFFEFF1F1) +val md_theme_light_inverseSurface = Color(0xFF2D3131) +val md_theme_light_inversePrimary = Color(0xFF4CDADA) +val md_theme_light_surfaceTint = Color(0xFF006A6A) +val md_theme_light_outlineVariant = Color(0xFFBEC9C9) val md_theme_light_scrim = Color(0xFF000000) -val md_theme_dark_primary = Color(0xFFFFB0C8) -val md_theme_dark_onPrimary = Color(0xFF5E1133) -val md_theme_dark_primaryContainer = Color(0xFF7B2949) -val md_theme_dark_onPrimaryContainer = Color(0xFFFFD9E2) -val md_theme_dark_secondary = Color(0xFFDEB7FF) -val md_theme_dark_onSecondary = Color(0xFF44196A) -val md_theme_dark_secondaryContainer = Color(0xFF5C3382) -val md_theme_dark_onSecondaryContainer = Color(0xFFF1DBFF) -val md_theme_dark_tertiary = Color(0xFFFFB1C7) -val md_theme_dark_onTertiary = Color(0xFF5E1132) -val md_theme_dark_tertiaryContainer = Color(0xFF7B2948) -val md_theme_dark_onTertiaryContainer = Color(0xFFFFD9E2) +// Dark Colors (Teal / Hijau Kebiruan) +val md_theme_dark_primary = Color(0xFF4CDADA) +val md_theme_dark_onPrimary = Color(0xFF003737) +val md_theme_dark_primaryContainer = Color(0xFF004F50) +val md_theme_dark_onPrimaryContainer = Color(0xFF70F7F7) +val md_theme_dark_secondary = Color(0xFFB1CBCB) +val md_theme_dark_onSecondary = Color(0xFF1B3434) +val md_theme_dark_secondaryContainer = Color(0xFF334B4B) +val md_theme_dark_onSecondaryContainer = Color(0xFFCDE8E8) +val md_theme_dark_tertiary = Color(0xFFB1CBCB) +val md_theme_dark_onTertiary = Color(0xFF1B3434) +val md_theme_dark_tertiaryContainer = Color(0xFF334B4B) +val md_theme_dark_onTertiaryContainer = Color(0xFFCDE8E8) val md_theme_dark_error = Color(0xFFFFB4AB) val md_theme_dark_errorContainer = Color(0xFF93000A) val md_theme_dark_onError = Color(0xFF690005) val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) -val md_theme_dark_background = Color(0xFF001F2A) -val md_theme_dark_onBackground = Color(0xFFBFE9FF) -val md_theme_dark_surface = Color(0xFF001F2A) -val md_theme_dark_onSurface = Color(0xFFBFE9FF) -val md_theme_dark_surfaceVariant = Color(0xFF514347) -val md_theme_dark_onSurfaceVariant = Color(0xFFD5C2C6) -val md_theme_dark_outline = Color(0xFF9E8C90) -val md_theme_dark_inverseOnSurface = Color(0xFF001F2A) -val md_theme_dark_inverseSurface = Color(0xFFBFE9FF) -val md_theme_dark_inversePrimary = Color(0xFF984061) -val md_theme_dark_surfaceTint = Color(0xFFFFB0C8) -val md_theme_dark_outlineVariant = Color(0xFF514347) -val md_theme_dark_scrim = Color(0xFF000000) + +// Background dengan sedikit warna (abu-abu kebiruan gelap) +val md_theme_dark_background = Color(0xFF152020) +val md_theme_dark_onBackground = Color(0xFFE0E3E3) + +// Surface sedikit lebih terang (kurang gelap) dari background untuk elevasi +val md_theme_dark_surface = Color(0xFF191C1C) +val md_theme_dark_onSurface = Color(0xFFE0E3E3) + +val md_theme_dark_surfaceVariant = Color(0xFF3F4949) +val md_theme_dark_onSurfaceVariant = Color(0xFFBEC9C9) +val md_theme_dark_outline = Color(0xFF899393) +val md_theme_dark_inverseOnSurface = Color(0xFF191C1C) +val md_theme_dark_inverseSurface = Color(0xFFE0E3E3) +val md_theme_dark_inversePrimary = Color(0xFF006A6A) +val md_theme_dark_surfaceTint = Color(0xFF4CDADA) +val md_theme_dark_outlineVariant = Color(0xFF3F4949) +val md_theme_dark_scrim = Color(0xFF000000) \ No newline at end of file diff --git a/app/src/main/java/com/example/tiptime/ui/theme/Type.kt b/app/src/main/java/com/example/tiptime/ui/theme/Type.kt index a4cf6e6..8190c41 100644 --- a/app/src/main/java/com/example/tiptime/ui/theme/Type.kt +++ b/app/src/main/java/com/example/tiptime/ui/theme/Type.kt @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -23,11 +23,36 @@ import androidx.compose.ui.unit.sp // Set of Material typography styles to start with val Typography = Typography( + // Style untuk Judul Utama (Header) displaySmall = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Bold, fontSize = 36.sp, lineHeight = 44.sp, letterSpacing = 0.sp, + ), + // Style untuk Judul Bagian Penting + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.SemiBold, // Lebih menarik dari Regular + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + // Style untuk Teks Normal/Konten Utama + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ), + // Style untuk Teks Kecil/Label Form + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp ) -) +) \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 04e6db2..605a0a3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,11 +15,17 @@ ~ limitations under the License. --> - BMI Calculator - Calculate BMI - Tinggi Badan - Berat Badan - Gunakan Unit USC (lbs/in)? + Kalkulator BMI + + Kalkulasi Indeks Massa Tubuh (BMI) + + Tinggi (cm) + Berat (kg) + Tinggi (in) + Berat (lbs) + + Gunakan Satuan Imperial (Inci/Lbs) + BMI Anda: %s Kategori: %s