import 'package:flutter/material.dart'; import 'package:agenda_tasks/l10n/app_localizations.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../../../auth/presentation/viewmodels/auth_viewmodel.dart'; import '../../domain/enums/app_mode.dart'; import '../viewmodels/settings_viewmodel.dart'; class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final settingsVm = context.watch(); return Scaffold( appBar: AppBar( title: Text(l10n.settings), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => context.pop(), ), ), body: ListView( children: [ _SectionHeader(title: l10n.appMode), ListTile( leading: Icon( settingsVm.isLocalMode ? Icons.smartphone : Icons.cloud_sync, ), title: Text(settingsVm.isLocalMode ? l10n.localMode : l10n.onlineMode), subtitle: Text( settingsVm.isLocalMode ? l10n.useLocallyDesc : l10n.syncOnlineDesc, ), trailing: const Icon(Icons.chevron_right), onTap: () => _showModeSwitchDialog(context, settingsVm, l10n), ), const Divider(), _SectionHeader(title: l10n.general), ListTile( leading: const Icon(Icons.language), title: Text(l10n.language), subtitle: Text(settingsVm.getLanguageName(settingsVm.locale!)), trailing: const Icon(Icons.chevron_right), onTap: () => _showLanguageDialog(context, settingsVm, l10n), ), const Divider(), _SectionHeader(title: l10n.appearance), ListTile( leading: const Icon(Icons.dark_mode), title: Text(l10n.darkMode), subtitle: Text(_getThemeModeLabel(settingsVm.themeMode, l10n)), trailing: const Icon(Icons.chevron_right), onTap: () => _showThemeDialog(context, settingsVm, l10n), ), const Divider(), _SectionHeader(title: l10n.about), ListTile( leading: const Icon(Icons.info_outline), title: Text(l10n.version), subtitle: const Text('1.0.0'), ), // Only show logout button in online mode when authenticated if (settingsVm.isOnlineMode) ...[ const Divider(), const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: SizedBox( height: 56, child: OutlinedButton.icon( onPressed: () => _showLogoutConfirmation(context, l10n), icon: const Icon(Icons.logout), label: Text(l10n.logout), style: OutlinedButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.error, side: BorderSide(color: Theme.of(context).colorScheme.error), ), ), ), ), ], const SizedBox(height: 32), ], ), ); } String _getThemeModeLabel(ThemeMode mode, AppLocalizations l10n) { switch (mode) { case ThemeMode.system: return l10n.systemDefault; case ThemeMode.light: return l10n.lightMode; case ThemeMode.dark: return l10n.darkModeOption; } } void _showLanguageDialog( BuildContext context, SettingsViewModel vm, AppLocalizations l10n, ) { showDialog( context: context, builder: (dialogContext) => _LanguageDialog( vm: vm, l10n: l10n, ), ); } void _showThemeDialog( BuildContext context, SettingsViewModel vm, AppLocalizations l10n, ) { showDialog( context: context, builder: (dialogContext) => _ThemeDialog( vm: vm, l10n: l10n, ), ); } void _showModeSwitchDialog( BuildContext context, SettingsViewModel settingsVm, AppLocalizations l10n, ) { final isLocalMode = settingsVm.isLocalMode; showDialog( context: context, builder: (dialogContext) => AlertDialog( title: Text(isLocalMode ? l10n.switchToOnline : l10n.switchToLocal), content: Text(l10n.switchModeWarning), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), child: Text(l10n.cancel), ), FilledButton( onPressed: () async { Navigator.pop(dialogContext); if (isLocalMode) { // Switching from local to online // First, ask if user wants to upload local tasks final uploadTasks = await _showUploadTasksDialog(context, l10n); if (uploadTasks == true) { // TODO: Implement task upload to server after login // For now, just switch mode and go to login } await settingsVm.setAppMode(AppMode.online); if (context.mounted) { context.go('/login'); } } else { // Switching from online to local await context.read().logout(); await settingsVm.setAppMode(AppMode.local); if (context.mounted) { context.go('/'); } } }, child: Text(isLocalMode ? l10n.switchToOnline : l10n.switchToLocal), ), ], ), ); } Future _showUploadTasksDialog( BuildContext context, AppLocalizations l10n, ) async { return showDialog( context: context, builder: (dialogContext) => AlertDialog( title: Text(l10n.uploadTasksQuestion), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), child: Text(l10n.no), ), FilledButton( onPressed: () => Navigator.pop(dialogContext, true), child: Text(l10n.yes), ), ], ), ); } void _showLogoutConfirmation(BuildContext context, AppLocalizations l10n) { showDialog( context: context, builder: (dialogContext) => AlertDialog( title: Text(l10n.logout), content: Text(l10n.logoutConfirmation), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext), child: Text(l10n.cancel), ), FilledButton( onPressed: () async { final authVm = context.read(); final settingsVm = context.read(); Navigator.pop(dialogContext); await authVm.logout(); // Reset setup so user returns to setup screen on next launch await settingsVm.setSetupCompleted(false); await settingsVm.setOnboardingShown(false); if (context.mounted) { context.go('/setup'); } }, style: FilledButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.error, ), child: Text(l10n.logout), ), ], ), ); } } class _LanguageDialog extends StatefulWidget { final SettingsViewModel vm; final AppLocalizations l10n; const _LanguageDialog({required this.vm, required this.l10n}); @override State<_LanguageDialog> createState() => _LanguageDialogState(); } class _LanguageDialogState extends State<_LanguageDialog> { late String _selectedLanguage; @override void initState() { super.initState(); _selectedLanguage = widget.vm.locale!.languageCode; } @override Widget build(BuildContext context) { return AlertDialog( title: Text(widget.l10n.language), content: Column( mainAxisSize: MainAxisSize.min, children: [ ...SettingsViewModel.supportedLocales.map((locale) { return ListTile( title: Text(widget.vm.getLanguageName(locale)), leading: Radio( value: locale.languageCode, groupValue: _selectedLanguage, onChanged: (value) { setState(() => _selectedLanguage = value!); widget.vm.setLocale(locale); Navigator.pop(context); }, ), onTap: () { setState(() => _selectedLanguage = locale.languageCode); widget.vm.setLocale(locale); Navigator.pop(context); }, ); }), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text(widget.l10n.cancel), ), ], ); } } class _ThemeDialog extends StatefulWidget { final SettingsViewModel vm; final AppLocalizations l10n; const _ThemeDialog({required this.vm, required this.l10n}); @override State<_ThemeDialog> createState() => _ThemeDialogState(); } class _ThemeDialogState extends State<_ThemeDialog> { late ThemeMode _selectedMode; @override void initState() { super.initState(); _selectedMode = widget.vm.themeMode; } @override Widget build(BuildContext context) { return AlertDialog( title: Text(widget.l10n.darkMode), content: Column( mainAxisSize: MainAxisSize.min, children: [ _buildThemeOption(ThemeMode.system, widget.l10n.systemDefault), _buildThemeOption(ThemeMode.light, widget.l10n.lightMode), _buildThemeOption(ThemeMode.dark, widget.l10n.darkModeOption), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text(widget.l10n.cancel), ), ], ); } Widget _buildThemeOption(ThemeMode mode, String label) { return ListTile( title: Text(label), leading: Radio( value: mode, groupValue: _selectedMode, onChanged: (value) { setState(() => _selectedMode = value!); widget.vm.setThemeMode(value!); Navigator.pop(context); }, ), onTap: () { setState(() => _selectedMode = mode); widget.vm.setThemeMode(mode); Navigator.pop(context); }, ); } } class _SectionHeader extends StatelessWidget { final String title; const _SectionHeader({required this.title}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Text( title.toUpperCase(), style: Theme.of(context).textTheme.labelSmall?.copyWith( color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.bold, ), ), ); } }