321 lines
11 KiB
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,
|
|
};
|
|
}
|
|
} |