// lib/screens/settings.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import 'package:environment_monitoring_app/auth_provider.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { bool _isSyncingData = false; Future _manualDataSync() async { if (_isSyncingData) return; setState(() => _isSyncingData = true); final auth = Provider.of(context, listen: false); // 1. Pre-sync checks if (!await auth.isConnected()) { _showSnackBar('Sync failed: No internet connection.', isError: true); setState(() => _isSyncingData = false); return; } if (auth.isSessionExpired) { _showSessionExpiredDialog(); setState(() => _isSyncingData = false); return; } // 2. Attempt the sync operation try { await auth.syncAllData(forceRefresh: true); // No need to reload settings here, child screens will load on demand if (mounted) { _showSnackBar('Data synced successfully.', isError: false); } } catch (e) { // 3. Handle failures if (mounted) { if (auth.isSessionExpired) { _showSessionExpiredDialog(); } else { _showSnackBar('Data sync failed: ${e.toString()}', isError: true); } } } finally { if (mounted) { setState(() => _isSyncingData = false); } } } void _showSessionExpiredDialog() { if (!mounted) return; showDialog( context: context, builder: (dialogContext) => AlertDialog( title: const Text("Session Expired"), content: const Text("Your session has expired and automatic re-login failed. Please log out and log in again to sync data."), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), child: const Text("OK"), ), ElevatedButton( onPressed: () { final auth = Provider.of(context, listen: false); Navigator.pop(dialogContext); auth.logout(); Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false); }, child: const Text("Logout"), ), ], ), ); } void _showSnackBar(String message, {bool isError = false}) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: isError ? Theme.of(context).colorScheme.error : Colors.green, ), ); } } Widget _buildSectionHeader(BuildContext context, String title) { return Padding( padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 16.0), child: Text( title, style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold), ), ); } Widget _buildNavTile(BuildContext context, { required String title, required String subtitle, required IconData icon, required String routeName, }) { return Card( margin: const EdgeInsets.symmetric(vertical: 6.0), child: ListTile( leading: Icon(icon, size: 32.0, color: Theme.of(context).colorScheme.primary), title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), subtitle: Text(subtitle), trailing: const Icon(Icons.arrow_forward_ios), onTap: () { Navigator.pushNamed(context, routeName); }, ), ); } @override Widget build(BuildContext context) { final auth = Provider.of(context); final lastSync = auth.lastSyncTimestamp; return Scaffold( appBar: AppBar( title: const Text("Settings"), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionHeader(context, "Synchronization"), Card( margin: const EdgeInsets.symmetric(vertical: 6.0), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text("Last Data Sync:", style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 4), Text(lastSync != null ? DateFormat('yyyy-MM-dd HH:mm:ss').format(lastSync.toLocal()) : 'Never', style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 16), ElevatedButton.icon( onPressed: _isSyncingData ? null : _manualDataSync, icon: _isSyncingData ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.cloud_sync), label: Text(_isSyncingData ? 'Syncing Data...' : 'Sync App Data'), style: ElevatedButton.styleFrom(minimumSize: const Size(double.infinity, 50)), ), ], ), ), ), const SizedBox(height: 32), _buildSectionHeader(context, "App Management"), _buildNavTile( context, title: "Submission Preferences", subtitle: "Manage API & FTP submissions for each module.", icon: Icons.send_to_mobile, routeName: '/settings/submission-prefs', ), _buildNavTile( context, title: "Telegram Alert Settings", subtitle: "View Telegram chat IDs for alerts.", icon: Icons.telegram, routeName: '/settings/telegram-alerts', ), _buildNavTile( context, title: "API/FTP Configurations", subtitle: "View synced server configurations.", icon: Icons.dns, routeName: '/settings/api-ftp-configs', ), _buildNavTile( context, title: "Parameter Limits", subtitle: "View parameter limits for all modules.", icon: Icons.science_outlined, routeName: '/settings/parameter-limits', ), _buildNavTile( context, title: "Air Clients", subtitle: "View and search for synced Air clients.", icon: Icons.air, routeName: '/settings/air-clients', ), _buildNavTile( context, title: "Station Info", subtitle: "View and search all synced stations.", icon: Icons.location_on, routeName: '/settings/station-info', ), const SizedBox(height: 32), _buildSectionHeader(context, "Other Information"), Card( margin: const EdgeInsets.symmetric(vertical: 6.0), child: Column( children: [ ListTile( leading: const Icon(Icons.info_outline), title: const Text('App Version'), subtitle: const Text('MMS Version 3.8.01'), dense: true, ), ListTile( leading: const Icon(Icons.privacy_tip_outlined), title: const Text('Privacy Policy'), onTap: () {}, dense: true, ), ], ), ), ], ), ), ); } }