From e1fa621f141ff04e30525039e67fab9f10a494ef Mon Sep 17 00:00:00 2001 From: dend <2023010715051@mhs.ubharajaya.ac.id> Date: Thu, 6 Nov 2025 22:01:43 +0700 Subject: [PATCH] Memperbarui Tampilan UI Dan UX Agar Lebih Menarik Dan Lebih Mudah Digunakan Seperti: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### **Versi 2.0 - Perubahan Unit Metric** #### Perubahan Major: - ✅ **Mengubah unit tinggi dari meter ke centimeter (cm)** - Alasan: Lebih mudah dipahami pengguna Indonesia - Format baru: tinggi dalam **cm** (contoh: 170 cm) - ✅ Update formula kalkulasi: - Konversi cm ke meter: `heightInMeters = height / 100.0` - BMI = weight / (heightInMeters²) - ✅ Update validasi input: - Minimum tinggi: 50 cm - Maximum tinggi: 300 cm --- ### **Versi 3.0 - UI/UX Enhancement** #### Perubahan UI/UX: - ✅ **Modern Card Design** dengan shadow effects - ✅ **Gradient Background** (Sky Blue ke White) - ✅ **Custom Input Fields** dengan Card wrapper - ✅ **Unit System Card** dengan design yang lebih menarik - ✅ **Color-coded Results** berdasarkan kategori BMI: - 🔵 Underweight - Light Blue - 🔵 Normal - Sky Blue - 🔵 Overweight - Medium Blue - 🔵 Obese - Dark Blue - ✅ **BMI Result Card** dengan: - Display BMI value besar dan bold - Badge kategori dengan emoji - Deskripsi lengkap untuk setiap kategori - Referensi range BMI WHO - ✅ **Responsive Layout** dengan vertical scroll - ✅ **Better Typography** dengan font weights dan sizing --- ### **Versi 4.0 - Blue Color Scheme Implementation** #### Perubahan Tema: - ✅ **Complete Blue Color Theme** - Primary Color: Light Blue (#03A9F4) - Secondary Color: Medium Blue (#0288D1) - Background: Very Light Blue White (#F5FBFF) - Accent: Sky Blue dan Navy Blue - ✅ **Light Theme Colors**: - Primary: Light Blue - warna utama aplikasi - Container: Very Light Blue - untuk card backgrounds - Surface: White - permukaan bersih - ✅ **Dark Theme Colors**: - Primary: Sky Blue - untuk dark mode - Background: Very Dark Blue - Surface: Deep Blue - ✅ **Component Colors**: - Button: Light Blue dengan shadow - Input border: Light Blue saat focus - Switch: Sky Blue theme - Cards: Gradasi warna biru --- --- README.md | 205 +++++++- .../java/com/example/tiptime/MainActivity.kt | 486 +++++++++++++----- .../com/example/tiptime/ui/theme/Color.kt | 118 ++--- 3 files changed, 627 insertions(+), 182 deletions(-) diff --git a/README.md b/README.md index 08d4aa4..1c2607f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,205 @@ -Kalkulator BMI -=============== +# Kalkulator BMI -Silahkan kembangkan aplikasi ini untuk melakukan perhitungan BMI +## 📱 Deskripsi Aplikasi +Aplikasi **BMI Calculator** (Body Mass Index Calculator) adalah aplikasi Android yang dibangun menggunakan Jetpack Compose untuk menghitung Indeks Massa Tubuh pengguna berdasarkan tinggi dan berat badan. Aplikasi ini mendukung dua sistem unit pengukuran: **Metric (kg/cm)** dan **Imperial (lbs/inches)**. -Petunjuk lebih detil dapat dibaca di +--- + +## 👨‍💻 Informasi Pengembang +- **NPM**: 202310715051 +- **Nama**: Dendi Yogia Pratama + +--- + +## 📚 Referensi +Petunjuk lebih detail dapat dibaca di: https://docs.google.com/document/d/1iGiC0Bg3Bdcd2Maq45TYkCDUkZ5Ql51E/edit?rtpof=true Starter dimodifikasi dan terinspirasi dari: -https://developer.android.com/codelabs/basic-android-compose-calculate-tip#0 \ No newline at end of file +https://developer.android.com/codelabs/basic-android-compose-calculate-tip#0 + +--- + +## 🔄 Changelog - Perubahan dari Awal sampai Akhir + +### **Versi 0.5 - Setup Code** +- Memperbaiki Rumus Yang Digunakan Untuk Menghitung BMI Agar Lebih Akurat Di Kedua Sistem Unit +- Mengatasi Tulisan NAN Yang Muncul Ditampilan Sebelum Kalkulasi + +### **Versi 1.0 - Initial Setup (Base Code)** +#### Fitur Awal: +- Setup project dengan Jetpack Compose +- Layout dasar dengan TextField untuk input +- Fungsi kalkulasi BMI sederhana +- Menggunakan sistem Metric (meter dan kg) + +--- + +### **Versi 1.5 - Penambahan Unit System** +#### Perubahan: +- ✅ Menambahkan **Switch Toggle** untuk memilih sistem unit (USC/SI) +- ✅ Implementasi dua formula BMI: + - **SI Formula**: BMI = weight (kg) / height² (meters) + - **USC Formula**: BMI = 703 × weight (lbs) / height² (inches) +- ✅ Validasi input untuk kedua sistem unit +- ✅ Dynamic label pada input field sesuai sistem unit yang dipilih + +--- + +### **Versi 2.0 - Perubahan Unit Metric** +#### Perubahan Major: +- ✅ **Mengubah unit tinggi dari meter ke centimeter (cm)** + - Alasan: Lebih mudah dipahami pengguna Indonesia + - Format baru: tinggi dalam **cm** (contoh: 170 cm) +- ✅ Update formula kalkulasi: + - Konversi cm ke meter: `heightInMeters = height / 100.0` + - BMI = weight / (heightInMeters²) +- ✅ Update validasi input: + - Minimum tinggi: 50 cm + - Maximum tinggi: 300 cm + +--- + +### **Versi 3.0 - UI/UX Enhancement** +#### Perubahan UI/UX: +- ✅ **Modern Card Design** dengan shadow effects +- ✅ **Gradient Background** (Sky Blue ke White) +- ✅ **Custom Input Fields** dengan Card wrapper +- ✅ **Unit System Card** dengan design yang lebih menarik +- ✅ **Color-coded Results** berdasarkan kategori BMI: + - 🔵 Underweight - Light Blue + - 🔵 Normal - Sky Blue + - 🔵 Overweight - Medium Blue + - 🔵 Obese - Dark Blue +- ✅ **BMI Result Card** dengan: + - Display BMI value besar dan bold + - Badge kategori dengan emoji + - Deskripsi lengkap untuk setiap kategori + - Referensi range BMI WHO +- ✅ **Responsive Layout** dengan vertical scroll +- ✅ **Better Typography** dengan font weights dan sizing + +--- + +### **Versi 4.0 - Blue Color Scheme Implementation** +#### Perubahan Tema: +- ✅ **Complete Blue Color Theme** + - Primary Color: Light Blue (#03A9F4) + - Secondary Color: Medium Blue (#0288D1) + - Background: Very Light Blue White (#F5FBFF) + - Accent: Sky Blue dan Navy Blue +- ✅ **Light Theme Colors**: + - Primary: Light Blue - warna utama aplikasi + - Container: Very Light Blue - untuk card backgrounds + - Surface: White - permukaan bersih +- ✅ **Dark Theme Colors**: + - Primary: Sky Blue - untuk dark mode + - Background: Very Dark Blue + - Surface: Deep Blue +- ✅ **Component Colors**: + - Button: Light Blue dengan shadow + - Input border: Light Blue saat focus + - Switch: Sky Blue theme + - Cards: Gradasi warna biru + +--- + +## ✨ Fitur Aplikasi + +### **1. Dual Unit System** +- 🌍 **Metric System**: Kilogram (kg) dan Centimeter (cm) +- 🇺🇸 **Imperial System**: Pounds (lbs) dan Inches (in) +- 🔄 Toggle switch untuk berpindah sistem +- 🔄 Auto-reset input saat ganti sistem + +### **2. Input Validation** +#### Metric System: +- Tinggi: 50 - 300 cm +- Berat: 20 - 500 kg + +#### Imperial System: +- Tinggi: 20 - 120 inches +- Berat: 44 - 1100 lbs + +### **3. BMI Categories (WHO Standard)** +- **Underweight**: BMI < 18.5 +- **Normal weight**: BMI 18.5 - 24.9 +- **Overweight**: BMI 25.0 - 29.9 +- **Obese**: BMI ≥ 30.0 + +### **4. Visual Features** +- 🎨 Gradient background dengan warna biru +- 💳 Card-based design untuk semua komponen +- 🌈 Color-coded results berdasarkan kategori +- 📊 BMI range reference dengan color indicators +- ✨ Shadow effects untuk depth visual +- 🔤 Modern typography dengan font weights +- 📱 Responsive dan scrollable layout + +--- + +## 🛠️ Teknologi yang Digunakan +- **Kotlin** - Programming Language +- **Jetpack Compose** - Modern UI Toolkit +- **Material Design 3** - Design System +- **Android Studio** - IDE + +--- + +## 📋 Struktur Kode + +### **Data Class** +```kotlin +data class BMIResult( + val bmiValue: Double, + val category: String, + val isValid: Boolean = true, + val errorMessage: String = "" +) +``` + +### **Main Components** +1. **BMICalculatorLayout** - Main screen layout +2. **UnitSystemCard** - Toggle untuk sistem unit +3. **BMIInputField** - Custom input field dengan card design +4. **BMIResultCard** - Menampilkan hasil dengan visual menarik +5. **BMIRangeReference** - Referensi range BMI WHO + +### **Key Functions** +- `calculateBMI()` - Menghitung BMI dengan validasi +- `validateBMIInput()` - Validasi input berdasarkan sistem unit +- `getBMICategory()` - Menentukan kategori BMI +- `getBMICategoryInfo()` - Memberikan deskripsi kategori +- `formatBMIResult()` - Format display angka BMI + +--- + +## 🎨 Design Principles +1. **User-Friendly**: Interface yang mudah dipahami +2. **Visual Feedback**: Color-coding untuk hasil yang jelas +3. **Informative**: Deskripsi lengkap untuk setiap kategori +4. **Modern**: Design mengikuti Material Design 3 +5. **Accessible**: Contrast yang baik dan text yang readable +6. **Responsive**: Layout adaptif untuk berbagai ukuran layar + +--- + +## 🚀 Cara Menggunakan +1. Pilih sistem unit (Metric/Imperial) dengan toggle switch +2. Masukkan tinggi badan (cm atau inches) +3. Masukkan berat badan (kg atau lbs) +4. Tekan tombol "Hitung BMI" +5. Lihat hasil BMI dengan kategori dan deskripsi lengkap + +--- + +## 📈 Future Improvements +- [ ] Menyimpan riwayat perhitungan BMI +- [ ] Grafik trend BMI dari waktu ke waktu +- [ ] Rekomendasi diet dan olahraga +- [ ] Export hasil ke PDF +- [ ] Multi-language support +- [ ] Dark mode toggle +- [ ] BMI ideal calculator berdasarkan usia dan gender + +--- \ No newline at end of file diff --git a/app/src/main/java/com/example/tiptime/MainActivity.kt b/app/src/main/java/com/example/tiptime/MainActivity.kt index 716dc23..c855c10 100644 --- a/app/src/main/java/com/example/tiptime/MainActivity.kt +++ b/app/src/main/java/com/example/tiptime/MainActivity.kt @@ -4,15 +4,25 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign 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 @@ -54,23 +64,93 @@ data class BMIResult( * Composable untuk switch pemilihan unit sistem (USC/SI) */ @Composable -fun UnitSystemSwitchRow( +fun UnitSystemCard( useUSC: Boolean, onUseUSCChanged: (Boolean) -> Unit, modifier: Modifier = Modifier ) { - Row( - modifier = modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically + Card( + modifier = modifier + .fillMaxWidth() + .shadow(4.dp, RoundedCornerShape(16.dp)), + shape = RoundedCornerShape(16.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.primaryContainer + ) ) { - Text(text = "Use USC Units (lbs/inches)") - Switch( + Row( modifier = Modifier .fillMaxWidth() - .wrapContentWidth(Alignment.End), - checked = useUSC, - onCheckedChange = onUseUSCChanged + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column { + Text( + text = "Sistem Unit", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + Text( + text = if (useUSC) "Imperial (lbs/inches)" else "Metric (kg/cm)", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.7f) + ) + } + Switch( + checked = useUSC, + onCheckedChange = onUseUSCChanged, + colors = SwitchDefaults.colors( + checkedThumbColor = MaterialTheme.colorScheme.primary, + checkedTrackColor = MaterialTheme.colorScheme.primaryContainer + ) + ) + } + } +} + +/** + * Custom Input Field dengan design yang lebih menarik + */ +@Composable +fun BMIInputField( + value: String, + onValueChange: (String) -> Unit, + label: String, + unit: String, + modifier: Modifier = Modifier +) { + Card( + modifier = modifier + .fillMaxWidth() + .shadow(2.dp, RoundedCornerShape(12.dp)), + shape = RoundedCornerShape(12.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface ) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = label, + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.SemiBold + ) + Spacer(modifier = Modifier.height(8.dp)) + OutlinedTextField( + value = value, + onValueChange = onValueChange, + suffix = { Text(unit, fontWeight = FontWeight.Bold) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), + modifier = Modifier.fillMaxWidth(), + singleLine = true, + shape = RoundedCornerShape(8.dp), + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = MaterialTheme.colorScheme.primary, + unfocusedBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f) + ) + ) + } } } @@ -84,130 +164,296 @@ fun BMICalculatorLayout() { var useUSC by remember { mutableStateOf(false) } var bmiResult by remember { mutableStateOf(null) } - Column( + Box( modifier = Modifier - .padding(40.dp) - .fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = "BMI Calculator", - style = MaterialTheme.typography.headlineMedium, - modifier = Modifier.padding(bottom = 16.dp) - ) - - // Unit System Switch - UnitSystemSwitchRow( - useUSC = useUSC, - onUseUSCChanged = { useUSC = it }, - modifier = Modifier.padding(vertical = 8.dp) - ) - - // Height Input - OutlinedTextField( - value = heightInput, - onValueChange = { heightInput = it }, - label = { - Text(if (useUSC) "Height (inches)" else "Height (meters)") - }, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), - modifier = Modifier.fillMaxWidth(), - singleLine = true - ) - - // Weight Input - OutlinedTextField( - value = weightInput, - onValueChange = { weightInput = it }, - label = { - Text(if (useUSC) "Weight (lbs)" else "Weight (kg)") - }, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), - modifier = Modifier.fillMaxWidth(), - singleLine = true - ) - - // Calculate Button - Button( - onClick = { - val height = heightInput.toDoubleOrNull() - val weight = weightInput.toDoubleOrNull() - - if (height != null && weight != null) { - bmiResult = calculateBMI(height, weight, useUSC) - } else { - bmiResult = BMIResult( - bmiValue = 0.0, - category = "", - isValid = false, - errorMessage = "Please enter valid numbers" + .fillMaxSize() + .background( + Brush.verticalGradient( + colors = listOf( + MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.3f), + MaterialTheme.colorScheme.background ) - } - }, - modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp) - ) { - Text("Calculate BMI") - } - - // Display Result - bmiResult?.let { result -> - Card( - modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp), - colors = CardDefaults.cardColors( - containerColor = if (result.isValid) - MaterialTheme.colorScheme.primaryContainer - else - MaterialTheme.colorScheme.errorContainer ) + ) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(24.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // Header + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally ) { - Column( - modifier = Modifier.padding(16.dp) - ) { - if (result.isValid) { - Text( - text = "Your BMI: ${formatBMIResult(result)}", - style = MaterialTheme.typography.titleLarge - ) - Text( - text = "Category: ${result.category}", - style = MaterialTheme.typography.bodyLarge, - modifier = Modifier.padding(top = 8.dp) - ) + Text( + text = "💪 BMI Calculator", + style = MaterialTheme.typography.headlineLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary + ) + Text( + text = "Hitung Indeks Massa Tubuh Anda", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f) + ) + } - // BMI Info - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = getBMICategoryInfo(result.category), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onPrimaryContainer - ) + Spacer(modifier = Modifier.height(8.dp)) + + // Unit System Switch + UnitSystemCard( + useUSC = useUSC, + onUseUSCChanged = { + useUSC = it + // Reset input saat ganti sistem + heightInput = "" + weightInput = "" + bmiResult = null + } + ) + + // Height Input + BMIInputField( + value = heightInput, + onValueChange = { heightInput = it }, + label = "Tinggi Badan", + unit = if (useUSC) "inches" else "cm" + ) + + // Weight Input + BMIInputField( + value = weightInput, + onValueChange = { weightInput = it }, + label = "Berat Badan", + unit = if (useUSC) "lbs" else "kg" + ) + + // Calculate Button + Button( + onClick = { + val height = heightInput.toDoubleOrNull() + val weight = weightInput.toDoubleOrNull() + + if (height != null && weight != null) { + bmiResult = calculateBMI(height, weight, useUSC) } else { - Text( - text = "Error: ${result.errorMessage}", - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.error + bmiResult = BMIResult( + bmiValue = 0.0, + category = "", + isValid = false, + errorMessage = "Mohon masukkan angka yang valid" ) } + }, + modifier = Modifier + .fillMaxWidth() + .height(56.dp) + .shadow(8.dp, RoundedCornerShape(12.dp)), + shape = RoundedCornerShape(12.dp), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.primary + ) + ) { + Text( + "Hitung BMI", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + } + + // Display Result + bmiResult?.let { result -> + BMIResultCard(result = result) + } + + Spacer(modifier = Modifier.height(16.dp)) + } + } +} + +/** + * Card untuk menampilkan hasil BMI dengan design menarik + */ +@Composable +fun BMIResultCard(result: BMIResult) { + Card( + modifier = Modifier + .fillMaxWidth() + .shadow(8.dp, RoundedCornerShape(20.dp)), + shape = RoundedCornerShape(20.dp), + colors = CardDefaults.cardColors( + containerColor = if (result.isValid) { + when (result.category) { + "Underweight" -> Color(0xFFFFF3E0) + "Normal weight" -> Color(0xFFE8F5E9) + "Overweight" -> Color(0xFFFFF9C4) + "Obese" -> Color(0xFFFFEBEE) + else -> MaterialTheme.colorScheme.surface } + } else { + MaterialTheme.colorScheme.errorContainer + } + ) + ) { + Column( + modifier = Modifier.padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (result.isValid) { + // BMI Value + Text( + text = "BMI Anda", + style = MaterialTheme.typography.titleMedium, + color = Color.Gray + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = formatBMIResult(result), + style = MaterialTheme.typography.displayLarge, + fontWeight = FontWeight.Bold, + color = getBMICategoryColor(result.category) + ) + Spacer(modifier = Modifier.height(16.dp)) + + // Category Badge + Surface( + shape = RoundedCornerShape(20.dp), + color = getBMICategoryColor(result.category).copy(alpha = 0.2f), + modifier = Modifier.padding(vertical = 8.dp) + ) { + Text( + text = getCategoryEmoji(result.category) + " " + result.category, + modifier = Modifier.padding(horizontal = 20.dp, vertical = 10.dp), + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold, + color = getBMICategoryColor(result.category) + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + Divider(color = Color.Gray.copy(alpha = 0.3f)) + Spacer(modifier = Modifier.height(12.dp)) + + // BMI Info + Text( + text = getBMICategoryInfo(result.category), + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Center, + color = Color.DarkGray + ) + + // BMI Range Reference + Spacer(modifier = Modifier.height(16.dp)) + BMIRangeReference() + } else { + Text( + text = "⚠️ Error", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.error + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = result.errorMessage, + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.error + ) } } } } +/** + * Reference BMI Range + */ +@Composable +fun BMIRangeReference() { + Card( + shape = RoundedCornerShape(12.dp), + colors = CardDefaults.cardColors( + containerColor = Color.White.copy(alpha = 0.7f) + ) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "Referensi BMI (WHO)", + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(bottom = 8.dp) + ) + BMIRangeItem("< 18.5", "Underweight", Color(0xFFFF9800)) + BMIRangeItem("18.5 - 24.9", "Normal", Color(0xFF4CAF50)) + BMIRangeItem("25.0 - 29.9", "Overweight", Color(0xFFFFEB3B)) + BMIRangeItem("≥ 30.0", "Obese", Color(0xFFF44336)) + } + } +} + +@Composable +fun BMIRangeItem(range: String, category: String, color: Color) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(12.dp) + .background(color, RoundedCornerShape(6.dp)) + ) + Spacer(modifier = Modifier.width(12.dp)) + Text( + text = range, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + modifier = Modifier.weight(1f) + ) + Text( + text = category, + style = MaterialTheme.typography.bodySmall, + color = Color.Gray + ) + } +} + +/** + * Helper functions + */ +fun getBMICategoryColor(category: String): Color { + return when (category) { + "Underweight" -> Color(0xFFFF9800) + "Normal weight" -> Color(0xFF4CAF50) + "Overweight" -> Color(0xFFFFEB3B) + "Obese" -> Color(0xFFF44336) + else -> Color.Gray + } +} + +fun getCategoryEmoji(category: String): String { + return when (category) { + "Underweight" -> "⚠️" + "Normal weight" -> "✅" + "Overweight" -> "⚡" + "Obese" -> "🔴" + else -> "❓" + } +} + /** * Memvalidasi input tinggi dan berat badan */ fun validateBMIInput(height: Double, weight: Double, useUSC: Boolean): Pair { if (!useUSC) { - // SI Units validation + // SI Units validation (cm dan kg) when { height <= 0 -> return Pair(false, "Tinggi harus lebih dari 0") - height < 0.5 -> return Pair(false, "Tinggi terlalu rendah (minimum 0.5m)") - height > 3.0 -> return Pair(false, "Tinggi tidak wajar (maksimum 3.0m)") + height < 50 -> return Pair(false, "Tinggi terlalu rendah (minimum 50cm)") + height > 300 -> return Pair(false, "Tinggi tidak wajar (maksimum 300cm)") weight <= 0 -> return Pair(false, "Berat harus lebih dari 0") weight < 20 -> return Pair(false, "Berat terlalu rendah (minimum 20kg)") weight > 500 -> return Pair(false, "Berat tidak wajar (maksimum 500kg)") @@ -231,7 +477,7 @@ fun validateBMIInput(height: Double, weight: Double, useUSC: Boolean): Pair "BMI < 18.5: Berat badan kurang" - "Normal weight" -> "BMI 18.5-24.9: Berat badan ideal" - "Overweight" -> "BMI 25.0-29.9: Kelebihan berat badan" - "Obese" -> "BMI ≥ 30.0: Obesitas" + "Underweight" -> "Berat badan Anda kurang dari ideal. Pertimbangkan untuk meningkatkan asupan nutrisi." + "Normal weight" -> "Selamat! Berat badan Anda dalam rentang ideal dan sehat." + "Overweight" -> "Berat badan Anda sedikit berlebih. Pertimbangkan pola makan sehat dan olahraga teratur." + "Obese" -> "Berat badan Anda berlebih. Konsultasikan dengan dokter untuk program penurunan berat badan." else -> "" } } 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..e9be706 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 @@ -17,62 +17,64 @@ package com.example.tiptime.ui.theme import androidx.compose.ui.graphics.Color -val md_theme_light_primary = Color(0xFF984061) -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_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_onTertiary = Color(0xFFFFFFFF) -val md_theme_light_tertiaryContainer = Color(0xFFFFD9E2) -val md_theme_light_onTertiaryContainer = Color(0xFF3E001D) -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) -val md_theme_light_scrim = Color(0xFF000000) +// Light Theme - Light Blue Dominant +val md_theme_light_primary = Color(0xFF03A9F4) // Light Blue +val md_theme_light_onPrimary = Color(0xFFFFFFFF) // White +val md_theme_light_primaryContainer = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_light_onPrimaryContainer = Color(0xFF01579B) // Navy Blue +val md_theme_light_secondary = Color(0xFF0288D1) // Medium Blue +val md_theme_light_onSecondary = Color(0xFFFFFFFF) // White +val md_theme_light_secondaryContainer = Color(0xFFE1F5FE) // Pale Blue +val md_theme_light_onSecondaryContainer = Color(0xFF014A7F) // Dark Blue +val md_theme_light_tertiary = Color(0xFF0277BD) // Blue +val md_theme_light_onTertiary = Color(0xFFFFFFFF) // White +val md_theme_light_tertiaryContainer = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_light_onTertiaryContainer = Color(0xFF003D5B) // Deep Blue +val md_theme_light_error = Color(0xFFBA1A1A) // Red +val md_theme_light_errorContainer = Color(0xFFFFDAD6) // Light Red +val md_theme_light_onError = Color(0xFFFFFFFF) // White +val md_theme_light_onErrorContainer = Color(0xFF410002) // Dark Red +val md_theme_light_background = Color(0xFFF5FBFF) // Very Light Blue White +val md_theme_light_onBackground = Color(0xFF001F2A) // Dark Blue Gray +val md_theme_light_surface = Color(0xFFFFFFFF) // White +val md_theme_light_onSurface = Color(0xFF001F2A) // Dark Blue Gray +val md_theme_light_surfaceVariant = Color(0xFFE3F2FD) // Pale Blue +val md_theme_light_onSurfaceVariant = Color(0xFF455A64) // Blue Gray +val md_theme_light_outline = Color(0xFF78909C) // Medium Blue Gray +val md_theme_light_inverseOnSurface = Color(0xFFE1F4FF) // Very Light Blue +val md_theme_light_inverseSurface = Color(0xFF003547) // Deep Blue +val md_theme_light_inversePrimary = Color(0xFF81D4FA) // Sky Blue +val md_theme_light_surfaceTint = Color(0xFF03A9F4) // Light Blue +val md_theme_light_outlineVariant = Color(0xFFB0BEC5) // Light Blue Gray +val md_theme_light_scrim = Color(0xFF000000) // Black -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) -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) +// Dark Theme - Dark Blue Dominant +val md_theme_dark_primary = Color(0xFF81D4FA) // Sky Blue +val md_theme_dark_onPrimary = Color(0xFF003D5B) // Deep Blue +val md_theme_dark_primaryContainer = Color(0xFF01579B) // Navy Blue +val md_theme_dark_onPrimaryContainer = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_dark_secondary = Color(0xFF64B5F6) // Light Blue +val md_theme_dark_onSecondary = Color(0xFF014A7F) // Dark Blue +val md_theme_dark_secondaryContainer = Color(0xFF0277BD) // Blue +val md_theme_dark_onSecondaryContainer = Color(0xFFE1F5FE) // Pale Blue +val md_theme_dark_tertiary = Color(0xFF90CAF9) // Soft Blue +val md_theme_dark_onTertiary = Color(0xFF003D5B) // Deep Blue +val md_theme_dark_tertiaryContainer = Color(0xFF01579B) // Navy Blue +val md_theme_dark_onTertiaryContainer = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_dark_error = Color(0xFFFFB4AB) // Light Red +val md_theme_dark_errorContainer = Color(0xFF93000A) // Dark Red +val md_theme_dark_onError = Color(0xFF690005) // Deep Red +val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) // Light Red +val md_theme_dark_background = Color(0xFF001F2A) // Very Dark Blue +val md_theme_dark_onBackground = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_dark_surface = Color(0xFF003547) // Deep Blue +val md_theme_dark_onSurface = Color(0xFFE1F5FE) // Pale Blue +val md_theme_dark_surfaceVariant = Color(0xFF01579B) // Navy Blue +val md_theme_dark_onSurfaceVariant = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_dark_outline = Color(0xFF607D8B) // Blue Gray +val md_theme_dark_inverseOnSurface = Color(0xFF001F2A) // Very Dark Blue +val md_theme_dark_inverseSurface = Color(0xFFB3E5FC) // Very Light Blue +val md_theme_dark_inversePrimary = Color(0xFF0277BD) // Blue +val md_theme_dark_surfaceTint = Color(0xFF81D4FA) // Sky Blue +val md_theme_dark_outlineVariant = Color(0xFF455A64) // Blue Gray +val md_theme_dark_scrim = Color(0xFF000000) // Black \ No newline at end of file