// lib/services/air_sampling_service.dart import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:image/image.dart' as img; import 'package:intl/intl.dart'; // Import your actual data models import '../models/air_installation_data.dart'; import '../models/air_collection_data.dart'; // Import a local storage service (you would create this) // import 'local_storage_service.dart'; // A placeholder for your actual API service class AirApiService { Future> submitInstallation({ required Map installationJson, required List imageFiles, }) async { // In a real app, you would build an http.MultipartRequest here // to send the JSON data and image files to your server. print("Submitting Installation to API..."); print("Data: $installationJson"); print("Image count: ${imageFiles.length}"); // Simulate a network call await Future.delayed(const Duration(seconds: 1)); // Simulate a successful response return { 'status': 'S1', // 'S1' for Server Success (Installation Pending Collection) 'message': 'Installation data successfully submitted to the server.', 'refID': installationJson['refID'], }; } Future> submitCollection({ required Map collectionJson, required List imageFiles, }) async { // In a real app, this would update the existing record linked by 'installationRefID' print("Submitting Collection to API..."); print("Data: $collectionJson"); print("Image count: ${imageFiles.length}"); // Simulate a network call await Future.delayed(const Duration(seconds: 1)); // Simulate a successful response return { 'status': 'S3', // 'S3' for Server Success (Completed) 'message': 'Collection data successfully linked and submitted.', }; } } /// A dedicated service to handle all business logic for the Air Manual Sampling feature. class AirSamplingService { final AirApiService _apiService = AirApiService(); // final LocalStorageService _localStorageService = LocalStorageService(); /// Picks an image from the specified source, adds a timestamp watermark, /// and saves it to a temporary directory with a standardized name. Future pickAndProcessImage( ImageSource source, { required String stationCode, required String imageInfo, // e.g., "INSTALLATION_LEFT", "COLLECTION_CHART" }) async { final picker = ImagePicker(); final XFile? photo = await picker.pickImage( source: source, imageQuality: 85, maxWidth: 1024); if (photo == null) return null; final bytes = await photo.readAsBytes(); img.Image? originalImage = img.decodeImage(bytes); if (originalImage == null) return null; // Prepare watermark text final String watermarkTimestamp = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); final font = img.arial24; // Add a white background for better text visibility final textWidth = watermarkTimestamp.length * 12; // Estimate width img.fillRect(originalImage, x1: 5, y1: 5, x2: textWidth + 15, y2: 35, color: img.ColorRgb8(255, 255, 255)); img.drawString(originalImage, watermarkTimestamp, font: font, x: 10, y: 10, color: img.ColorRgb8(0, 0, 0)); // Create a standardized file name final tempDir = await getTemporaryDirectory(); final fileTimestamp = watermarkTimestamp.replaceAll(':', '-').replaceAll(' ', '_'); final newFileName = "${stationCode}_${fileTimestamp}_${imageInfo.replaceAll(' ', '')}.jpg"; final filePath = path.join(tempDir.path, newFileName); // Save the processed image and return the file return File(filePath)..writeAsBytesSync(img.encodeJpg(originalImage)); } /// Submits only the installation data. Future> submitInstallation(AirInstallationData data) async { try { // Prepare image files for upload final List images = []; if (data.image1 != null) images.add(data.image1!); if (data.image2 != null) images.add(data.image2!); if (data.image3 != null) images.add(data.image3!); if (data.image4 != null) images.add(data.image4!); // In a real app, you would check connectivity here before attempting the API call final result = await _apiService.submitInstallation( installationJson: data.toJson(), imageFiles: images, ); return result; } catch (e) { print("API submission failed: $e. Saving installation locally."); // --- Fallback to Local Storage --- // TODO: Implement local DB save for installation data data.status = 'L1'; // Mark as saved locally, pending collection // await _localStorageService.saveAirInstallationData(data); return { 'status': 'L1', 'message': 'Installation data saved locally.', }; } } /// Submits only the collection data, linked to a previous installation. Future> submitCollection(AirCollectionData data) async { try { // Prepare image files for upload final List images = []; if (data.imageSiteLeft != null) images.add(data.imageSiteLeft!); if (data.imageSiteRight != null) images.add(data.imageSiteRight!); // ... add all other collection images // In a real app, you would check connectivity here final result = await _apiService.submitCollection( collectionJson: data.toJson(), imageFiles: images, ); return result; } catch (e) { print("API submission failed: $e. Saving collection locally."); // --- Fallback to Local Storage --- // TODO: Implement local DB save for collection data data.status = 'L3'; // Mark as completed locally // await _localStorageService.saveAirCollectionData(data); return { 'status': 'L3', 'message': 'Collection data saved locally.', }; } } /// Fetches installations that are pending collection. Future> getPendingInstallations() async { // In a real app, this would query your local database or a server endpoint // for records with status 'L1' (local, pending) or 'S1' (server, pending). print("Fetching pending installations..."); await Future.delayed(const Duration(milliseconds: 500)); // Simulate network/DB delay // Return placeholder data for demonstration return [ AirInstallationData( refID: 'ABC1234567', stationID: 'SGR01', locationName: 'Shah Alam', samplingDate: '2025-08-10', temp: '28.5', status: 'L1', // Example of a locally saved installation ), AirInstallationData( refID: 'DEF8901234', stationID: 'JHR02', locationName: 'Muar', samplingDate: '2025-08-09', temp: '29.1', status: 'S1', // Example of a server-saved installation ), AirInstallationData( refID: 'GHI5678901', stationID: 'PRK01', locationName: 'Ipoh', samplingDate: '2025-08-11', temp: '27.9', status: 'S1', ), ]; } void dispose() { // Clean up any resources if necessary } }