Compare commits

..

No commits in common. "8522ddc9ef0f4b586cad40c6c1817f23e1a82db0" and "2e0003f6119af26e27afb15692969271e10663da" have entirely different histories.

4 changed files with 107 additions and 164 deletions

View File

@ -48,7 +48,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
@ -64,11 +63,8 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
TipTimeTheme { TipTimeTheme {
Surface( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
// merubah warna latar belakang
color = Color(0xFF687FF5)
) { ) {
TipTimeLayout() TipTimeLayout()
} }
@ -79,17 +75,14 @@ class MainActivity : ComponentActivity() {
@Composable @Composable
fun TipTimeLayout() { fun TipTimeLayout() {
var heightInput by remember { mutableStateOf("") } var amountInput by remember { mutableStateOf("") }
var weightInput by remember { mutableStateOf("") } var tipInput by remember { mutableStateOf("") }
var useUSC by remember { mutableStateOf(false) } var roundUp by remember { mutableStateOf(false) }
val height = heightInput.toDoubleOrNull() ?: 0.0 val BmiHeight = amountInput.toDoubleOrNull() ?: 0.0
val weight = weightInput.toDoubleOrNull() ?: 0.0 val BmiWeight = tipInput.toDoubleOrNull() ?: 0.0
val bmi = calculateBMI(BmiHeight, BmiWeight, roundUp)
// Perhitungan BMI dan Kategori harus menggunakan Double val category = calculateBMICategory(BmiHeight, BmiWeight, roundUp)
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( Column(
modifier = Modifier modifier = Modifier
@ -101,61 +94,51 @@ fun TipTimeLayout() {
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
Text( Text(
text = stringResource(R.string.calculate_bmi), text = stringResource(R.string.calculate_tip),
style = MaterialTheme.typography.headlineMedium,
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 = if (useUSC) R.string.height_usc else R.string.height_metric, // Teks dinamis label = R.string.height,
leadingIcon = R.drawable.number, leadingIcon = R.drawable.number,
keyboardOptions = KeyboardOptions.Default.copy( keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number, keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next imeAction = ImeAction.Next
), ),
value = heightInput, value = amountInput,
onValueChanged = { heightInput = it }, onValueChanged = { amountInput = it },
modifier = Modifier modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth(),
.padding(bottom = 32.dp)
.fillMaxWidth(),
) )
EditNumberField( EditNumberField(
label = if (useUSC) R.string.weight_usc else R.string.weight_metric, // Teks dinamis label = R.string.weight,
leadingIcon = R.drawable.number, leadingIcon = R.drawable.number,
keyboardOptions = KeyboardOptions.Default.copy( keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number, keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done imeAction = ImeAction.Done
), ),
value = weightInput, value = tipInput,
onValueChanged = { weightInput = it }, onValueChanged = { tipInput = it },
modifier = Modifier modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth(),
.padding(bottom = 32.dp)
.fillMaxWidth(),
) )
UnitSwitchRow( // Ganti RoundTheTipRow menjadi UnitSwitchRow RoundTheTipRow(
useUSC = useUSC, roundUp = roundUp,
onUseUSCChanged = { useUSC = it }, onRoundUpChanged = { roundUp = it },
modifier = Modifier.padding(bottom = 32.dp) modifier = Modifier.padding(bottom = 32.dp)
) )
// Menampilkan Hasil BMI
Text( Text(
text = stringResource(R.string.bmi_calculation, formattedBMI), text = stringResource(R.string.bmi_calculation, bmi), // rumus
style = MaterialTheme.typography.titleLarge // Ganti displaySmall ke titleLarge style = MaterialTheme.typography.displaySmall
) )
Spacer(modifier = Modifier.height(8.dp))
// Menampilkan Kategori BMI
Text( Text(
text = stringResource(R.string.bmi_category, category), text = stringResource(R.string.bmi_category, category), // kategori
style = MaterialTheme.typography.titleLarge style = MaterialTheme.typography.displaySmall
) )
Spacer(modifier = Modifier.height(150.dp)) Spacer(modifier = Modifier.height(150.dp))
} }
} }
@Composable @Composable
fun EditNumberField( fun EditNumberField(
@StringRes label: Int, @StringRes label: Int,
@ -168,7 +151,7 @@ fun EditNumberField(
TextField( TextField(
value = value, value = value,
singleLine = true, singleLine = true,
leadingIcon = { Icon(painter = painterResource(id = leadingIcon), contentDescription = null) }, leadingIcon = { Icon(painter = painterResource(id = leadingIcon), null) },
modifier = modifier, modifier = modifier,
onValueChange = onValueChanged, onValueChange = onValueChanged,
label = { Text(stringResource(label)) }, label = { Text(stringResource(label)) },
@ -177,9 +160,9 @@ fun EditNumberField(
} }
@Composable @Composable
fun UnitSwitchRow( // Nama fungsi diperbarui fun RoundTheTipRow(
useUSC: Boolean, roundUp: Boolean,
onUseUSCChanged: (Boolean) -> Unit, onRoundUpChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Row( Row(
@ -191,43 +174,46 @@ fun UnitSwitchRow( // Nama fungsi diperbarui
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentWidth(Alignment.End), .wrapContentWidth(Alignment.End),
checked = useUSC, checked = roundUp,
onCheckedChange = onUseUSCChanged onCheckedChange = onRoundUpChanged
) )
} }
} }
/** /**
* Calculates the BMI value (Double). * Calculates the BMI
* Catatan: Jika ingin menampilkan pembulatan di hasil, lakukan di formattedBMI. *
* Catatan: tambahkan unit test untuk kalkulasi BMI ini
*/ */
private fun calculateBMIValue(height: Double, weight: Double, useUSC: Boolean): Double { private fun calculateBMI(BmiHeight: Double, BmiWeight: Double, useUSC: Boolean): String {
if (height <= 0 || weight <= 0) return 0.0 if (BmiHeight <= 0 || BmiWeight <= 0) return "0.0"
return if (useUSC) { val bmi = if (useUSC) {
// USC: Berat dalam lbs, Tinggi dalam inches. Rumus: (Berat / Tinggi^2) * 703 // USC: Berat dalam lbs, tinggi dalam inches
(weight / (height * height)) * 703 703 * (BmiWeight*2.2) / ((BmiHeight*0.29) * (BmiHeight*0.29))
} else { } else {
// SI Metric: Berat dalam kg, Tinggi dalam cm. Konversi cm ke meter. Rumus: Berat / Tinggi^2 (dalam m) // SI Metric: konversi cm ke meter
val heightInMeter = height / 100 val heightInMeter = BmiHeight / 100
weight / (heightInMeter * heightInMeter) BmiWeight / (heightInMeter * heightInMeter)
} }
return String.format("%.2f", bmi)
} }
/** /**
* Calculates the BMI Category (String) based on the BMI value (Double). * Calculates the BMI Category
*
* Catatan: tambahkan unit test untuk kalkulasi BMI ini
*/ */
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"
}
}
private fun calculateBMICategory(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)
}
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable
fun TipTimeLayoutPreview() { fun TipTimeLayoutPreview() {

View File

@ -17,74 +17,62 @@ package com.example.tiptime.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
// Light Colors (Teal / Hijau Kebiruan) val md_theme_light_primary = Color(0xFF984061)
val md_theme_light_primary = Color(0xFF006A6A)
val md_theme_light_onPrimary = Color(0xFFFFFFFF) val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFF70F7F7) val md_theme_light_primaryContainer = Color(0xFFFFD9E2)
val md_theme_light_onPrimaryContainer = Color(0xFF002020) val md_theme_light_onPrimaryContainer = Color(0xFF3E001D)
val md_theme_light_secondary = Color(0xFF4A6363) val md_theme_light_secondary = Color(0xFF754B9C)
val md_theme_light_onSecondary = Color(0xFFFFFFFF) val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFCDE8E8) val md_theme_light_secondaryContainer = Color(0xFFF1DBFF)
val md_theme_light_onSecondaryContainer = Color(0xFF051F1F) val md_theme_light_onSecondaryContainer = Color(0xFF2D0050)
val md_theme_light_tertiary = Color(0xFF4A6363) val md_theme_light_tertiary = Color(0xFF984060)
val md_theme_light_onTertiary = Color(0xFFFFFFFF) val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFCDE8E8) val md_theme_light_tertiaryContainer = Color(0xFFFFD9E2)
val md_theme_light_onTertiaryContainer = Color(0xFF051F1F) val md_theme_light_onTertiaryContainer = Color(0xFF3E001D)
val md_theme_light_error = Color(0xFFBA1A1A) val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6) val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF) val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002) val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFAFCFF)
// Background dengan sedikit warna (putih kebiruan lembut) val md_theme_light_onBackground = Color(0xFF001F2A)
val md_theme_light_background = Color(0xFFF0F5F5) val md_theme_light_surface = Color(0xFFFAFCFF)
val md_theme_light_onBackground = Color(0xFF191C1C) val md_theme_light_onSurface = Color(0xFF001F2A)
val md_theme_light_surfaceVariant = Color(0xFFF2DDE2)
// Surface sedikit lebih putih dari background agar elemen menonjol val md_theme_light_onSurfaceVariant = Color(0xFF514347)
val md_theme_light_surface = Color(0xFFFAFDFD) val md_theme_light_outline = Color(0xFF837377)
val md_theme_light_onSurface = Color(0xFF191C1C) val md_theme_light_inverseOnSurface = Color(0xFFE1F4FF)
val md_theme_light_inverseSurface = Color(0xFF003547)
val md_theme_light_surfaceVariant = Color(0xFFDAE5E4) val md_theme_light_inversePrimary = Color(0xFFFFB0C8)
val md_theme_light_onSurfaceVariant = Color(0xFF3F4949) val md_theme_light_surfaceTint = Color(0xFF984061)
val md_theme_light_outline = Color(0xFF6F7979) val md_theme_light_outlineVariant = Color(0xFFD5C2C6)
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_light_scrim = Color(0xFF000000)
// Dark Colors (Teal / Hijau Kebiruan) val md_theme_dark_primary = Color(0xFFFFB0C8)
val md_theme_dark_primary = Color(0xFF4CDADA) val md_theme_dark_onPrimary = Color(0xFF5E1133)
val md_theme_dark_onPrimary = Color(0xFF003737) val md_theme_dark_primaryContainer = Color(0xFF7B2949)
val md_theme_dark_primaryContainer = Color(0xFF004F50) val md_theme_dark_onPrimaryContainer = Color(0xFFFFD9E2)
val md_theme_dark_onPrimaryContainer = Color(0xFF70F7F7) val md_theme_dark_secondary = Color(0xFFDEB7FF)
val md_theme_dark_secondary = Color(0xFFB1CBCB) val md_theme_dark_onSecondary = Color(0xFF44196A)
val md_theme_dark_onSecondary = Color(0xFF1B3434) val md_theme_dark_secondaryContainer = Color(0xFF5C3382)
val md_theme_dark_secondaryContainer = Color(0xFF334B4B) val md_theme_dark_onSecondaryContainer = Color(0xFFF1DBFF)
val md_theme_dark_onSecondaryContainer = Color(0xFFCDE8E8) val md_theme_dark_tertiary = Color(0xFFFFB1C7)
val md_theme_dark_tertiary = Color(0xFFB1CBCB) val md_theme_dark_onTertiary = Color(0xFF5E1132)
val md_theme_dark_onTertiary = Color(0xFF1B3434) val md_theme_dark_tertiaryContainer = Color(0xFF7B2948)
val md_theme_dark_tertiaryContainer = Color(0xFF334B4B) val md_theme_dark_onTertiaryContainer = Color(0xFFFFD9E2)
val md_theme_dark_onTertiaryContainer = Color(0xFFCDE8E8)
val md_theme_dark_error = Color(0xFFFFB4AB) val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A) val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005) val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF001F2A)
// Background dengan sedikit warna (abu-abu kebiruan gelap) val md_theme_dark_onBackground = Color(0xFFBFE9FF)
val md_theme_dark_background = Color(0xFF152020) val md_theme_dark_surface = Color(0xFF001F2A)
val md_theme_dark_onBackground = Color(0xFFE0E3E3) val md_theme_dark_onSurface = Color(0xFFBFE9FF)
val md_theme_dark_surfaceVariant = Color(0xFF514347)
// Surface sedikit lebih terang (kurang gelap) dari background untuk elevasi val md_theme_dark_onSurfaceVariant = Color(0xFFD5C2C6)
val md_theme_dark_surface = Color(0xFF191C1C) val md_theme_dark_outline = Color(0xFF9E8C90)
val md_theme_dark_onSurface = Color(0xFFE0E3E3) val md_theme_dark_inverseOnSurface = Color(0xFF001F2A)
val md_theme_dark_inverseSurface = Color(0xFFBFE9FF)
val md_theme_dark_surfaceVariant = Color(0xFF3F4949) val md_theme_dark_inversePrimary = Color(0xFF984061)
val md_theme_dark_onSurfaceVariant = Color(0xFFBEC9C9) val md_theme_dark_surfaceTint = Color(0xFFFFB0C8)
val md_theme_dark_outline = Color(0xFF899393) val md_theme_dark_outlineVariant = Color(0xFF514347)
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) val md_theme_dark_scrim = Color(0xFF000000)

View File

@ -23,36 +23,11 @@ import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with // Set of Material typography styles to start with
val Typography = Typography( val Typography = Typography(
// Style untuk Judul Utama (Header)
displaySmall = TextStyle( displaySmall = TextStyle(
fontFamily = FontFamily.Default, fontFamily = FontFamily.Default,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 36.sp, fontSize = 36.sp,
lineHeight = 44.sp, lineHeight = 44.sp,
letterSpacing = 0.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
) )
) )

View File

@ -15,17 +15,11 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<resources> <resources>
<string name="app_name">Kalkulator BMI</string> <string name="app_name">BMI Calculator</string>
<string name="calculate_tip">Calculate BMI</string>
<string name="calculate_bmi">Kalkulasi Indeks Massa Tubuh (BMI)</string> <string name="height">Tinggi Badan</string>
<string name="weight">Berat Badan</string>
<string name="height_metric">Tinggi (cm)</string> <string name="use_usc">Gunakan Unit USC (lbs/in)?</string>
<string name="weight_metric">Berat (kg)</string>
<string name="height_usc">Tinggi (in)</string>
<string name="weight_usc">Berat (lbs)</string>
<string name="use_usc">Gunakan Satuan Imperial (Inci/Lbs)</string>
<string name="bmi_calculation">BMI Anda: %s</string> <string name="bmi_calculation">BMI Anda: %s</string>
<string name="bmi_category">Kategori: %s</string> <string name="bmi_category">Kategori: %s</string>
</resources> </resources>