environment_monitoring_app/lib/screens/settings.dart

241 lines
7.8 KiB
Dart

// 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<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _isSyncingData = false;
Future<void> _manualDataSync() async {
if (_isSyncingData) return;
setState(() => _isSyncingData = true);
final auth = Provider.of<AuthProvider>(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<AuthProvider>(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<AuthProvider>(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.12.06'),
dense: true,
),
ListTile(
leading: const Icon(Icons.privacy_tip_outlined),
title: const Text('Privacy Policy'),
onTap: () {},
dense: true,
),
],
),
),
],
),
),
);
}
}