// lib/screens/marine/manual/tarball_sampling.dart import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:dropdown_search/dropdown_search.dart'; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:geolocator/geolocator.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:image/image.dart' as img; import 'package:environment_monitoring_app/auth_provider.dart'; // START CHANGE: Import the new dedicated service import 'package:environment_monitoring_app/services/marine_tarball_sampling_service.dart'; // END CHANGE import 'package:environment_monitoring_app/models/tarball_data.dart'; class MarineTarballSampling extends StatefulWidget { const MarineTarballSampling({super.key}); @override State createState() => _MarineTarballSamplingState(); } class _MarineTarballSamplingState extends State { final _formKey1 = GlobalKey(); final _formKey2 = GlobalKey(); int _currentStep = 1; // MODIFIED: The service instance is no longer created here. // It will be fetched from the Provider right before it is used. bool _isLoading = false; final TarballSamplingData _data = TarballSamplingData(); List _statesList = []; List _categoriesForState = []; List> _stationsForCategory = []; @override void initState() { super.initState(); _initializeForm(); } void _initializeForm() { final auth = Provider.of(context, listen: false); _data.firstSampler = auth.profileData?['first_name'] ?? 'Current User'; final now = DateTime.now(); _data.samplingDate = DateFormat('yyyy-MM-dd').format(now); _data.samplingTime = DateFormat('HH:mm:ss').format(now); final allStations = auth.tarballStations ?? []; if (allStations.isNotEmpty) { final states = allStations.map((s) => s['state_name'] as String?).whereType().toSet().toList(); states.sort(); _statesList = states; } } Future _pickAndProcessImage(ImageSource source) 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; final String timestamp = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); // Shadow for visibility img.drawString(originalImage, timestamp, font: img.arial24, x: 11, y: 11, color: img.ColorRgb8(0, 0, 0)); // Foreground text img.drawString(originalImage, timestamp, font: img.arial24, x: 10, y: 10, color: img.ColorRgb8(255, 255, 255)); final tempDir = await getTemporaryDirectory(); final filePath = path.join(tempDir.path, '${DateTime.now().millisecondsSinceEpoch}.jpg'); return File(filePath)..writeAsBytesSync(img.encodeJpg(originalImage)); } void _setImage(Function(File?) setImageCallback, ImageSource source) async { final file = await _pickAndProcessImage(source); if (file != null) setState(() => setImageCallback(file)); } Future _getCurrentLocation() async { /* ... Location logic ... */ } void _calculateDistance() { /* ... Distance logic ... */ } // MODIFIED: This method now uses the new dedicated service for submission. Future _submitForm() async { setState(() => _isLoading = true); // Get the appSettings list from AuthProvider. final authProvider = Provider.of(context, listen: false); final appSettings = authProvider.appSettings; // ADDED: Fetch the global service instance from Provider. final tarballService = Provider.of(context, listen: false); // START FIX: Pass the required `context` argument to the function call. final result = await tarballService.submitTarballSample( data: _data, appSettings: appSettings, context: context, ); // END FIX if (!mounted) return; setState(() => _isLoading = false); if (result['success'] == true) { _showSnackBar("Data submitted successfully!"); Navigator.of(context).pop(); } else { _showSnackBar("Submission failed: ${result['message']}"); } } void _showSnackBar(String message) { if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message))); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Marine Tarball Sampling")), body: Stepper( currentStep: _currentStep - 1, onStepContinue: () { if (_currentStep == 1 && _formKey1.currentState!.validate()) { _formKey1.currentState!.save(); setState(() => _currentStep++); } else if (_currentStep == 2 && _formKey2.currentState!.validate()) { _formKey2.currentState!.save(); setState(() => _currentStep++); } }, onStepCancel: () { if (_currentStep > 1) setState(() => _currentStep--); }, controlsBuilder: (context, details) { return Padding( padding: const EdgeInsets.only(top: 16.0), child: _isLoading ? const Center(child: CircularProgressIndicator()) : Row( children: [ if (_currentStep < 3) ElevatedButton(onPressed: details.onStepContinue, child: const Text('Next')), if (_currentStep == 3) ElevatedButton(onPressed: _submitForm, child: const Text('Submit')), if (_currentStep > 1) TextButton(onPressed: details.onStepCancel, child: const Text('Back')), ], ), ); }, steps: [ Step(title: const Text('Sampling Info'), content: _buildForm1(), isActive: _currentStep >= 1), Step(title: const Text('On-Site Info'), content: _buildForm2(), isActive: _currentStep >= 2), Step(title: const Text('Summary'), content: _buildForm3(), isActive: _currentStep >= 3), ], ), ); } Widget _buildForm1() { /* ... UI for Step 1 ... */ return Container(); } Widget _buildForm2() { /* ... UI for Step 2 ... */ return Container(); } Widget _buildForm3() { /* ... UI for Step 3 ... */ return Container(); } }