repair marine manual and tarball screen
This commit is contained in:
parent
dff653883a
commit
821bb89ac4
@ -29,7 +29,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
title: const Text("MMS Version 3.4.01"),
|
title: const Text("MMS Version 3.5.01"),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.person),
|
icon: const Icon(Icons.person),
|
||||||
|
|||||||
@ -25,9 +25,14 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
bool _isPickingImage = false;
|
bool _isPickingImage = false;
|
||||||
|
|
||||||
// This will hold the user's selection in the UI
|
|
||||||
Map<String, dynamic>? _selectedClassification;
|
Map<String, dynamic>? _selectedClassification;
|
||||||
|
|
||||||
|
// --- START: MODIFICATION 1 ---
|
||||||
|
// Added a state variable to easily check if the classification requires photos.
|
||||||
|
// We will assume 'None' classification has an ID of 1. Adjust if necessary.
|
||||||
|
bool _isNoneClassificationSelected = false;
|
||||||
|
// --- END: MODIFICATION 1 ---
|
||||||
|
|
||||||
late final TextEditingController _remark1Controller;
|
late final TextEditingController _remark1Controller;
|
||||||
late final TextEditingController _remark2Controller;
|
late final TextEditingController _remark2Controller;
|
||||||
late final TextEditingController _remark3Controller;
|
late final TextEditingController _remark3Controller;
|
||||||
@ -42,11 +47,9 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
_remark3Controller = TextEditingController(text: widget.data.optionalRemark3);
|
_remark3Controller = TextEditingController(text: widget.data.optionalRemark3);
|
||||||
_remark4Controller = TextEditingController(text: widget.data.optionalRemark4);
|
_remark4Controller = TextEditingController(text: widget.data.optionalRemark4);
|
||||||
|
|
||||||
// This block ensures the dropdown shows the correct value if the user comes back to this screen
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
final auth = Provider.of<AuthProvider>(context, listen: false);
|
final auth = Provider.of<AuthProvider>(context, listen: false);
|
||||||
|
|
||||||
// Restore the selected value from the data model using the cached list in the provider
|
|
||||||
if (widget.data.classificationId != null && auth.tarballClassifications != null) {
|
if (widget.data.classificationId != null && auth.tarballClassifications != null) {
|
||||||
try {
|
try {
|
||||||
final foundClassification = auth.tarballClassifications!.firstWhere(
|
final foundClassification = auth.tarballClassifications!.firstWhere(
|
||||||
@ -54,19 +57,16 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
);
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedClassification = foundClassification;
|
_selectedClassification = foundClassification;
|
||||||
// Also restore the full object to the data model
|
|
||||||
widget.data.selectedClassification = foundClassification;
|
widget.data.selectedClassification = foundClassification;
|
||||||
|
// --- START: MODIFICATION 2 ---
|
||||||
|
// Update our state variable when restoring the form state.
|
||||||
|
_isNoneClassificationSelected = widget.data.classificationId == 1;
|
||||||
|
// --- END: MODIFICATION 2 ---
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("Could not find pre-selected classification in the cached list.");
|
debugPrint("Could not find pre-selected classification in the cached list.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// **OFFLINE-FIRST SYNC**:
|
|
||||||
// Attempt to sync all master data with the server in the background.
|
|
||||||
// The UI will build instantly using existing local data from AuthProvider.
|
|
||||||
// If the sync is successful, the Consumer widget will automatically rebuild the dropdown with fresh data.
|
|
||||||
// If offline, this will fail gracefully and the user will see the data from the last successful sync.
|
|
||||||
auth.syncAllData();
|
auth.syncAllData();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -86,10 +86,7 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text("Incorrect Image Orientation"),
|
title: const Text("Incorrect Image Orientation"),
|
||||||
// --- START: MODIFICATION 1 ---
|
|
||||||
// Updated the dialog text to be more general as it now applies to all photos.
|
|
||||||
content: const Text("All photos must be taken in a horizontal (landscape) orientation."),
|
content: const Text("All photos must be taken in a horizontal (landscape) orientation."),
|
||||||
// --- END: MODIFICATION 1 ---
|
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
child: const Text("OK"),
|
child: const Text("OK"),
|
||||||
@ -101,11 +98,7 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- START: MODIFICATION 2 ---
|
|
||||||
// The `isRequired` parameter has been removed. The orientation check will now
|
|
||||||
// apply to every image processed by this function.
|
|
||||||
Future<File?> _pickAndProcessImage(ImageSource source, String imageInfo) async {
|
Future<File?> _pickAndProcessImage(ImageSource source, String imageInfo) async {
|
||||||
// --- END: MODIFICATION 2 ---
|
|
||||||
if (_isPickingImage) return null;
|
if (_isPickingImage) return null;
|
||||||
setState(() => _isPickingImage = true);
|
setState(() => _isPickingImage = true);
|
||||||
|
|
||||||
@ -124,15 +117,11 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- START: MODIFICATION 3 ---
|
|
||||||
// The `isRequired` check has been removed. Now, ALL photos (required and optional)
|
|
||||||
// must be in landscape orientation (width > height).
|
|
||||||
if (originalImage.height > originalImage.width) {
|
if (originalImage.height > originalImage.width) {
|
||||||
_showOrientationDialog();
|
_showOrientationDialog();
|
||||||
setState(() => _isPickingImage = false);
|
setState(() => _isPickingImage = false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// --- END: MODIFICATION 3 ---
|
|
||||||
|
|
||||||
final String watermarkTimestamp = "${widget.data.samplingDate} ${widget.data.samplingTime}";
|
final String watermarkTimestamp = "${widget.data.samplingDate} ${widget.data.samplingTime}";
|
||||||
final font = img.arial24;
|
final font = img.arial24;
|
||||||
@ -172,12 +161,8 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
return processedFile;
|
return processedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- START: MODIFICATION 4 ---
|
|
||||||
// The `isRequired` parameter has been removed from the function signature
|
|
||||||
// to align with the changes in `_pickAndProcessImage`.
|
|
||||||
void _setImage(Function(File?) setImageCallback, ImageSource source, String imageInfo) async {
|
void _setImage(Function(File?) setImageCallback, ImageSource source, String imageInfo) async {
|
||||||
final file = await _pickAndProcessImage(source, imageInfo);
|
final file = await _pickAndProcessImage(source, imageInfo);
|
||||||
// --- END: MODIFICATION 4 ---
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
setImageCallback(file);
|
setImageCallback(file);
|
||||||
@ -210,9 +195,23 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- START: MODIFICATION 5 ---
|
// --- START: MODIFICATION 3 ---
|
||||||
// Added validation to ensure that if an optional image is provided, its
|
// This is the new validation logic.
|
||||||
// corresponding remark field is not empty.
|
// If the classification is NOT "None", we check if Optional Photo 1 and its remark have been provided.
|
||||||
|
if (!_isNoneClassificationSelected) {
|
||||||
|
if (widget.data.optionalImage1 == null || _remark1Controller.text.trim().isEmpty) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Optional Photo 1 and its remark are mandatory for this classification.'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- END: MODIFICATION 3 ---
|
||||||
|
|
||||||
|
// This is the existing validation you already had, which is still correct.
|
||||||
if (widget.data.optionalImage1 != null && _remark1Controller.text.trim().isEmpty) {
|
if (widget.data.optionalImage1 != null && _remark1Controller.text.trim().isEmpty) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('A remark is required for Optional Photo 1.'), backgroundColor: Colors.red),
|
const SnackBar(content: Text('A remark is required for Optional Photo 1.'), backgroundColor: Colors.red),
|
||||||
@ -237,7 +236,6 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// --- END: MODIFICATION 5 ---
|
|
||||||
|
|
||||||
widget.data.optionalRemark1 = _remark1Controller.text;
|
widget.data.optionalRemark1 = _remark1Controller.text;
|
||||||
widget.data.optionalRemark2 = _remark2Controller.text;
|
widget.data.optionalRemark2 = _remark2Controller.text;
|
||||||
@ -290,6 +288,20 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
_selectedClassification = value;
|
_selectedClassification = value;
|
||||||
widget.data.selectedClassification = value;
|
widget.data.selectedClassification = value;
|
||||||
widget.data.classificationId = value?['classification_id'];
|
widget.data.classificationId = value?['classification_id'];
|
||||||
|
|
||||||
|
// --- START: MODIFICATION 4 ---
|
||||||
|
// Update the state variable whenever the dropdown changes.
|
||||||
|
// This will drive the conditional UI and validation.
|
||||||
|
_isNoneClassificationSelected = widget.data.classificationId == 1;
|
||||||
|
|
||||||
|
// If user switches back to 'None', clear out old optional data
|
||||||
|
if (_isNoneClassificationSelected) {
|
||||||
|
widget.data.optionalImage1 = null;
|
||||||
|
widget.data.optionalRemark1 = null;
|
||||||
|
_remark1Controller.clear();
|
||||||
|
// You might want to clear others too if needed
|
||||||
|
}
|
||||||
|
// --- END: MODIFICATION 4 ---
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
validator: (value) => value == null ? 'Classification is required' : null,
|
validator: (value) => value == null ? 'Classification is required' : null,
|
||||||
@ -302,15 +314,28 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
_buildImagePicker('Left Side Coastal View', 'LEFTSIDECOASTALVIEW', widget.data.leftCoastalViewImage, (file) => widget.data.leftCoastalViewImage = file, isRequired: true),
|
_buildImagePicker('Left Side Coastal View', 'LEFTSIDECOASTALVIEW', widget.data.leftCoastalViewImage, (file) => widget.data.leftCoastalViewImage = file, isRequired: true),
|
||||||
_buildImagePicker('Right Side Coastal View', 'RIGHTSIDECOASTALVIEW', widget.data.rightCoastalViewImage, (file) => widget.data.rightCoastalViewImage = file, isRequired: true),
|
_buildImagePicker('Right Side Coastal View', 'RIGHTSIDECOASTALVIEW', widget.data.rightCoastalViewImage, (file) => widget.data.rightCoastalViewImage = file, isRequired: true),
|
||||||
_buildImagePicker('Drawing Vertical Lines', 'VERTICALLINES', widget.data.verticalLinesImage, (file) => widget.data.verticalLinesImage = file, isRequired: true),
|
_buildImagePicker('Drawing Vertical Lines', 'VERTICALLINES', widget.data.verticalLinesImage, (file) => widget.data.verticalLinesImage = file, isRequired: true),
|
||||||
_buildImagePicker('Drawing Horizontal Line', 'HORIZONTALLINE', widget.data.horizontalLineImage, (file) => widget.data.horizontalLineImage = file, isRequired: true),
|
_buildImagePicker('Drawing Horizontal Lines (Racking)', 'HORIZONTALLINE', widget.data.horizontalLineImage, (file) => widget.data.horizontalLineImage = file, isRequired: true),
|
||||||
|
|
||||||
|
// --- START: MODIFICATION 5 ---
|
||||||
|
// Wrap the entire "Optional Photos" section in a Visibility widget.
|
||||||
|
// It will only be visible if a classification has been selected AND it's not the "None" classification.
|
||||||
|
Visibility(
|
||||||
|
visible: _selectedClassification != null && !_isNoneClassificationSelected,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Text("Optional Photos & Remarks", style: Theme.of(context).textTheme.titleLarge),
|
Text("Optional Photos & Remarks", style: Theme.of(context).textTheme.titleLarge),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildImagePicker('Optional Photo 1', 'OPTIONAL1', widget.data.optionalImage1, (file) => widget.data.optionalImage1 = file, remarkController: _remark1Controller),
|
// For the first optional photo, we now mark it as required.
|
||||||
|
_buildImagePicker('Optional Photo 1', 'OPTIONAL1', widget.data.optionalImage1, (file) => widget.data.optionalImage1 = file, remarkController: _remark1Controller, isRequired: true),
|
||||||
_buildImagePicker('Optional Photo 2', 'OPTIONAL2', widget.data.optionalImage2, (file) => widget.data.optionalImage2 = file, remarkController: _remark2Controller),
|
_buildImagePicker('Optional Photo 2', 'OPTIONAL2', widget.data.optionalImage2, (file) => widget.data.optionalImage2 = file, remarkController: _remark2Controller),
|
||||||
_buildImagePicker('Optional Photo 3', 'OPTIONAL3', widget.data.optionalImage3, (file) => widget.data.optionalImage3 = file, remarkController: _remark3Controller),
|
_buildImagePicker('Optional Photo 3', 'OPTIONAL3', widget.data.optionalImage3, (file) => widget.data.optionalImage3 = file, remarkController: _remark3Controller),
|
||||||
_buildImagePicker('Optional Photo 4', 'OPTIONAL4', widget.data.optionalImage4, (file) => widget.data.optionalImage4 = file, remarkController: _remark4Controller),
|
_buildImagePicker('Optional Photo 4', 'OPTIONAL4', widget.data.optionalImage4, (file) => widget.data.optionalImage4 = file, remarkController: _remark4Controller),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// --- END: MODIFICATION 5 ---
|
||||||
|
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -357,11 +382,8 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
// --- START: MODIFICATION 6 ---
|
|
||||||
// The `isRequired` parameter is no longer passed to `_setImage`.
|
|
||||||
ElevatedButton.icon(onPressed: _isPickingImage ? null : () => _setImage(setImageCallback, ImageSource.camera, imageInfo), icon: const Icon(Icons.camera_alt), label: const Text("Camera")),
|
ElevatedButton.icon(onPressed: _isPickingImage ? null : () => _setImage(setImageCallback, ImageSource.camera, imageInfo), icon: const Icon(Icons.camera_alt), label: const Text("Camera")),
|
||||||
ElevatedButton.icon(onPressed: _isPickingImage ? null : () => _setImage(setImageCallback, ImageSource.gallery, imageInfo), icon: const Icon(Icons.photo_library), label: const Text("Gallery")),
|
ElevatedButton.icon(onPressed: _isPickingImage ? null : () => _setImage(setImageCallback, ImageSource.gallery, imageInfo), icon: const Icon(Icons.photo_library), label: const Text("Gallery")),
|
||||||
// --- END: MODIFICATION 6 ---
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (remarkController != null)
|
if (remarkController != null)
|
||||||
@ -370,8 +392,8 @@ class _TarballSamplingStep2State extends State<TarballSamplingStep2> {
|
|||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: remarkController,
|
controller: remarkController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Remarks for $title',
|
labelText: 'Remarks for $title' + (isRequired ? ' *' : ''), // Also indicate required status here
|
||||||
hintText: 'Add a remark...', // Changed hint text to be more direct
|
hintText: 'Add a remark...',
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -6,9 +6,7 @@ import 'package:provider/provider.dart';
|
|||||||
|
|
||||||
import 'package:environment_monitoring_app/auth_provider.dart';
|
import 'package:environment_monitoring_app/auth_provider.dart';
|
||||||
import 'package:environment_monitoring_app/models/tarball_data.dart';
|
import 'package:environment_monitoring_app/models/tarball_data.dart';
|
||||||
// START CHANGE: Import the new dedicated service
|
|
||||||
import 'package:environment_monitoring_app/services/marine_tarball_sampling_service.dart';
|
import 'package:environment_monitoring_app/services/marine_tarball_sampling_service.dart';
|
||||||
// END CHANGE
|
|
||||||
|
|
||||||
|
|
||||||
class TarballSamplingStep3Summary extends StatefulWidget {
|
class TarballSamplingStep3Summary extends StatefulWidget {
|
||||||
@ -20,23 +18,16 @@ class TarballSamplingStep3Summary extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summary> {
|
class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summary> {
|
||||||
// MODIFIED: The service instance is no longer created here.
|
|
||||||
// It will be fetched from the Provider where it's needed.
|
|
||||||
|
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
|
||||||
// START CHANGE: The _submitForm method is now greatly simplified
|
|
||||||
Future<void> _submitForm() async {
|
Future<void> _submitForm() async {
|
||||||
setState(() => _isLoading = true);
|
setState(() => _isLoading = true);
|
||||||
|
|
||||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||||
final appSettings = authProvider.appSettings;
|
final appSettings = authProvider.appSettings;
|
||||||
|
|
||||||
// ADDED: Fetch the global service instance from Provider before using it.
|
|
||||||
// We use listen: false as this is a one-time action within a method.
|
|
||||||
final tarballService = Provider.of<MarineTarballSamplingService>(context, listen: false);
|
final tarballService = Provider.of<MarineTarballSamplingService>(context, listen: false);
|
||||||
|
|
||||||
// Delegate the entire submission process to the new dedicated service
|
|
||||||
final result = await tarballService.submitTarballSample(
|
final result = await tarballService.submitTarballSample(
|
||||||
data: widget.data,
|
data: widget.data,
|
||||||
appSettings: appSettings,
|
appSettings: appSettings,
|
||||||
@ -56,7 +47,6 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
|
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
// END CHANGE
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -73,7 +63,7 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
_buildSectionCard(
|
_buildSectionCard(
|
||||||
"Sampling Details",
|
"Sampling Information",
|
||||||
[
|
[
|
||||||
_buildDetailRow("1st Sampler:", widget.data.firstSampler),
|
_buildDetailRow("1st Sampler:", widget.data.firstSampler),
|
||||||
_buildDetailRow("2nd Sampler:", widget.data.secondSampler?['first_name']?.toString()),
|
_buildDetailRow("2nd Sampler:", widget.data.secondSampler?['first_name']?.toString()),
|
||||||
@ -87,7 +77,7 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
[
|
[
|
||||||
_buildDetailRow("State:", widget.data.selectedStateName),
|
_buildDetailRow("State:", widget.data.selectedStateName),
|
||||||
_buildDetailRow("Category:", widget.data.selectedCategoryName),
|
_buildDetailRow("Category:", widget.data.selectedCategoryName),
|
||||||
_buildDetailRow("Station Code:", widget.data.selectedStation?['tbl_station_code']?.toString()),
|
_buildDetailRow("Station ID:", widget.data.selectedStation?['tbl_station_code']?.toString()),
|
||||||
_buildDetailRow("Station Name:", widget.data.selectedStation?['tbl_station_name']?.toString()),
|
_buildDetailRow("Station Name:", widget.data.selectedStation?['tbl_station_name']?.toString()),
|
||||||
_buildDetailRow("Station Latitude:", widget.data.stationLatitude),
|
_buildDetailRow("Station Latitude:", widget.data.stationLatitude),
|
||||||
_buildDetailRow("Station Longitude:", widget.data.stationLongitude),
|
_buildDetailRow("Station Longitude:", widget.data.stationLongitude),
|
||||||
@ -132,6 +122,15 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
_buildImageCard("Right Side Coastal View", widget.data.rightCoastalViewImage),
|
_buildImageCard("Right Side Coastal View", widget.data.rightCoastalViewImage),
|
||||||
_buildImageCard("Drawing Vertical Lines", widget.data.verticalLinesImage),
|
_buildImageCard("Drawing Vertical Lines", widget.data.verticalLinesImage),
|
||||||
_buildImageCard("Drawing Horizontal Line", widget.data.horizontalLineImage),
|
_buildImageCard("Drawing Horizontal Line", widget.data.horizontalLineImage),
|
||||||
|
|
||||||
|
// --- START: MODIFICATION ---
|
||||||
|
// Wrapped the optional photos section in a Visibility widget.
|
||||||
|
// It will only be shown if the classification ID is not 1 (i.e., not "None").
|
||||||
|
Visibility(
|
||||||
|
visible: widget.data.classificationId != 1,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
const Divider(height: 24),
|
const Divider(height: 24),
|
||||||
Text("Optional Photos", style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
Text("Optional Photos", style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
@ -141,6 +140,10 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
_buildImageCard("Optional Photo 4", widget.data.optionalImage4, remark: widget.data.optionalRemark4),
|
_buildImageCard("Optional Photo 4", widget.data.optionalImage4, remark: widget.data.optionalRemark4),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
// --- END: MODIFICATION ---
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
_isLoading
|
_isLoading
|
||||||
@ -216,6 +219,11 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildImageCard(String title, File? image, {String? remark}) {
|
Widget _buildImageCard(String title, File? image, {String? remark}) {
|
||||||
|
// Only build the card if there is an image or a remark to show.
|
||||||
|
if (image == null && (remark == null || remark.isEmpty)) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -242,7 +250,7 @@ class _TarballSamplingStep3SummaryState extends State<TarballSamplingStep3Summar
|
|||||||
if (remark != null && remark.isNotEmpty)
|
if (remark != null && remark.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
child: Text('Remark: $remark', style: const TextStyle(fontStyle: FontStyle.italic, color: Colors.black54)),
|
child: Text('Remark: $remark', style: const TextStyle(fontStyle: FontStyle.italic, color: Colors.grey)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -34,7 +34,7 @@ class _InSituStep2SiteInfoState extends State<InSituStep2SiteInfo> {
|
|||||||
// --- END MODIFICATION ---
|
// --- END MODIFICATION ---
|
||||||
|
|
||||||
|
|
||||||
final List<String> _weatherOptions = ['Clear', 'Rainy', 'Cloudy'];
|
final List<String> _weatherOptions = ['Clear', 'Cloudy', 'Drizzle', 'Rainy', 'Windy'];
|
||||||
final List<String> _tideOptions = ['High', 'Low', 'Mid'];
|
final List<String> _tideOptions = ['High', 'Low', 'Mid'];
|
||||||
final List<String> _seaConditionOptions = ['Calm', 'Moderate Wave', 'High Wave'];
|
final List<String> _seaConditionOptions = ['Calm', 'Moderate Wave', 'High Wave'];
|
||||||
|
|
||||||
|
|||||||
@ -387,7 +387,7 @@ class _InSituStep4SummaryState extends State<InSituStep4Summary> {
|
|||||||
const Divider(height: 20),
|
const Divider(height: 20),
|
||||||
_buildDetailRow("State:", widget.data.selectedStateName),
|
_buildDetailRow("State:", widget.data.selectedStateName),
|
||||||
_buildDetailRow("Category:", widget.data.selectedCategoryName),
|
_buildDetailRow("Category:", widget.data.selectedCategoryName),
|
||||||
_buildDetailRow("Station Code:",
|
_buildDetailRow("Station ID:",
|
||||||
widget.data.selectedStation?['man_station_code']?.toString()),
|
widget.data.selectedStation?['man_station_code']?.toString()),
|
||||||
_buildDetailRow("Station Name:",
|
_buildDetailRow("Station Name:",
|
||||||
widget.data.selectedStation?['man_station_name']?.toString()),
|
widget.data.selectedStation?['man_station_name']?.toString()),
|
||||||
|
|||||||
@ -748,7 +748,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.info_outline),
|
leading: const Icon(Icons.info_outline),
|
||||||
title: const Text('App Version'),
|
title: const Text('App Version'),
|
||||||
subtitle: const Text('MMS Version 3.4.01'),
|
subtitle: const Text('MMS Version 3.5.01'),
|
||||||
dense: true,
|
dense: true,
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user