189 lines
5.5 KiB
Dart
189 lines
5.5 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:mobile_monitoring/data/services/planting_cycles_service.dart';
|
|
import 'package:mobile_monitoring/data/models/service_result.dart';
|
|
import 'package:mobile_monitoring/core/utils/cycle_phase_utils.dart';
|
|
import 'package:mobile_monitoring/core/utils/phase_display_utils.dart';
|
|
|
|
class GrowthPhaseService {
|
|
final PlantingCyclesService _cyclesService;
|
|
final FirebaseFirestore _firestore;
|
|
final FirebaseAuth _auth;
|
|
|
|
GrowthPhaseService({
|
|
PlantingCyclesService? cyclesService,
|
|
FirebaseFirestore? firestore,
|
|
FirebaseAuth? auth,
|
|
}) : _cyclesService = cyclesService ?? PlantingCyclesService(),
|
|
_firestore = firestore ?? FirebaseFirestore.instance,
|
|
_auth = auth ?? FirebaseAuth.instance;
|
|
|
|
String getCurrentUserId() => _auth.currentUser?.uid ?? '';
|
|
|
|
User? getCurrentUser() => _auth.currentUser;
|
|
|
|
Stream<Map<String, dynamic>?> activeCycleStream(String userId) {
|
|
if (userId.isEmpty) {
|
|
return Stream.value(null);
|
|
}
|
|
|
|
return _cyclesService.getActiveCycleStream(userId: userId);
|
|
}
|
|
|
|
DateTime? extractStartDate(Map<String, dynamic>? cycleData) {
|
|
return CyclePhaseUtils.extractStartDate(cycleData);
|
|
}
|
|
|
|
// Calculate phase name based on days since planting
|
|
String calculateCurrentPhase(int days) {
|
|
return CyclePhaseUtils.calculateDisplayPhase(days);
|
|
}
|
|
|
|
// Get phase color
|
|
Color getPhaseColor(String phase) {
|
|
return PhaseDisplayUtils.fromName(phase).color;
|
|
}
|
|
|
|
// Apply alpha to a color
|
|
Color applyAlpha(Color color, double opacity) {
|
|
return color.withValues(alpha: (color.a * opacity).clamp(0.0, 1.0));
|
|
}
|
|
|
|
// Format date for display (e.g., "5 Mei 2024")
|
|
String formatDate(DateTime date) {
|
|
return CyclePhaseUtils.formatIndonesianDate(date);
|
|
}
|
|
|
|
// Get phase data (duration, progress) for a given days count
|
|
Map<String, dynamic> getPhaseData(int daysSincePlanting) {
|
|
final progressData = PhaseDisplayUtils.progressData(daysSincePlanting);
|
|
return {
|
|
'day': progressData.dayInPhase,
|
|
'duration': progressData.phaseDuration,
|
|
'progress': progressData.progress,
|
|
};
|
|
}
|
|
|
|
Future<ServiceResult<void>> savePlantingDate({
|
|
required String userId,
|
|
required DateTime plantingDate,
|
|
}) async {
|
|
if (userId.isEmpty) {
|
|
return ServiceResult.failure(
|
|
message: 'User tidak terautentikasi',
|
|
errorCode: 'unauthenticated',
|
|
);
|
|
}
|
|
|
|
try {
|
|
final days = DateTime.now().difference(plantingDate).inDays;
|
|
final phase = calculateCurrentPhase(days);
|
|
|
|
await _cyclesService.addCycle(userId: userId, startDate: plantingDate);
|
|
await _createPhaseSnapshot(
|
|
userId: userId,
|
|
phase: phase,
|
|
daysSincePlanting: days,
|
|
);
|
|
|
|
return ServiceResult.success(message: 'Tanggal tanam disimpan');
|
|
} catch (e) {
|
|
return ServiceResult.failure(
|
|
message: 'Gagal menyimpan tanggal tanam: $e',
|
|
errorCode: 'save_cycle_failed',
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<ServiceResult<void>> resetCycle(String userId) async {
|
|
if (userId.isEmpty) {
|
|
return ServiceResult.failure(
|
|
message: 'User tidak terautentikasi',
|
|
errorCode: 'unauthenticated',
|
|
);
|
|
}
|
|
|
|
try {
|
|
await _cyclesService.deleteCycle(userId: userId);
|
|
return ServiceResult.success(message: 'Siklus direset');
|
|
} catch (e) {
|
|
return ServiceResult.failure(
|
|
message: 'Gagal reset siklus: $e',
|
|
errorCode: 'reset_failed',
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<ServiceResult<void>> markHarvest(String userId) async {
|
|
if (userId.isEmpty) {
|
|
return ServiceResult.failure(
|
|
message: 'User tidak terautentikasi',
|
|
errorCode: 'unauthenticated',
|
|
);
|
|
}
|
|
|
|
try {
|
|
// Hitung total hari siklus sebelum menghapus
|
|
final daysSincePlanting = await _cyclesService
|
|
.calculateCycleDaysBeforeDelete(userId: userId);
|
|
|
|
// Catat snapshot panen untuk historikal
|
|
await _createPhaseSnapshot(
|
|
userId: userId,
|
|
phase: 'Panen',
|
|
daysSincePlanting: daysSincePlanting,
|
|
);
|
|
|
|
// Hapus siklus aktif setelah panen dicatat
|
|
await _cyclesService.deleteCycle(userId: userId);
|
|
|
|
return ServiceResult.success(message: 'Panen dicatat, siklus selesai');
|
|
} catch (e) {
|
|
return ServiceResult.failure(
|
|
message: 'Gagal mencatat panen: $e',
|
|
errorCode: 'harvest_failed',
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> updatePhaseIfChanged({
|
|
required String userId,
|
|
required String currentPhaseInDb,
|
|
required String calculatedPhase,
|
|
required int days,
|
|
required DateTime startDate,
|
|
}) async {
|
|
if (currentPhaseInDb == calculatedPhase) return;
|
|
|
|
await _cyclesService.updateCycleProgress(
|
|
userId: userId,
|
|
startDate: startDate,
|
|
);
|
|
await _createPhaseSnapshot(
|
|
userId: userId,
|
|
phase: calculatedPhase,
|
|
daysSincePlanting: days,
|
|
);
|
|
}
|
|
|
|
Future<void> _createPhaseSnapshot({
|
|
required String userId,
|
|
required String phase,
|
|
int? daysSincePlanting,
|
|
}) async {
|
|
await _firestore.collection('hidroponik_data').add({
|
|
'user_id': userId,
|
|
'growth_phase': phase,
|
|
if (daysSincePlanting != null) 'days_since_planting': daysSincePlanting,
|
|
'pH_value': 0.0,
|
|
'nutrient_level': 0.0,
|
|
'pump_ph_up_status': false,
|
|
'pump_ph_down_status': false,
|
|
'pump_nutrient_status': false,
|
|
'pump_water_status': false,
|
|
'timestamp': FieldValue.serverTimestamp(),
|
|
});
|
|
}
|
|
}
|