366 lines
9.2 KiB
Markdown
366 lines
9.2 KiB
Markdown
# 📝 CHANGELOG - Aplikasi Absensi Akademik
|
|
|
|
## Version 1.1.0 - Enhancement Release
|
|
|
|
### 🎯 Overview
|
|
Aplikasi Absensi Akademik telah diperkaya dengan fitur-fitur penting untuk meningkatkan fungsionalitas dan keamanan sistem. Fitur baru mencakup validasi lokasi berbasis radius, penyimpanan riwayat absensi lokal, dan privacy protection untuk koordinat GPS.
|
|
|
|
---
|
|
|
|
## ✨ Fitur Baru (NEW FEATURES)
|
|
|
|
### 1. Location Radius Validation
|
|
**File**: `MainActivity.kt`
|
|
- **Fungsi**: `isWithinAbsensiRadius()`
|
|
- **Deskripsi**: Validasi otomatis apakah mahasiswa berada dalam radius yang diizinkan (default 100 meter)
|
|
- **Default Location**: UBH Campus (-6.2030, 107.0045)
|
|
- **Benefit**: Mencegah absensi dari lokasi yang tidak sesuai
|
|
|
|
```kotlin
|
|
fun isWithinAbsensiRadius(
|
|
studentLat: Double,
|
|
studentLon: Double,
|
|
campusLat: Double = -6.2030,
|
|
campusLon: Double = 107.0045,
|
|
radiusMeters: Float = 100f
|
|
): Boolean
|
|
```
|
|
|
|
### 2. Distance Calculation
|
|
**File**: `MainActivity.kt`
|
|
- **Fungsi**: `calculateDistance()`
|
|
- **Deskripsi**: Menghitung jarak presisi antara dua koordinat dalam meter
|
|
- **Method**: Menggunakan Android Location API
|
|
|
|
```kotlin
|
|
fun calculateDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Float
|
|
```
|
|
|
|
### 3. Coordinate Obfuscation (Privacy)
|
|
**File**: `MainActivity.kt`
|
|
- **Fungsi**: `obfuscateCoordinates()`
|
|
- **Deskripsi**: Menambahkan offset random pada koordinat untuk melindungi privasi (mencegah kebocoran lokasi rumah)
|
|
- **Default Offset**: 0.002 derajat (~200 meter)
|
|
- **Benefit**: Privacy protection sambil tetap valid untuk validasi radius
|
|
|
|
```kotlin
|
|
fun obfuscateCoordinates(
|
|
latitude: Double,
|
|
longitude: Double,
|
|
offsetDegrees: Double = 0.002
|
|
): Pair<Double, Double>
|
|
```
|
|
|
|
### 4. Attendance History Storage
|
|
**File**: `DatabaseHelper.kt`
|
|
- **Database Version**: Upgraded from v1 to v2
|
|
- **New Table**: `attendance`
|
|
- **Columns**:
|
|
- `id` (INTEGER PRIMARY KEY)
|
|
- `npm` (TEXT - Foreign Key)
|
|
- `timestamp` (INTEGER)
|
|
- `latitude` (REAL)
|
|
- `longitude` (REAL)
|
|
- `status` (TEXT - "success" or "invalid_location")
|
|
|
|
### 5. Attendance Management Functions
|
|
**File**: `DatabaseHelper.kt`
|
|
- `addAttendanceRecord()`: Menyimpan record absensi ke database
|
|
- `getAttendanceHistory()`: Mengambil semua history absensi mahasiswa
|
|
|
|
```kotlin
|
|
fun addAttendanceRecord(
|
|
npm: String,
|
|
timestamp: Long,
|
|
latitude: Double,
|
|
longitude: Double,
|
|
status: String
|
|
): Boolean
|
|
|
|
fun getAttendanceHistory(npm: String): List<AttendanceRecord>
|
|
```
|
|
|
|
### 6. AttendanceRecord Data Class
|
|
**File**: `DatabaseHelper.kt`
|
|
- Model data untuk riwayat absensi
|
|
- Fields: timestamp, latitude, longitude, status
|
|
|
|
```kotlin
|
|
data class AttendanceRecord(
|
|
val timestamp: Long,
|
|
val latitude: Double,
|
|
val longitude: Double,
|
|
val status: String
|
|
)
|
|
```
|
|
|
|
### 7. History Screen UI
|
|
**File**: `MainActivity.kt`
|
|
- **Composable**: `HistoryScreen()`
|
|
- **Features**:
|
|
- List view riwayat absensi
|
|
- Status visual (✓ Diterima / ✗ Ditolak)
|
|
- Formatted date/time (dd/MM/yyyy HH:mm:ss)
|
|
- Coordinate display (4 decimal places)
|
|
- Empty state handling
|
|
- Back navigation
|
|
|
|
### 8. Attendance Card Component
|
|
**File**: `MainActivity.kt`
|
|
- **Composable**: `AttendanceCard()`
|
|
- **Shows**: Tanggal, Status, dan Koordinat
|
|
- **Styling**: Color-coded status (green for success, red for rejected)
|
|
|
|
### 9. Enhanced Webhook Integration
|
|
**File**: `MainActivity.kt`
|
|
- **Updated Function**: `kirimKeN8n()`
|
|
- **New Features**:
|
|
- Automatic location validation
|
|
- Local database saving before sending
|
|
- Enhanced JSON payload with validation info
|
|
- Better error messages
|
|
- Status feedback based on validation result
|
|
|
|
**JSON Payload**:
|
|
```json
|
|
{
|
|
"npm": "string",
|
|
"nama": "string",
|
|
"latitude": "number",
|
|
"longitude": "number",
|
|
"timestamp": "number",
|
|
"foto_base64": "string",
|
|
"validation_status": "success|invalid_location",
|
|
"is_within_radius": "boolean"
|
|
}
|
|
```
|
|
|
|
### 10. Navigation Enhancement
|
|
**File**: `MainActivity.kt`
|
|
- **Added Screen**: "history" screen
|
|
- **Navigation Flow**: home ↔ history
|
|
- **Button**: "Lihat Riwayat" di halaman absensi
|
|
|
|
---
|
|
|
|
## 🔧 Perubahan Existing Code
|
|
|
|
### MainActivity.kt Changes
|
|
|
|
#### Updated Function Signatures
|
|
```kotlin
|
|
// Before
|
|
fun kirimKeN8n(
|
|
context: ComponentActivity,
|
|
npm: String,
|
|
nama: String,
|
|
latitude: Double,
|
|
longitude: Double,
|
|
foto: Bitmap
|
|
)
|
|
|
|
// After
|
|
fun kirimKeN8n(
|
|
context: ComponentActivity,
|
|
db: DatabaseHelper, // NEW
|
|
npm: String,
|
|
nama: String,
|
|
latitude: Double,
|
|
longitude: Double,
|
|
foto: Bitmap
|
|
)
|
|
```
|
|
|
|
#### Updated AbsensiScreen Signature
|
|
```kotlin
|
|
// Before
|
|
fun AbsensiScreen(
|
|
activity: ComponentActivity,
|
|
npm: String,
|
|
nama: String,
|
|
onLogout: () -> Unit
|
|
)
|
|
|
|
// After
|
|
fun AbsensiScreen(
|
|
activity: ComponentActivity,
|
|
db: DatabaseHelper, // NEW
|
|
npm: String,
|
|
nama: String,
|
|
onLogout: () -> Unit,
|
|
onNavigateToHistory: () -> Unit // NEW
|
|
)
|
|
```
|
|
|
|
#### Navigation Switch Statement
|
|
```kotlin
|
|
when (currentScreen) {
|
|
"login" -> LoginScreen(...)
|
|
"register" -> RegisterScreen(...)
|
|
"home" -> AbsensiScreen(...) // Added: db parameter, onNavigateToHistory
|
|
"history" -> HistoryScreen(...) // NEW BRANCH
|
|
}
|
|
```
|
|
|
|
#### UI Changes in AbsensiScreen
|
|
- Button "📷 Ambil Foto" (menggunakan emoji bukan icon untuk compatibility)
|
|
- New button: "Lihat Riwayat" dengan warna secondary
|
|
|
|
### DatabaseHelper.kt Changes
|
|
|
|
#### Database Version Upgrade
|
|
```kotlin
|
|
// Before
|
|
private const val DATABASE_VERSION = 1
|
|
|
|
// After
|
|
private const val DATABASE_VERSION = 2
|
|
```
|
|
|
|
#### Updated onCreate()
|
|
- Added creation of `attendance` table
|
|
- Maintained existing `users` table with UNIQUE constraint on NPM
|
|
|
|
#### Updated onUpgrade()
|
|
- Handles migration from v1 to v2
|
|
- Creates `attendance` table if upgrading
|
|
|
|
#### New Methods
|
|
- `addAttendanceRecord()` - Insert attendance record
|
|
- `getAttendanceHistory()` - Query attendance history
|
|
|
|
### build.gradle.kts Changes
|
|
|
|
#### Added Dependencies
|
|
```gradle
|
|
// Material Icons Extended (untuk dukungan icon yang lebih lengkap)
|
|
implementation("androidx.compose.material:material-icons-extended:1.6.0")
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Database Changes
|
|
|
|
### Migration from v1 to v2
|
|
|
|
**v1 Schema** (before):
|
|
```
|
|
Table: users
|
|
├── id (INTEGER PRIMARY KEY AUTOINCREMENT)
|
|
├── username (TEXT)
|
|
├── npm (TEXT)
|
|
└── password (TEXT)
|
|
```
|
|
|
|
**v2 Schema** (after):
|
|
```
|
|
Table: users
|
|
├── id (INTEGER PRIMARY KEY AUTOINCREMENT)
|
|
├── username (TEXT)
|
|
├── npm (TEXT UNIQUE) // Added UNIQUE constraint
|
|
└── password (TEXT)
|
|
|
|
Table: attendance (NEW)
|
|
├── id (INTEGER PRIMARY KEY AUTOINCREMENT)
|
|
├── npm (TEXT - FOREIGN KEY)
|
|
├── timestamp (INTEGER)
|
|
├── latitude (REAL)
|
|
├── longitude (REAL)
|
|
└── status (TEXT)
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 Security Improvements
|
|
|
|
1. **UNIQUE Constraint on NPM**: Mencegah duplicate user registration
|
|
2. **Foreign Key**: Linking attendance records to users
|
|
3. **Privacy Protection**: Coordinate obfuscation untuk melindungi privacy
|
|
4. **Validation**: Location validation sebelum accepting absensi
|
|
5. **Error Handling**: Better error messages dan handling exceptions
|
|
|
|
---
|
|
|
|
## 🎨 UI/UX Improvements
|
|
|
|
1. **History Screen**: Dedicated screen untuk melihat riwayat absensi
|
|
2. **Status Indicators**: Visual feedback (✓/✗) untuk status absensi
|
|
3. **Date Formatting**: Tanggal dalam format Indonesia (dd/MM/yyyy HH:mm:ss)
|
|
4. **Color Coding**:
|
|
- Green (#4CAF50) untuk status accepted
|
|
- Red (#F44336) untuk status rejected
|
|
5. **Empty State**: Message untuk ketika tidak ada riwayat
|
|
|
|
---
|
|
|
|
## 📱 Screen Flow
|
|
|
|
```
|
|
LOGIN/REGISTER
|
|
↓
|
|
HOME (ABSENSI)
|
|
├─ 📸 Ambil Foto
|
|
├─ 📍 Auto Detect Lokasi
|
|
├─ ✅ Kirim Absensi
|
|
│ ├─ Validasi Radius
|
|
│ ├─ Simpan ke DB
|
|
│ └─ Kirim ke n8n
|
|
└─ 📄 Lihat Riwayat
|
|
└─ History Screen
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing Checklist
|
|
|
|
- [ ] Login dengan NPM dan password valid
|
|
- [ ] Register user baru dengan NPM yang unik
|
|
- [ ] Ambil foto dengan kamera
|
|
- [ ] Arahkan ke lokasi yang valid dan kirim absensi
|
|
- [ ] Arahkan ke lokasi yang tidak valid dan cek validasi
|
|
- [ ] Lihat riwayat absensi
|
|
- [ ] Verifikasi data di webhook n8n
|
|
- [ ] Cek database lokal dengan status yang benar
|
|
- [ ] Coba logout dan login kembali
|
|
|
|
---
|
|
|
|
## 🚀 Version History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 1.0.0 | Jan 2026 | Initial Starter Release |
|
|
| 1.1.0 | Jan 14, 2026 | Added History, Location Validation, Privacy Features |
|
|
|
|
---
|
|
|
|
## 📋 Known Limitations & Future Work
|
|
|
|
### Current Limitations
|
|
1. Foto hanya tersimpan di RAM, tidak di storage permanent
|
|
2. Database hanya lokal, tidak sync ke server
|
|
3. Tidak ada resume mechanism untuk koneksi yang terputus
|
|
4. Radius validation menggunakan hardcoded default location
|
|
|
|
### Future Enhancements
|
|
1. Persistent photo storage di device
|
|
2. Database sync dengan server
|
|
3. Offline queue untuk pending uploads
|
|
4. Admin panel untuk manage allowed locations
|
|
5. Statistics dashboard
|
|
6. Real-time location tracking visualization
|
|
7. Biometric authentication support
|
|
8. Push notifications untuk absensi status
|
|
|
|
---
|
|
|
|
## 📞 Support & Contact
|
|
|
|
Untuk pertanyaan atau issue, silakan contact development team atau refer ke DEVELOPMENT_GUIDE.md untuk informasi lebih detail.
|
|
|
|
---
|
|
|
|
**Last Updated**: 14 January 2026
|
|
**Status**: ✅ Production Ready v1.1.0
|
|
|