// lib/screens/settings/station_info_settings.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:environment_monitoring_app/auth_provider.dart'; class StationInfoSettingsScreen extends StatefulWidget { const StationInfoSettingsScreen({super.key}); @override State createState() => _StationInfoSettingsScreenState(); } class _StationInfoSettingsScreenState extends State { final TextEditingController _tarballSearchController = TextEditingController(); String _tarballSearchQuery = ''; final TextEditingController _manualSearchController = TextEditingController(); String _manualSearchQuery = ''; final TextEditingController _riverManualSearchController = TextEditingController(); String _riverManualSearchQuery = ''; final TextEditingController _riverTriennialSearchController = TextEditingController(); String _riverTriennialSearchQuery = ''; final TextEditingController _airStationSearchController = TextEditingController(); String _airStationSearchQuery = ''; @override void initState() { super.initState(); _tarballSearchController.addListener(_onTarballSearchChanged); _manualSearchController.addListener(_onManualSearchChanged); _riverManualSearchController.addListener(_onRiverManualSearchChanged); _riverTriennialSearchController.addListener(_onRiverTriennialSearchChanged); _airStationSearchController.addListener(_onAirStationSearchChanged); } @override void dispose() { _tarballSearchController.dispose(); _manualSearchController.dispose(); _riverManualSearchController.dispose(); _riverTriennialSearchController.dispose(); _airStationSearchController.dispose(); super.dispose(); } void _onTarballSearchChanged() { setState(() { _tarballSearchQuery = _tarballSearchController.text; }); } void _onManualSearchChanged() { setState(() { _manualSearchQuery = _manualSearchController.text; }); } void _onRiverManualSearchChanged() { setState(() { _riverManualSearchQuery = _riverManualSearchController.text; }); } void _onRiverTriennialSearchChanged() { setState(() { _riverTriennialSearchQuery = _riverTriennialSearchController.text; }); } void _onAirStationSearchChanged() { setState(() { _airStationSearchQuery = _airStationSearchController.text; }); } Widget _buildSectionHeader(BuildContext context, String title) { return Padding( padding: const EdgeInsets.fromLTRB(8.0, 24.0, 8.0, 16.0), child: Text( title, style: Theme.of(context) .textTheme .headlineSmall ?.copyWith(fontWeight: FontWeight.bold), ), ); } Widget _buildExpansionTile({ required String title, required IconData leadingIcon, required Widget child, }) { return ExpansionTile( leading: Icon(leadingIcon), title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), initiallyExpanded: true, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: child, ), ], ); } Widget _buildSearchBar({ required TextEditingController controller, required String labelText, required String hintText, }) { return Padding( padding: const EdgeInsets.only(bottom: 8.0, top: 8.0), child: TextField( controller: controller, decoration: InputDecoration( labelText: labelText, hintText: hintText, prefixIcon: const Icon(Icons.search), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.0)), suffixIcon: controller.text.isNotEmpty ? IconButton( icon: const Icon(Icons.clear), onPressed: () => controller.clear()) : null, ), style: const TextStyle(fontSize: 14), ), ); } Widget _buildStationList( List>? stations, String noMatchText, String noDataText, Widget Function(Map) itemBuilder, {double height = 250}) { if (stations == null || stations.isEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Text( stations == null ? noDataText : noMatchText, textAlign: TextAlign.center, ), ), ); } return SizedBox( height: height, child: ListView.builder( itemCount: stations.length, itemBuilder: (context, index) { final station = stations[index]; return itemBuilder(station); }, ), ); } Widget _buildStationTile( {required String title, required String subtitle, required String type}) { return ListTile( title: Text(title, style: const TextStyle(fontSize: 14)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(subtitle, style: const TextStyle(fontSize: 12)), Text('Type: $type', style: const TextStyle(fontSize: 12, fontStyle: FontStyle.italic)), ], ), dense: true, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Station Info"), ), body: Consumer( builder: (context, auth, child) { final filteredTarballStations = (auth.tarballStations?.where((station) { final stationName = station['tbl_station_name']?.toLowerCase() ?? ''; final stationCode = station['tbl_station_code']?.toLowerCase() ?? ''; final query = _tarballSearchQuery.toLowerCase(); return stationName.contains(query) || stationCode.contains(query); }).toList()) ?.cast>(); final filteredManualStations = (auth.manualStations?.where((station) { final stationName = station['man_station_name']?.toLowerCase() ?? ''; final stationCode = station['man_station_code']?.toLowerCase() ?? ''; final query = _manualSearchQuery.toLowerCase(); return stationName.contains(query) || stationCode.contains(query); }).toList()) ?.cast>(); final filteredRiverManualStations = (auth.riverManualStations?.where((station) { final riverName = station['sampling_river']?.toLowerCase() ?? ''; final stationCode = station['sampling_station_code']?.toLowerCase() ?? ''; final basinName = station['sampling_basin']?.toLowerCase() ?? ''; final query = _riverManualSearchQuery.toLowerCase(); return riverName.contains(query) || stationCode.contains(query) || basinName.contains(query); }).toList()) ?.cast>(); final filteredRiverTriennialStations = (auth.riverTriennialStations?.where((station) { final riverName = station['triennial_river']?.toLowerCase() ?? ''; final stationCode = station['triennial_station_code']?.toLowerCase() ?? ''; final basinName = station['triennial_basin']?.toLowerCase() ?? ''; final query = _riverTriennialSearchQuery.toLowerCase(); return riverName.contains(query) || stationCode.contains(query) || basinName.contains(query); }).toList()) ?.cast>(); final filteredAirStations = (auth.airManualStations?.where((station) { final stationName = station['station_name']?.toLowerCase() ?? ''; final stationCode = station['station_code']?.toLowerCase() ?? ''; final query = _airStationSearchQuery.toLowerCase(); return stationName.contains(query) || stationCode.contains(query); }).toList()) ?.cast>(); return ListView( padding: const EdgeInsets.all(16.0), children: [ _buildSectionHeader(context, "Stations Info"), Card( margin: EdgeInsets.zero, child: Column( children: [ _buildExpansionTile( title: 'Marine Stations', leadingIcon: Icons.waves, child: Column( children: [ _buildSearchBar( controller: _tarballSearchController, labelText: 'Search Tarball Stations', hintText: 'Search by name or code', ), const SizedBox(height: 16), _buildStationList( filteredTarballStations, 'No matching tarball stations found.', 'No tarball stations available. Sync to download.', (station) => _buildStationTile( title: station['tbl_station_name'] ?? 'N/A', subtitle: 'Code: ${station['tbl_station_code'] ?? 'N/A'}', type: 'Tarball'), height: 250, ), const SizedBox(height: 16), _buildSearchBar( controller: _manualSearchController, labelText: 'Search Manual Stations', hintText: 'Search by name or code', ), const SizedBox(height: 16), _buildStationList( filteredManualStations, 'No matching manual stations found.', 'No manual stations available. Sync to download.', (station) => _buildStationTile( title: station['man_station_name'] ?? 'N/A', subtitle: 'Code: ${station['man_station_code'] ?? 'N/A'}', type: 'Manual'), height: 250, ), ], ), ), _buildExpansionTile( title: 'River Stations', leadingIcon: Icons.water, child: Column( children: [ _buildSearchBar( controller: _riverManualSearchController, labelText: 'Search River Manual Stations', hintText: 'Search by name, code, or basin', ), const SizedBox(height: 16), _buildStationList( filteredRiverManualStations, 'No matching river manual stations found.', 'No river manual stations available. Sync to download.', (station) => _buildStationTile( title: station['sampling_river'] ?? 'N/A', subtitle: 'Code: ${station['sampling_station_code'] ?? 'N/A'}, Basin: ${station['sampling_basin'] ?? 'N/A'}', type: 'River Manual'), height: 250, ), const SizedBox(height: 16), _buildSearchBar( controller: _riverTriennialSearchController, labelText: 'Search River Triennial Stations', hintText: 'Search by name, code, or basin', ), const SizedBox(height: 16), _buildStationList( filteredRiverTriennialStations, 'No matching river triennial stations found.', 'No river triennial stations available. Sync to download.', (station) => _buildStationTile( title: station['triennial_river'] ?? 'N/A', subtitle: 'Code: ${station['triennial_station_code'] ?? 'N/A'}, Basin: ${station['triennial_basin'] ?? 'N/A'}', type: 'River Triennial'), height: 250, ), ], ), ), _buildExpansionTile( title: 'Air Stations', leadingIcon: Icons.air, child: Column( children: [ _buildSearchBar( controller: _airStationSearchController, labelText: 'Search Air Stations', hintText: 'Search by name or code', ), const SizedBox(height: 16), _buildStationList( filteredAirStations, 'No matching air stations found.', 'No air stations available. Sync to download.', (station) => _buildStationTile( title: station['station_name'] ?? 'N/A', subtitle: 'Code: ${station['station_code'] ?? 'N/A'}', type: 'Air'), height: 250, ), ], ), ), ], ), ), ], ); }, ), ); } }