180 lines
4.6 KiB
Markdown
180 lines
4.6 KiB
Markdown
# Persistent Cooldown Implementation
|
|
|
|
Implementasi cooldown persisten untuk panic button yang akan tetap berlaku meskipun user keluar dan masuk kembali dari aplikasi.
|
|
|
|
## Features
|
|
|
|
1. **Persistent Storage**: Cooldown state disimpan menggunakan SharedPreferences
|
|
2. **Auto-restore**: Cooldown akan otomatis dipulihkan saat aplikasi dibuka kembali
|
|
3. **Expiration Check**: Otomatis membersihkan cooldown yang sudah expired
|
|
4. **Force Clear**: Method untuk membersihkan cooldown secara paksa (untuk testing/admin)
|
|
|
|
## Implementation Details
|
|
|
|
### 1. SharedPreferences Keys
|
|
|
|
```dart
|
|
static const String _cooldownEndTimeKey = 'panic_cooldown_end_time';
|
|
static const String _cooldownActiveKey = 'panic_cooldown_active';
|
|
```
|
|
|
|
### 2. Core Methods
|
|
|
|
#### Load Cooldown State
|
|
|
|
```dart
|
|
Future<void> _loadCooldownState() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final cooldownEndTime = prefs.getString(_cooldownEndTimeKey);
|
|
|
|
if (cooldownEndTime != null) {
|
|
final endTime = DateTime.parse(cooldownEndTime);
|
|
final now = DateTime.now();
|
|
|
|
if (now.isBefore(endTime)) {
|
|
// Cooldown is still active
|
|
isCooldownActive.value = true;
|
|
cooldownSeconds.value = endTime.difference(now).inSeconds;
|
|
_startCooldownTimer();
|
|
} else {
|
|
// Cooldown has expired, clean up
|
|
await _clearCooldownState();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Save Cooldown State
|
|
|
|
```dart
|
|
Future<void> _saveCooldownState(DateTime endTime) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString(_cooldownEndTimeKey, endTime.toIso8601String());
|
|
await prefs.setBool(_cooldownActiveKey, true);
|
|
}
|
|
```
|
|
|
|
#### Clear Cooldown State
|
|
|
|
```dart
|
|
Future<void> _clearCooldownState() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.remove(_cooldownEndTimeKey);
|
|
await prefs.remove(_cooldownActiveKey);
|
|
isCooldownActive.value = false;
|
|
cooldownSeconds.value = 0;
|
|
}
|
|
```
|
|
|
|
### 3. Integration with Existing Code
|
|
|
|
#### Modified \_startCooldown()
|
|
|
|
```dart
|
|
void _startCooldown() {
|
|
int cooldownDuration = _calculateCooldownDuration();
|
|
|
|
isCooldownActive.value = true;
|
|
cooldownSeconds.value = cooldownDuration;
|
|
_updateCooldownTimeString();
|
|
|
|
// Save cooldown end time to persistent storage
|
|
final endTime = DateTime.now().add(Duration(seconds: cooldownDuration));
|
|
_saveCooldownState(endTime);
|
|
|
|
_startCooldownTimer();
|
|
}
|
|
```
|
|
|
|
#### Modified \_endCooldown()
|
|
|
|
```dart
|
|
void _endCooldown() {
|
|
_cooldownTimer?.cancel();
|
|
isCooldownActive.value = false;
|
|
cooldownSeconds.value = 0;
|
|
cooldownTimeString.value = '';
|
|
|
|
// Clear persistent storage
|
|
_clearCooldownState();
|
|
}
|
|
```
|
|
|
|
### 4. Controller Initialization
|
|
|
|
#### In onInit()
|
|
|
|
```dart
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
|
|
// Load cooldown state from persistent storage
|
|
_loadCooldownState();
|
|
|
|
// ... other initialization code
|
|
}
|
|
```
|
|
|
|
## Usage Scenarios
|
|
|
|
### 1. App Launch with Active Cooldown
|
|
|
|
- User mengaktifkan panic button
|
|
- Cooldown dimulai (5 menit)
|
|
- User keluar dari aplikasi
|
|
- User membuka aplikasi kembali setelah 2 menit
|
|
- Cooldown akan otomatis dipulihkan dengan 3 menit tersisa
|
|
|
|
### 2. App Launch with Expired Cooldown
|
|
|
|
- User mengaktifkan panic button
|
|
- Cooldown dimulai (5 menit)
|
|
- User keluar dari aplikasi
|
|
- User membuka aplikasi kembali setelah 6 menit
|
|
- Cooldown akan otomatis dibersihkan karena sudah expired
|
|
|
|
### 3. Force Clear Cooldown
|
|
|
|
- Admin atau developer dapat menggunakan method `forceClearCooldown()`
|
|
- Berguna untuk testing atau situasi darurat
|
|
|
|
## Testing
|
|
|
|
### Manual Testing Steps
|
|
|
|
1. Aktivasi panic button hingga cooldown aktif
|
|
2. Tutup aplikasi sepenuhnya
|
|
3. Buka aplikasi kembali
|
|
4. Verify cooldown masih aktif dengan waktu yang tepat
|
|
5. Tunggu hingga cooldown habis
|
|
6. Verify panic button dapat digunakan lagi
|
|
|
|
### Edge Cases
|
|
|
|
- Perubahan timezone
|
|
- Perubahan waktu sistem
|
|
- Aplikasi di-kill oleh sistem
|
|
- Storage permission issues
|
|
|
|
## Security Considerations
|
|
|
|
1. **No sensitive data**: Hanya menyimpan timestamp, tidak ada data sensitif
|
|
2. **Local storage only**: Menggunakan SharedPreferences yang bersifat lokal
|
|
3. **Validation**: Selalu validasi timestamp sebelum menggunakan
|
|
4. **Fallback**: Jika ada error, default ke state aman (no cooldown)
|
|
|
|
## Performance Considerations
|
|
|
|
1. **Minimal storage**: Hanya menyimpan 2 key-value pairs
|
|
2. **Efficient loading**: Loading dilakukan sekali saat app start
|
|
3. **Cleanup**: Otomatis membersihkan expired data
|
|
4. **Timer optimization**: Reuse existing timer mechanism
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Server sync**: Sinkronisasi dengan server untuk multi-device
|
|
2. **Usage analytics**: Track cooldown patterns
|
|
3. **Dynamic duration**: Cooldown duration berdasarkan usage pattern
|
|
4. **Notification**: Notify user saat cooldown berakhir
|