environment_monitoring_app/lib/models/in_situ_sampling_data.dart

321 lines
11 KiB
Dart

import 'dart:io';
import 'dart:convert'; // Added for jsonEncode
/// A data model class to hold all information for the multi-step
/// In-Situ Sampling form.
class InSituSamplingData {
// --- Step 1: Sampling & Station Info ---
String? firstSamplerName;
int? firstSamplerUserId;
Map<String, dynamic>? secondSampler;
String? samplingDate;
String? samplingTime;
String? samplingType;
String? sampleIdCode;
String? selectedStateName;
String? selectedCategoryName;
Map<String, dynamic>? selectedStation;
String? stationLatitude;
String? stationLongitude;
String? currentLatitude;
String? currentLongitude;
double? distanceDifferenceInKm;
String? distanceDifferenceRemarks;
// --- Step 2: Site Info & Photos ---
String? weather;
String? tideLevel;
String? seaCondition;
String? eventRemarks;
String? labRemarks;
File? leftLandViewImage;
File? rightLandViewImage;
File? waterFillingImage;
File? seawaterColorImage;
File? phPaperImage;
File? optionalImage1;
String? optionalRemark1;
File? optionalImage2;
String? optionalRemark2;
File? optionalImage3;
String? optionalRemark3;
File? optionalImage4;
String? optionalRemark4;
// --- Step 3: Data Capture ---
String? sondeId;
String? dataCaptureDate;
String? dataCaptureTime;
double? oxygenConcentration;
double? oxygenSaturation;
double? ph;
double? salinity;
double? electricalConductivity;
double? temperature;
double? tds;
double? turbidity;
double? tss;
double? batteryVoltage;
// --- Post-Submission Status ---
String? submissionStatus;
String? submissionMessage;
String? reportId;
// REPAIRED: Added a constructor to accept initial values.
InSituSamplingData({
this.samplingDate,
this.samplingTime,
});
// --- ADDED: Factory constructor to create a new instance from a map ---
factory InSituSamplingData.fromJson(Map<String, dynamic> json) {
double? doubleFromJson(dynamic value) {
if (value is num) return value.toDouble();
if (value is String) return double.tryParse(value);
return null;
}
int? intFromJson(dynamic value) {
if (value is int) return value;
if (value is String) return int.tryParse(value);
return null;
}
return InSituSamplingData()
..firstSamplerName = json['first_sampler_name']
..firstSamplerUserId = intFromJson(json['first_sampler_user_id'])
..secondSampler = json['secondSampler']
..samplingDate = json['man_date']
..samplingTime = json['man_time']
..samplingType = json['man_type']
..sampleIdCode = json['man_sample_id_code']
..selectedStateName = json['selectedStateName']
..selectedCategoryName = json['selectedCategoryName']
..selectedStation = json['selectedStation']
..stationLatitude = json['stationLatitude']
..stationLongitude = json['stationLongitude']
..currentLatitude = json['man_current_latitude']?.toString()
..currentLongitude = json['man_current_longitude']?.toString()
..distanceDifferenceInKm = doubleFromJson(json['man_distance_difference'])
..distanceDifferenceRemarks = json['man_distance_difference_remarks']
..weather = json['man_weather']
..tideLevel = json['man_tide_level']
..seaCondition = json['man_sea_condition']
..eventRemarks = json['man_event_remark']
..labRemarks = json['man_lab_remark']
..sondeId = json['man_sondeID']
..dataCaptureDate = json['data_capture_date']
..dataCaptureTime = json['data_capture_time']
..oxygenConcentration = doubleFromJson(json['man_oxygen_conc'])
..oxygenSaturation = doubleFromJson(json['man_oxygen_sat'])
..ph = doubleFromJson(json['man_ph'])
..salinity = doubleFromJson(json['man_salinity'])
..electricalConductivity = doubleFromJson(json['man_conductivity'])
..temperature = doubleFromJson(json['man_temperature'])
..tds = doubleFromJson(json['man_tds'])
..turbidity = doubleFromJson(json['man_turbidity'])
..tss = doubleFromJson(json['man_tss'])
..batteryVoltage = doubleFromJson(json['man_battery_volt'])
..optionalRemark1 = json['man_optional_photo_01_remarks']
..optionalRemark2 = json['man_optional_photo_02_remarks']
..optionalRemark3 = json['man_optional_photo_03_remarks']
..optionalRemark4 = json['man_optional_photo_04_remarks'];
}
/// Generates a formatted Telegram alert message for successful submissions.
String generateTelegramAlertMessage({required bool isDataOnly}) {
final submissionType = isDataOnly ? "(Data Only)" : "(Data & Images)";
final stationName = selectedStation?['man_station_name'] ?? 'N/A';
final stationCode = selectedStation?['man_station_code'] ?? 'N/A';
final buffer = StringBuffer()
..writeln('✅ *In-Situ Sample $submissionType Submitted:*')
..writeln()
..writeln('*Station Name & Code:* $stationName ($stationCode)')
..writeln('*Date of Submission:* $samplingDate')
..writeln('*Submitted by User:* $firstSamplerName')
..writeln('*Sonde ID:* ${sondeId ?? "N/A"}')
..writeln('*Status of Submission:* Successful');
// Add distance alert if relevant
if (distanceDifferenceInKm != null && distanceDifferenceInKm! > 0) {
buffer
..writeln()
..writeln('🔔 *Alert:*')
..writeln('*Distance from station:* ${(distanceDifferenceInKm! * 1000).toStringAsFixed(0)} meters');
if (distanceDifferenceRemarks != null && distanceDifferenceRemarks!.isNotEmpty) {
buffer.writeln('*Remarks for distance:* $distanceDifferenceRemarks');
}
}
return buffer.toString();
}
/// Converts the data model into a Map<String, String> for the API form data.
Map<String, String> toApiFormData() {
final Map<String, String> map = {};
void add(String key, dynamic value) {
if (value != null) {
map[key] = value.toString();
}
}
// Step 1 Data
add('first_sampler_user_id', firstSamplerUserId);
add('man_second_sampler_id', secondSampler?['user_id']);
add('man_date', samplingDate);
add('man_time', samplingTime);
add('man_type', samplingType);
add('man_sample_id_code', sampleIdCode);
add('station_id', selectedStation?['station_id']);
add('man_current_latitude', currentLatitude);
add('man_current_longitude', currentLongitude);
add('man_distance_difference', distanceDifferenceInKm);
add('man_distance_difference_remarks', distanceDifferenceRemarks);
// Step 2 Data
add('man_weather', weather);
add('man_tide_level', tideLevel);
add('man_sea_condition', seaCondition);
add('man_event_remark', eventRemarks);
add('man_lab_remark', labRemarks);
add('man_optional_photo_01_remarks', optionalRemark1);
add('man_optional_photo_02_remarks', optionalRemark2);
add('man_optional_photo_03_remarks', optionalRemark3);
add('man_optional_photo_04_remarks', optionalRemark4);
// Step 3 Data
add('man_sondeID', sondeId);
add('data_capture_date', dataCaptureDate);
add('data_capture_time', dataCaptureTime);
add('man_oxygen_conc', oxygenConcentration);
add('man_oxygen_sat', oxygenSaturation);
add('man_ph', ph);
add('man_salinity', salinity);
add('man_conductivity', electricalConductivity);
add('man_temperature', temperature);
add('man_tds', tds);
add('man_turbidity', turbidity);
add('man_tss', tss);
add('man_battery_volt', batteryVoltage);
add('first_sampler_name', firstSamplerName);
add('man_station_code', selectedStation?['man_station_code']);
add('man_station_name', selectedStation?['man_station_name']);
return map;
}
/// Converts the image properties into a Map<String, File?> for the multipart API request.
Map<String, File?> toApiImageFiles() {
return {
'man_left_side_land_view': leftLandViewImage,
'man_right_side_land_view': rightLandViewImage,
'man_filling_water_into_sample_bottle': waterFillingImage,
'man_seawater_in_clear_glass_bottle': seawaterColorImage,
'man_examine_preservative_ph_paper': phPaperImage,
'man_optional_photo_01': optionalImage1,
'man_optional_photo_02': optionalImage2,
'man_optional_photo_03': optionalImage3,
'man_optional_photo_04': optionalImage4,
};
}
// --- ADDED: Methods to format data for FTP submission as separate JSON files ---
/// Creates a single JSON object with all submission data, mimicking 'db.json'
Map<String, dynamic> toDbJson() {
// This is a direct conversion of the model's properties to a map,
// with keys matching the expected JSON file format.
return {
'first_sampler_name': firstSamplerName,
'first_sampler_user_id': firstSamplerUserId,
'second_sampler': secondSampler,
'sampling_date': samplingDate,
'sampling_time': samplingTime,
'sampling_type': samplingType,
'sample_id_code': sampleIdCode,
'selected_state_name': selectedStateName,
'selected_category_name': selectedCategoryName,
'selected_station': selectedStation,
'station_latitude': stationLatitude,
'station_longitude': stationLongitude,
'current_latitude': currentLatitude,
'current_longitude': currentLongitude,
'distance_difference_in_km': distanceDifferenceInKm,
'distance_difference_remarks': distanceDifferenceRemarks,
'weather': weather,
'tide_level': tideLevel,
'sea_condition': seaCondition,
'event_remarks': eventRemarks,
'lab_remarks': labRemarks,
'sonde_id': sondeId,
'data_capture_date': dataCaptureDate,
'data_capture_time': dataCaptureTime,
'oxygen_concentration': oxygenConcentration,
'oxygen_saturation': oxygenSaturation,
'ph': ph,
'salinity': salinity,
'electrical_conductivity': electricalConductivity,
'temperature': temperature,
'tds': tds,
'turbidity': turbidity,
'tss': tss,
'battery_voltage': batteryVoltage,
'submission_status': submissionStatus,
'submission_message': submissionMessage,
'report_id': reportId,
};
}
/// Creates a JSON object for basic form info, mimicking 'basic_form.json'.
Map<String, dynamic> toBasicFormJson() {
return {
'tech_name': firstSamplerName,
'sampler_2ndname': secondSampler?['user_name'],
'sample_date': samplingDate,
'sample_time': samplingTime,
'sampling_type': samplingType,
'sample_state': selectedStateName,
'station_id': selectedStation?['man_station_code'],
'station_latitude': stationLatitude,
'station_longitude': stationLongitude,
'latitude': currentLatitude,
'longitude': currentLongitude,
'sample_id': sampleIdCode,
};
}
/// Creates a JSON object for sensor readings, mimicking 'reading.json'.
Map<String, dynamic> toReadingJson() {
return {
'do_mgl': oxygenConcentration,
'do_sat': oxygenSaturation,
'ph': ph,
'salinity': salinity,
'temperature': temperature,
'turbidity': turbidity,
'tds': tds,
'electric_conductivity': electricalConductivity,
'flowrate': null, // This is not collected in marine in-situ
'date_sampling_reading': dataCaptureDate,
'time_sampling_reading': dataCaptureTime,
};
}
/// Creates a JSON object for manual info, mimicking 'manual_info.json'.
Map<String, dynamic> toManualInfoJson() {
return {
'weather': weather,
'remarks_event': eventRemarks,
'remarks_lab': labRemarks,
};
}
}