390 lines
9.8 KiB
Markdown
390 lines
9.8 KiB
Markdown
# 📱 Ringkasan Implementasi Fitur Mata Kuliah dan Absen Kehadiran
|
|
|
|
## ✅ Fitur yang Telah Ditambahkan
|
|
|
|
### 1. **Daftar Mata Kuliah**
|
|
- Menampilkan semua mata kuliah yang tersedia
|
|
- Informasi lengkap: kode, nama, dosen, jadwal, ruang, SKS
|
|
- Dapat memilih mata kuliah untuk absensi
|
|
- Menyimpan pilihan mata kuliah terakhir
|
|
|
|
### 2. **Absensi dengan Mata Kuliah**
|
|
- User dapat memilih mata kuliah sebelum absensi
|
|
- Data kehadiran disimpan dengan informasi mata kuliah lengkap
|
|
- Dikirim ke N8n webhook dengan format JSON yang lebih lengkap
|
|
|
|
### 3. **Riwayat Kehadiran**
|
|
- Melihat riwayat absensi per mata kuliah
|
|
- Tanggal, waktu, dan status kehadiran
|
|
- Dapat difilter berdasarkan status (hadir, terlambat, tidak hadir, dll)
|
|
|
|
### 4. **Laporan Kehadiran**
|
|
- Statistik kehadiran per mata kuliah
|
|
- Persentase kehadiran dengan visual indicator (hijau/orange/merah)
|
|
- Total sesi, hadir, terlambat, tidak hadir, izin/sakit
|
|
- Automatic calculation dari history kehadiran
|
|
|
|
---
|
|
|
|
## 📁 File-File yang Ditambahkan
|
|
|
|
### Models Layer
|
|
- **`models/CourseModels.kt`** - Data class untuk Course, Attendance, AttendanceStatus, AttendanceReport
|
|
|
|
### Configuration Layer
|
|
- **`config/CourseConfig.kt`** - Konfigurasi mata kuliah dan threshold kehadiran
|
|
|
|
### Service Layer
|
|
- **`utils/CourseService.kt`** - Service untuk CRUD operasi mata kuliah dan kehadiran
|
|
- **`utils/AttendanceUtils.kt`** - Utility function untuk operasi kehadiran
|
|
|
|
### UI Components Layer
|
|
- **`ui/components/CourseComponents.kt`** - Reusable components untuk tampilan mata kuliah dan kehadiran
|
|
|
|
### Screen/UI Layer
|
|
- **`ui/screens/CourseScreen.kt`** - Screens untuk menampilkan daftar dan detail mata kuliah
|
|
|
|
---
|
|
|
|
## 🔄 Alur Data Flow
|
|
|
|
```
|
|
User Interface (MainActivity.kt)
|
|
↓
|
|
CourseService (Manage data)
|
|
↓
|
|
SharedPreferences (Local Storage)
|
|
↓
|
|
N8nService (Send to server)
|
|
↓
|
|
N8n Webhook → Google Sheets
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Data Struktur
|
|
|
|
### Course Model
|
|
```kotlin
|
|
data class Course(
|
|
val courseId: String, // ID unik mata kuliah
|
|
val courseCode: String, // Kode mata kuliah (PBO2024)
|
|
val courseName: String, // Nama mata kuliah
|
|
val lecturer: String, // Nama dosen
|
|
val credits: Int, // Jumlah SKS
|
|
val schedule: String, // Jadwal (Senin 08:00-09:30)
|
|
val room: String, // Ruang kelas (A-101)
|
|
val semester: Int, // Semester
|
|
val isActive: Boolean // Status aktif
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Perubahan di MainActivity.kt
|
|
|
|
### Sebelum
|
|
```kotlin
|
|
fun AbsensiScreen(
|
|
modifier: Modifier = Modifier,
|
|
activity: ComponentActivity
|
|
) {
|
|
var state by remember { mutableStateOf(AttendanceState()) }
|
|
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
|
|
val n8nService = remember { N8nService(activity) }
|
|
|
|
// Hanya absensi tanpa mata kuliah
|
|
n8nService.submitAttendance(...)
|
|
}
|
|
```
|
|
|
|
### Sesudah
|
|
```kotlin
|
|
fun AbsensiScreen(
|
|
modifier: Modifier = Modifier,
|
|
activity: ComponentActivity
|
|
) {
|
|
var state by remember { mutableStateOf(AttendanceState()) }
|
|
var courses by remember { mutableStateOf<List<Course>>(emptyList()) }
|
|
var selectedCourse by remember { mutableStateOf<Course?>(null) }
|
|
|
|
val courseService = remember { CourseService(context) }
|
|
|
|
// Initialize courses
|
|
LaunchedEffect(Unit) {
|
|
courseService.initializeSampleData()
|
|
courses = courseService.getCourses()
|
|
selectedCourse = courseService.getSelectedCourse() ?: courses.firstOrNull()
|
|
}
|
|
|
|
// Absensi dengan pilihan mata kuliah
|
|
n8nService.submitAttendanceWithCourse(
|
|
courseId = selectedCourse!!.courseId,
|
|
courseCode = selectedCourse!!.courseCode,
|
|
courseName = selectedCourse!!.courseName,
|
|
...
|
|
)
|
|
|
|
// Simpan ke database lokal
|
|
courseService.saveAttendance(attendance)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔌 Perubahan di N8nService.kt
|
|
|
|
### Method Baru
|
|
```kotlin
|
|
fun submitAttendanceWithCourse(
|
|
npm: String,
|
|
nama: String,
|
|
courseId: String,
|
|
courseCode: String,
|
|
courseName: String,
|
|
latitude: Double,
|
|
longitude: Double,
|
|
foto: Bitmap,
|
|
isTest: Boolean = false,
|
|
callback: SubmitCallback? = null
|
|
) {
|
|
// Send to N8n dengan informasi mata kuliah
|
|
val json = JSONObject().apply {
|
|
put("npm", npm)
|
|
put("nama", nama)
|
|
put("courseId", courseId)
|
|
put("courseCode", courseCode)
|
|
put("courseName", courseName)
|
|
put("latitude", latitude)
|
|
put("longitude", longitude)
|
|
put("timestamp", System.currentTimeMillis())
|
|
put("foto_base64", bitmapToBase64(foto))
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 💾 Penyimpanan Data
|
|
|
|
Data disimpan di **SharedPreferences** dengan struktur:
|
|
|
|
```
|
|
SharedPreferences Database: "course_attendance_db"
|
|
├── courses_list (JSON)
|
|
│ └── [Course, Course, Course, ...]
|
|
├── attendance_list (JSON)
|
|
│ └── [Attendance, Attendance, Attendance, ...]
|
|
└── selected_course (JSON)
|
|
└── Current selected Course
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Cara Menggunakan
|
|
|
|
### 1. Initialize CourseService
|
|
```kotlin
|
|
val courseService = CourseService(context)
|
|
courseService.initializeSampleData()
|
|
```
|
|
|
|
### 2. Dapatkan Daftar Mata Kuliah
|
|
```kotlin
|
|
val courses = courseService.getCourses()
|
|
courses.forEach { course ->
|
|
println("${course.courseCode} - ${course.courseName}")
|
|
}
|
|
```
|
|
|
|
### 3. Pilih Mata Kuliah
|
|
```kotlin
|
|
val selectedCourse = courses.first()
|
|
courseService.setSelectedCourse(selectedCourse)
|
|
```
|
|
|
|
### 4. Simpan Kehadiran
|
|
```kotlin
|
|
val attendance = Attendance(
|
|
npm = "202310715082",
|
|
nama = "Fazri Abdurrahman",
|
|
courseId = "COURSE_001",
|
|
courseCode = "PBO2024",
|
|
courseName = "Pemrograman Berorientasi Objek",
|
|
latitude = -7.000123,
|
|
longitude = 110.400456,
|
|
timestamp = System.currentTimeMillis(),
|
|
date = courseService.getCurrentDate(),
|
|
time = courseService.formatTime(System.currentTimeMillis()),
|
|
status = AttendanceStatus.PRESENT,
|
|
isValid = true
|
|
)
|
|
courseService.saveAttendance(attendance)
|
|
```
|
|
|
|
### 5. Buat Laporan Kehadiran
|
|
```kotlin
|
|
val report = courseService.generateAttendanceReport("COURSE_001")
|
|
println("Persentase: ${report.attendancePercentage}%")
|
|
println("Hadir: ${report.presentCount}/${report.totalSessions}")
|
|
```
|
|
|
|
---
|
|
|
|
## 📱 UI Components yang Baru
|
|
|
|
### CourseCard
|
|
Menampilkan informasi singkat mata kuliah dengan design yang menarik
|
|
|
|
### CourseListSection
|
|
List of courses dengan scroll support dan loading state
|
|
|
|
### AttendanceReportCard
|
|
Menampilkan statistik kehadiran dengan progress visual
|
|
|
|
### AttendanceDetailCard
|
|
Menampilkan detail satu record kehadiran
|
|
|
|
### AttendanceHistoryList
|
|
List riwayat kehadiran dengan infinite scroll
|
|
|
|
---
|
|
|
|
## 🔧 Konfigurasi
|
|
|
|
### Tambah Mata Kuliah Baru
|
|
Edit `CourseConfig.kt`:
|
|
```kotlin
|
|
Course(
|
|
courseId = "COURSE_006",
|
|
courseCode = "NEWCODE2024",
|
|
courseName = "Nama Mata Kuliah Baru",
|
|
lecturer = "Nama Dosen",
|
|
credits = 3,
|
|
schedule = "Hari HH:MM-HH:MM",
|
|
room = "Ruang Kelas",
|
|
semester = 4,
|
|
isActive = true
|
|
)
|
|
```
|
|
|
|
### Ubah Threshold Kehadiran
|
|
Edit `CourseConfig.kt`:
|
|
```kotlin
|
|
const val MINIMUM_ATTENDANCE_PERCENTAGE = 80.0 // Minimum 80%
|
|
const val MAX_EXCUSED_ABSENCES = 3 // Maksimal 3 izin
|
|
const val MAX_SICK_LEAVE = 2 // Maksimal 2 sakit
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing
|
|
|
|
### Test Scenario 1: Daftar Mata Kuliah
|
|
1. Buka app
|
|
2. Lihat daftar mata kuliah di section atas
|
|
3. Verifikasi ada 5 mata kuliah default
|
|
|
|
### Test Scenario 2: Pilih Mata Kuliah
|
|
1. Klik tombol "Pilih Mata Kuliah"
|
|
2. Dialog muncul dengan daftar mata kuliah
|
|
3. Pilih salah satu
|
|
4. Verifikasi mata kuliah terpilih ditampilkan
|
|
|
|
### Test Scenario 3: Absensi Lengkap
|
|
1. Pilih mata kuliah
|
|
2. Ambil foto
|
|
3. Tunggu lokasi terdeteksi
|
|
4. Klik "Kirim Absensi"
|
|
5. Verifikasi pesan sukses dan data tersimpan
|
|
|
|
### Test Scenario 4: Lihat Riwayat
|
|
1. Setelah absensi berhasil
|
|
2. Buka detail mata kuliah
|
|
3. Lihat riwayat kehadiran
|
|
4. Verifikasi ada record kehadiran baru
|
|
|
|
### Test Scenario 5: Laporan Kehadiran
|
|
1. Buka detail mata kuliah
|
|
2. Lihat statistik kehadiran di atas
|
|
3. Verifikasi persentase dihitung dengan benar
|
|
|
|
---
|
|
|
|
## 📦 Dependencies Baru
|
|
|
|
Tambahkan di `app/build.gradle.kts`:
|
|
```gradle
|
|
implementation("com.google.code.gson:gson:2.10.1")
|
|
```
|
|
|
|
---
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
### Issue: "Tidak ada mata kuliah"
|
|
**Solusi**:
|
|
```kotlin
|
|
// Pastikan initialization di startup
|
|
courseService.initializeSampleData()
|
|
```
|
|
|
|
### Issue: Data tidak tersimpan
|
|
**Solusi**:
|
|
- Cek SharedPreferences di Device Explorer
|
|
- Verifikasi format data JSON
|
|
- Cek permissions untuk write
|
|
|
|
### Issue: Kehadiran tidak terkirim ke N8n
|
|
**Solusi**:
|
|
- Pastikan network connection aktif
|
|
- Verifikasi webhook URL di AttendanceConfig
|
|
- Cek logcat untuk error details
|
|
|
|
### Issue: Laporan kehadiran tidak update
|
|
**Solusi**:
|
|
```kotlin
|
|
// Force refresh
|
|
val report = courseService.generateAttendanceReport(courseId)
|
|
```
|
|
|
|
---
|
|
|
|
## 📈 Fitur yang Mungkin Ditambahkan di Masa Depan
|
|
|
|
- [ ] Filter attendance berdasarkan rentang tanggal
|
|
- [ ] Export laporan ke PDF/Excel
|
|
- [ ] Multi-semester support
|
|
- [ ] Notification untuk kehadiran di bawah threshold
|
|
- [ ] Analytics dashboard
|
|
- [ ] Sync dengan server API
|
|
- [ ] Offline mode dengan sync otomatis
|
|
- [ ] QR code untuk quick attendance
|
|
|
|
---
|
|
|
|
## 📝 Catatan Penting
|
|
|
|
1. **Data Privacy**: Semua data sensitif dikirim via HTTPS
|
|
2. **Local Storage**: Menggunakan SharedPreferences (aman untuk level ini)
|
|
3. **Photo Handling**: Foto dikonversi ke Base64 hanya saat pengiriman
|
|
4. **Database**: Menggunakan Gson untuk serialisasi/deserialisasi JSON
|
|
|
|
---
|
|
|
|
## 🎯 Hasil Akhir
|
|
|
|
✅ **Fitur Mata Kuliah** - Daftar, pilih, dan kelola mata kuliah
|
|
✅ **Fitur Absensi** - Absensi dengan pilihan mata kuliah lengkap
|
|
✅ **Fitur Riwayat** - Lihat history kehadiran per mata kuliah
|
|
✅ **Fitur Laporan** - Statistik dan analisis kehadiran
|
|
✅ **Integration** - Terintegrasi dengan N8n webhook
|
|
✅ **Storage** - Penyimpanan lokal dengan SharedPreferences
|
|
|
|
---
|
|
|
|
**Status**: ✅ **SELESAI** - Semua fitur siap digunakan
|
|
**Last Updated**: 14 Januari 2026
|
|
**Version**: 1.0
|
|
|