193 lines
5.4 KiB
Dart
193 lines
5.4 KiB
Dart
import 'package:get/get.dart';
|
|
import 'dart:async';
|
|
import '../../../models/patient_model.dart';
|
|
import '../../../models/device_model.dart';
|
|
import '../../../models/realtime_monitoring_model.dart';
|
|
import '../../../models/history_model.dart';
|
|
import '../../../models/chart_data_point.dart';
|
|
import '../../../services/firestore_service.dart';
|
|
import '../../../services/realtime_database_service.dart';
|
|
import '../../../widgets/app_snackbar.dart';
|
|
|
|
class DeviceDetailController extends GetxController {
|
|
final FirestoreService _firestoreService = FirestoreService();
|
|
final RealtimeDatabaseService _realtimeService = RealtimeDatabaseService();
|
|
|
|
String? deviceId;
|
|
String? roomId;
|
|
|
|
final deviceName = ''.obs;
|
|
final patientName = ''.obs;
|
|
final roomName = ''.obs;
|
|
final dropsPerMinute = '0'.obs;
|
|
final lastUpdate = DateTime.now().obs;
|
|
final isServoActive = false.obs;
|
|
final deviceStatus = 'disconnected'.obs;
|
|
final isLoading = true.obs;
|
|
|
|
final RxList<ChartDataPoint> chartData = <ChartDataPoint>[].obs;
|
|
|
|
StreamSubscription? _realtimeSubscription;
|
|
StreamSubscription? _historySubscription;
|
|
|
|
PatientModel? patient;
|
|
DeviceModel? device;
|
|
RealtimeMonitoringModel? realtimeData;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_getArguments();
|
|
if (deviceId != null && roomId != null) {
|
|
_initializeDeviceDetail();
|
|
} else {
|
|
Get.back();
|
|
AppSnackbar.error('Device ID tidak ditemukan');
|
|
}
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_realtimeSubscription?.cancel();
|
|
_historySubscription?.cancel();
|
|
super.onClose();
|
|
}
|
|
|
|
void _getArguments() {
|
|
final args = Get.arguments as Map<String, dynamic>?;
|
|
if (args != null) {
|
|
deviceId = args['deviceId'];
|
|
roomId = args['roomId'];
|
|
}
|
|
}
|
|
|
|
Future<void> _initializeDeviceDetail() async {
|
|
try {
|
|
isLoading.value = true;
|
|
|
|
await _loadPatientData();
|
|
await _loadDeviceData();
|
|
_listenToRealtimeData();
|
|
_listenToHistoryData();
|
|
|
|
isLoading.value = false;
|
|
} catch (e) {
|
|
isLoading.value = false;
|
|
AppSnackbar.error('Gagal memuat data');
|
|
}
|
|
}
|
|
|
|
Future<void> _loadPatientData() async {
|
|
patient = await _firestoreService.getPatientByDeviceId(deviceId!);
|
|
if (patient != null) {
|
|
patientName.value = patient!.namePatient;
|
|
}
|
|
}
|
|
|
|
Future<void> _loadDeviceData() async {
|
|
device = await _firestoreService.getDeviceById(deviceId!);
|
|
if (device != null) {
|
|
deviceName.value = device!.devicesName;
|
|
roomName.value = await _getRoomName(device!.roomId);
|
|
}
|
|
}
|
|
|
|
Future<String> _getRoomName(String roomId) async {
|
|
try {
|
|
final rooms = await _firestoreService.getRoomsStream().first;
|
|
final room = rooms.firstWhereOrNull(
|
|
(r) =>
|
|
r.id == roomId || r.roomName.toLowerCase() == roomId.toLowerCase(),
|
|
);
|
|
return room?.roomName ?? roomId;
|
|
} catch (e) {
|
|
return roomId;
|
|
}
|
|
}
|
|
|
|
void _listenToRealtimeData() {
|
|
final dbRoomId = roomId!.toLowerCase().replaceAll(' ', '_');
|
|
|
|
_realtimeSubscription = _realtimeService
|
|
.getDeviceStream(dbRoomId, deviceId!)
|
|
.listen((data) {
|
|
if (data != null) {
|
|
realtimeData = data;
|
|
dropsPerMinute.value = data.dropRate.toStringAsFixed(0);
|
|
lastUpdate.value = data.lastUpdate;
|
|
isServoActive.value = data.servoOpen;
|
|
deviceStatus.value = data.deviceStatus;
|
|
}
|
|
}, onError: (error) => AppSnackbar.error('Koneksi realtime terputus'));
|
|
}
|
|
|
|
void _listenToHistoryData() {
|
|
_historySubscription = _firestoreService
|
|
.getDeviceHistoriesStream(deviceId!)
|
|
.listen(
|
|
(histories) {
|
|
if (histories.isNotEmpty) {
|
|
_processHistoryData(histories);
|
|
} else {
|
|
chartData.value = [];
|
|
}
|
|
},
|
|
onError: (error) {
|
|
chartData.value = [];
|
|
AppSnackbar.error('Gagal memuat data history');
|
|
},
|
|
);
|
|
}
|
|
|
|
void _processHistoryData(List<HistoryModel> histories) {
|
|
histories.sort((a, b) => b.timestamp.compareTo(a.timestamp));
|
|
|
|
final latestHistories = histories.take(10).toList();
|
|
|
|
latestHistories.sort((a, b) => a.timestamp.compareTo(b.timestamp));
|
|
|
|
final List<ChartDataPoint> points = latestHistories.map((history) {
|
|
return ChartDataPoint(
|
|
hour: history.timestamp.hour,
|
|
dropsPerMinute: history.dropPerMinute,
|
|
);
|
|
}).toList();
|
|
|
|
chartData.value = points;
|
|
}
|
|
|
|
Future<void> toggleServo(bool value) async {
|
|
try {
|
|
final dbRoomId = roomId!.toLowerCase().replaceAll(' ', '_');
|
|
await _realtimeService.controlServo(dbRoomId, deviceId!, value);
|
|
isServoActive.value = value;
|
|
AppSnackbar.success(value ? 'Infus dibuka' : 'Infus ditutup');
|
|
} catch (e) {
|
|
AppSnackbar.error('Gagal mengontrol servo');
|
|
}
|
|
}
|
|
|
|
String getLastUpdateText() {
|
|
final difference = DateTime.now().difference(lastUpdate.value);
|
|
if (difference.inMinutes < 1) return 'just now';
|
|
if (difference.inMinutes < 60) return '${difference.inMinutes}m ago';
|
|
if (difference.inHours < 24) return '${difference.inHours}h ago';
|
|
return '${difference.inDays}d ago';
|
|
}
|
|
|
|
void navigateToHistory() {
|
|
Get.toNamed(
|
|
'/history',
|
|
arguments: {
|
|
'deviceId': deviceId,
|
|
'deviceName': deviceName.value,
|
|
'patientName': patientName.value,
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<void> refreshData() async {
|
|
await _loadDeviceData();
|
|
}
|
|
}
|