revisi terbaru
This commit is contained in:
parent
0358bf15e4
commit
253cc3a6bb
80
README.md
80
README.md
@ -2,67 +2,61 @@
|
||||
|
||||
**Dibuat oleh:**
|
||||
👨💻 **Rafi Fattan Fitriardi**
|
||||
🆔 **NPM: 202310715002**
|
||||
🏫 **Pemrograman Perangkat Bergerak - F5A5**
|
||||
🆔 **NPM:** 202310715002
|
||||
🏫 **Kelas:** Pemrograman Perangkat Bergerak - F5A5
|
||||
|
||||
---
|
||||
|
||||
## 📖 Deskripsi Aplikasi
|
||||
Aplikasi **Kalkulator BMI (Body Mass Index)** ini dibuat sebagai proyek akhir mata kuliah **Pemrograman Perangkat Bergerak**.
|
||||
Tujuan utama aplikasi ini adalah membantu pengguna menghitung **Indeks Massa Tubuh (BMI)** berdasarkan **berat badan (kg)** dan **tinggi badan (cm)** untuk mengetahui apakah berat badan tergolong **kurang, ideal, berlebih, atau obesitas**.
|
||||
Tujuannya adalah membantu pengguna menghitung **Indeks Massa Tubuh (BMI)** berdasarkan **berat badan (kg/lbs)** dan **tinggi badan (cm/inci)** agar dapat mengetahui apakah berat badan tergolong **kurang, ideal, berlebih, atau obesitas**.
|
||||
|
||||
Aplikasi ini memiliki **dua halaman utama**:
|
||||
1. **Halaman Biodata Pengembang** – menampilkan informasi pembuat aplikasi (nama, NIM, kelas, dan foto), serta tombol **“MULAI”** untuk berpindah ke laman utama.
|
||||
2. **Halaman Utama (Kalkulator BMI)** – tempat pengguna menginput berat dan tinggi badan, menekan tombol **“Hitung BMI”**, lalu melihat hasil nilai BMI beserta kategori dan saran kesehatannya.
|
||||
Aplikasi memiliki **dua halaman utama**:
|
||||
|
||||
1. 🧑💻 **Halaman Biodata Pengembang**
|
||||
Menampilkan informasi pengembang (nama, NIM, kelas, dan foto), serta tombol **“MULAI”** untuk berpindah ke halaman utama.
|
||||
|
||||
2. ⚖️ **Halaman Utama (Kalkulator BMI)**
|
||||
Pengguna dapat menginput berat dan tinggi badan, menekan tombol **“Hitung BMI”**, dan melihat hasil nilai BMI beserta **kategori serta saran kesehatannya**.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Fitur Utama
|
||||
- Input berat dan tinggi badan secara interaktif (bisa satuan SI atau USC).
|
||||
- Perhitungan otomatis nilai BMI.
|
||||
- Tampilan kategori hasil (Kurus, Normal, Gemuk, Obesitas).
|
||||
- Antarmuka sederhana dan responsif.
|
||||
- Navigasi antarhalaman menggunakan tombol **MULAI** dari halaman biodata.
|
||||
- ✏️ Input berat dan tinggi badan secara interaktif (bisa satuan **SI** atau **USC**).
|
||||
- 🧮 Perhitungan otomatis nilai BMI dengan opsi pembulatan hasil.
|
||||
- 📊 Tampilan kategori hasil (Kurus, Normal, Gemuk, Obesitas).
|
||||
- 🎨 Antarmuka sederhana, bersih, dan responsif menggunakan **Jetpack Compose**.
|
||||
- 🔄 Navigasi antarhalaman dengan tombol **MULAI** dari halaman biodata.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Teknologi yang Digunakan
|
||||
- **Android Studio (Kotlin)**
|
||||
- **XML Layouts** untuk desain antarmuka
|
||||
- **Intent** untuk navigasi antar activity
|
||||
- **Drawable XML** untuk gradasi dan tema warna aplikasi
|
||||
|
||||
---
|
||||
|
||||
## 💡 Struktur Proyek
|
||||
```
|
||||
app/
|
||||
├── java/com/example/bmiapp/
|
||||
│ ├── SplashActivity.kt // Halaman biodata pengembang
|
||||
│ ├── MainActivity.kt // Halaman utama kalkulator BMI
|
||||
│
|
||||
├── res/
|
||||
│ ├── layout/
|
||||
│ │ ├── activity_splash.xml
|
||||
│ │ ├── activity_main.xml
|
||||
│ ├── drawable/
|
||||
│ │ ├── splash_gradient.xml
|
||||
│ ├── mipmap/
|
||||
│ │ ├── ic_launcher.png // Ikon aplikasi
|
||||
│ │ ├── ic_launcher_round.png
|
||||
│ ├── values/
|
||||
│ ├── colors.xml
|
||||
│ ├── strings.xml
|
||||
│ ├── themes.xml
|
||||
│
|
||||
└── AndroidManifest.xml
|
||||
```
|
||||
- 💻 **Android Studio (Kotlin)**
|
||||
- 🧱 **Jetpack Compose** & **XML Layouts** untuk desain antarmuka
|
||||
- 🔗 **Intent** untuk navigasi antar activity
|
||||
- 🎨 **Drawable XML & colors.xml** untuk tema warna dan efek gradasi
|
||||
- 🧪 **Unit Test (disarankan)** untuk menguji akurasi perhitungan BMI
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Kontribusi & Kredit
|
||||
Aplikasi ini dikembangkan dengan bantuan **ChatGPT (OpenAI)** dalam pembuatan kode, desain antarmuka, dan penyusunan dokumentasi.
|
||||
Semua logika, pengujian, dan penyempurnaan dilakukan secara mandiri oleh pengembang.
|
||||
Aplikasi ini dikembangkan dengan bantuan **ChatGPT (OpenAI)** dalam pembuatan kode, desain antarmuka, dan dokumentasi.
|
||||
Semua logika perhitungan, pengujian, dan penyempurnaan dilakukan mandiri oleh pengembang.
|
||||
|
||||
---
|
||||
|
||||
## 🕓 Change Log (Ringkas)
|
||||
- ✅ **Migrasi kode dasar** dari kalkulator tip ke kalkulator BMI berbasis Kotlin Compose.
|
||||
- ⚙️ **Penambahan mode satuan USC (Inci & Lbs)** dengan validasi tinggi minimal 4 inci.
|
||||
- 🧮 **Perbaikan rumus perhitungan BMI** agar sesuai standar WHO.
|
||||
- 🎨 **Desain ulang Splash Screen** dengan tombol “MULAI” berwarna hijau dan latar gradasi biru-hijau.
|
||||
- 🚀 **Optimalisasi UX** — hasil BMI hanya muncul setelah tombol **“Hitung BMI”** ditekan.
|
||||
- 🧰 **Penambahan file `colors.xml` dan drawable gradient** untuk tema.
|
||||
|
||||
---
|
||||
|
||||
## 📜 Lisensi
|
||||
Proyek ini dibuat untuk tujuan pembelajaran dalam mata kuliah **Pemrograman Perangkat Bergerak** dan tidak untuk tujuan komersial.
|
||||
Lisensi mengikuti [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
---
|
||||
|
||||
@ -45,14 +45,13 @@ fun BmiCalculatorLayout() {
|
||||
var weightInput by remember { mutableStateOf("") }
|
||||
var useMetricSystem by remember { mutableStateOf(true) } // ✅ toggle sistem satuan
|
||||
var errorMessage by remember { mutableStateOf("") }
|
||||
var showResult by remember { mutableStateOf(false) } // ✅ hasil hanya tampil setelah tombol ditekan
|
||||
var showResult by remember { mutableStateOf(false) }
|
||||
|
||||
val height = heightInput.toFloatOrNull() ?: 0f
|
||||
val weight = weightInput.toFloatOrNull() ?: 0f
|
||||
|
||||
val isValid = validateInput(height, weight, useMetricSystem)
|
||||
|
||||
// Konversi tinggi & berat ke sistem metrik (meter & kg)
|
||||
val heightInMeters = if (useMetricSystem) height / 100f else height * 0.0254f
|
||||
val weightInKg = if (useMetricSystem) weight else weight * 0.453592f
|
||||
|
||||
@ -176,7 +175,6 @@ fun BmiCalculatorLayout() {
|
||||
)
|
||||
}
|
||||
|
||||
// Pesan error
|
||||
if (errorMessage.isNotEmpty()) {
|
||||
Text(
|
||||
text = errorMessage,
|
||||
@ -186,7 +184,7 @@ fun BmiCalculatorLayout() {
|
||||
)
|
||||
}
|
||||
|
||||
// Hasil BMI hanya tampil setelah ditekan tombol
|
||||
// Hasil BMI
|
||||
if (showResult && isValid) {
|
||||
val categoryColor = when (category) {
|
||||
"Kurus" -> MaterialTheme.colorScheme.tertiaryContainer
|
||||
@ -217,10 +215,34 @@ fun BmiCalculatorLayout() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 📘 Panduan Kategori BMI
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = "Panduan Kategori BMI",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Divider()
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text("• Kurus : BMI < 18.5")
|
||||
Text("• Normal : 18.5 ≤ BMI < 25")
|
||||
Text("• Kelebihan Berat : 25 ≤ BMI < 30")
|
||||
Text("• Obesitas : BMI ≥ 30")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun EditNumberField(
|
||||
@StringRes label: Int,
|
||||
@ -257,6 +279,16 @@ fun validateInput(height: Float, weight: Float, useMetric: Boolean): Boolean {
|
||||
height >= 4f && height <= 100f && weight in 5f..550f
|
||||
}
|
||||
|
||||
fun calculateBMI(weight: Float, height: Float, useMetric: Boolean = true): Float {
|
||||
if (height <= 0) return 0f
|
||||
|
||||
val heightInMeters = if (useMetric) height / 100f else height * 0.0254f
|
||||
val weightInKg = if (useMetric) weight else weight * 0.453592f
|
||||
|
||||
return weightInKg / heightInMeters.pow(2)
|
||||
}
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun BmiCalculatorPreview() {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package com.example.tiptime
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class SplashActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -11,11 +11,9 @@ class SplashActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_splash)
|
||||
|
||||
val btnMulai = findViewById<Button>(R.id.btnMulai)
|
||||
|
||||
btnMulai.setOnClickListener {
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
startActivity(intent)
|
||||
//finish() // supaya tidak bisa kembali ke splash dengan tombol back
|
||||
startActivity(Intent(this, MainActivity::class.java))
|
||||
//finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
app/src/main/res/drawable/circle_bg.xml
Normal file
6
app/src/main/res/drawable/circle_bg.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#1FFFFFFF" />
|
||||
<stroke android:color="#40FFFFFF" android:width="2dp"/>
|
||||
</shape>
|
||||
@ -1,13 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:angle="270"
|
||||
android:startColor="#4A90E2"
|
||||
android:centerColor="#6A5ACD"
|
||||
android:endColor="#8A2BE2"
|
||||
android:useLevel="false" />
|
||||
|
||||
android:startColor="@color/purple_200"
|
||||
android:centerColor="@color/teal_200"
|
||||
android:endColor="@color/purple_700"
|
||||
android:angle="270" />
|
||||
</shape>
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="24dp"
|
||||
android:background="@drawable/splash_gradient">
|
||||
android:background="@drawable/splash_gradient"
|
||||
tools:context=".SplashActivity">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="160dp"
|
||||
android:src="@mipmap/ic_launcher_round"
|
||||
android:contentDescription="Foto Profil"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:layout_marginBottom="20dp"
|
||||
|
||||
android:padding="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvName"
|
||||
@ -20,12 +24,12 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Rafi Fattan Fitriardi"
|
||||
android:textStyle="bold"
|
||||
android:textSize="20sp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="22sp"
|
||||
android:textColor="@android:color/white"
|
||||
android:shadowColor="#80000000"
|
||||
android:shadowDx="1"
|
||||
android:shadowDy="1"
|
||||
android:shadowRadius="2"
|
||||
android:shadowDx="2"
|
||||
android:shadowDy="2"
|
||||
android:shadowRadius="4"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<TextView
|
||||
@ -33,12 +37,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="202310715002"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#E0E0E0"
|
||||
android:shadowColor="#80000000"
|
||||
android:shadowDx="1"
|
||||
android:shadowDy="1"
|
||||
android:shadowRadius="2"
|
||||
android:textSize="18sp"
|
||||
android:textColor="#F0F0F0"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<TextView
|
||||
@ -47,20 +47,18 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Pemrograman Perangkat Bergerak - F5A5"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#E0E0E0"
|
||||
android:shadowColor="#80000000"
|
||||
android:shadowDx="1"
|
||||
android:shadowDy="1"
|
||||
android:shadowRadius="2"
|
||||
android:layout_marginBottom="24dp" />
|
||||
android:textColor="#EDEDED"
|
||||
android:layout_marginBottom="32dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnMulai"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="MULAI"
|
||||
android:backgroundTint="#4CAF50"
|
||||
android:textColor="@android:color/white"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:paddingVertical="12dp" />
|
||||
android:backgroundTint="@android:color/holo_green_dark"
|
||||
android:elevation="6dp"
|
||||
android:paddingHorizontal="36dp"
|
||||
android:paddingVertical="14dp"
|
||||
android:fontFamily="sans-serif-medium" />
|
||||
</LinearLayout>
|
||||
|
||||
16
app/src/main/res/values/colors.xml
Normal file
16
app/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Warna tema dasar -->
|
||||
<color name="purple_200">#BB86FC</color>
|
||||
<color name="purple_500">#6200EE</color>
|
||||
<color name="purple_700">#3700B3</color>
|
||||
<color name="teal_200">#03DAC5</color>
|
||||
<color name="teal_700">#018786</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
|
||||
<!-- Gradasi untuk splash screen -->
|
||||
<color name="gradient_start">#4CAF50</color> <!-- hijau terang -->
|
||||
<color name="gradient_center">#81C784</color> <!-- hijau lembut -->
|
||||
<color name="gradient_end">#C8E6C9</color> <!-- hijau muda -->
|
||||
</resources>
|
||||
@ -4,8 +4,7 @@ import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Unit test untuk memastikan fungsi perhitungan dan kategori BMI
|
||||
* berjalan dengan benar.
|
||||
* Unit test untuk memastikan fungsi perhitungan dan kategori BMI berjalan dengan benar.
|
||||
*
|
||||
* Lokasi file: app/src/test/java/com/example/tiptime/BmiUnitTest.kt
|
||||
*/
|
||||
@ -13,15 +12,15 @@ class BmiUnitTest {
|
||||
|
||||
@Test
|
||||
fun calculateBMI_isAccurate() {
|
||||
// Data: berat 70 kg, tinggi 170 cm
|
||||
val result = calculateBMI(70f, 170f)
|
||||
// Data: berat 70 kg, tinggi 170 cm (sistem metrik)
|
||||
val result = calculateBMI(70f, 170f, true)
|
||||
// Hasil ekspektasi ≈ 24.22
|
||||
assertEquals(24.22f, result, 0.01f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun calculateBMI_zeroHeight_returnsZero() {
|
||||
val result = calculateBMI(70f, 0f)
|
||||
val result = calculateBMI(70f, 0f, true)
|
||||
assertEquals(0f, result, 0.0f)
|
||||
}
|
||||
|
||||
@ -51,13 +50,13 @@ class BmiUnitTest {
|
||||
|
||||
@Test
|
||||
fun validateInput_validValues_returnsTrue() {
|
||||
val isValid = validateInput(170f, 65f)
|
||||
val isValid = validateInput(170f, 65f, true)
|
||||
assertEquals(true, isValid)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateInput_invalidValues_returnsFalse() {
|
||||
val isValid = validateInput(5f, 500f)
|
||||
val isValid = validateInput(5f, 500f, true)
|
||||
assertEquals(false, isValid)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user