Files
LearnIT/lib/features/settings/presentation/pages/settings_page.dart
240405 62b9a107bc - Dark / light mode a funcionar no lado do aluno
- Atualização dos ficheiros markdown.
2026-05-14 22:07:03 +01:00

382 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/theme/app_colors.dart';
import '../../../../core/services/theme_service.dart';
import '../../../../core/providers/theme_provider.dart';
/// Settings page for app configuration
class SettingsPage extends ConsumerStatefulWidget {
const SettingsPage({super.key});
@override
ConsumerState<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends ConsumerState<SettingsPage> {
@override
Widget build(BuildContext context) {
final themeMode = ref.watch(themeProvider);
final isDarkModeAvailable = ThemeService.isDarkModeAvailable();
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
if (!didPop) {
// Navigate to student dashboard on back button
context.go('/student-dashboard');
}
},
child: Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: themeMode == ThemeMode.light
? [
const Color(0xFFD4E8E8),
const Color(0xFFE8D4C0),
const Color(0xFFD8E0E8),
]
: [
Theme.of(context).colorScheme.primary.withOpacity(0.1),
Theme.of(context).colorScheme.secondary.withOpacity(0.05),
Theme.of(context).colorScheme.background,
],
),
),
child: SafeArea(
child: Column(
children: [
// Custom AppBar
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => context.go('/student-dashboard'),
),
Expanded(
child: Text(
'Configurações',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
// Settings content
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: [
// Appearance Section
_buildSection(
title: 'Aparência',
themeMode: themeMode,
children: [
_buildThemeTile(
context: context,
currentTheme: themeMode,
isDarkModeAvailable: isDarkModeAvailable,
onThemeChanged: (ThemeMode newTheme) async {
await ref
.read(themeProvider.notifier)
.setThemeMode(newTheme);
},
),
],
),
const SizedBox(height: 24),
// Future sections can be added here
_buildSection(
title: 'Notificações',
themeMode: themeMode,
children: [
_buildToggleTile(
themeMode: themeMode,
title: 'Notificações Push',
subtitle: 'Receber notificações da app',
value: false, // Future implementation
onChanged: null, // Future implementation
enabled: false, // Disabled for now
),
],
),
const SizedBox(height: 24),
_buildSection(
title: 'Conta',
themeMode: themeMode,
children: [
_buildActionTile(
themeMode: themeMode,
title: 'Perfil',
subtitle: 'Gerir informações do perfil',
icon: Icons.person,
onTap: () {
// Navigate to profile edit
context.push('/settings/profile-edit');
},
),
_buildActionTile(
themeMode: themeMode,
title: 'Privacidade',
subtitle: 'Definições de privacidade e segurança',
icon: Icons.security,
onTap: () {
// Navigate to privacy settings
},
),
],
),
const SizedBox(height: 24),
_buildSection(
title: 'Sobre',
themeMode: themeMode,
children: [
_buildInfoTile(
themeMode: themeMode,
title: 'Versão',
subtitle: '1.0.0',
icon: Icons.info,
),
_buildActionTile(
themeMode: themeMode,
title: 'Ajuda',
subtitle: 'Obter ajuda e suporte',
icon: Icons.help,
onTap: () {
// Navigate to help
context.push('/settings/help');
},
),
],
),
],
),
),
],
),
),
),
),
);
}
Widget _buildSection({
required String title,
required ThemeMode themeMode,
required List<Widget> children,
}) {
final isDark = themeMode == ThemeMode.dark;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 16, bottom: 8),
child: Text(
title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: isDark
? Colors.white70
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Theme.of(
context,
).colorScheme.onSurfaceVariant.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(children: children),
),
],
);
}
Widget _buildThemeTile({
required BuildContext context,
required ThemeMode currentTheme,
required bool isDarkModeAvailable,
required Function(ThemeMode) onThemeChanged,
}) {
final isDark = currentTheme == ThemeMode.dark;
return ListTile(
leading: const Icon(Icons.palette, color: AppColors.primaryTeal),
title: Text(
'Tema',
style: TextStyle(
color: isDark
? Colors.white
: Theme.of(context).colorScheme.onSurface,
),
),
subtitle: Text(
isDarkModeAvailable
? 'Atual: ${_getThemeModeString(currentTheme)}'
: 'Light Mode (padrão)',
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
trailing: isDarkModeAvailable
? DropdownButton<ThemeMode>(
value: currentTheme,
onChanged: (ThemeMode? newValue) {
if (newValue != null) {
onThemeChanged(newValue);
}
},
items: const [
DropdownMenuItem(
value: ThemeMode.light,
child: Text('Light Mode'),
),
DropdownMenuItem(
value: ThemeMode.dark,
child: Text('Dark Mode'),
),
DropdownMenuItem(
value: ThemeMode.system,
child: Text('System Default'),
),
],
)
: Icon(
Icons.lock,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
);
}
String _getThemeModeString(ThemeMode themeMode) {
switch (themeMode) {
case ThemeMode.light:
return 'Light Mode';
case ThemeMode.dark:
return 'Dark Mode';
case ThemeMode.system:
return 'System Default';
}
}
Widget _buildToggleTile({
required ThemeMode themeMode,
required String title,
required String subtitle,
required bool value,
required ValueChanged<bool>? onChanged,
bool enabled = true,
}) {
final isDark = themeMode == ThemeMode.dark;
return ListTile(
leading: const Icon(Icons.notifications, color: AppColors.primaryTeal),
title: Text(
title,
style: TextStyle(
color: isDark
? Colors.white
: Theme.of(context).colorScheme.onSurface,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
color: isDark
? Colors.white70
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
trailing: Switch(
value: value,
onChanged: enabled ? onChanged : null,
activeColor: AppColors.primaryTeal,
),
enabled: enabled,
);
}
Widget _buildActionTile({
required ThemeMode themeMode,
required String title,
required String subtitle,
required IconData icon,
required VoidCallback onTap,
}) {
final isDark = themeMode == ThemeMode.dark;
return ListTile(
leading: Icon(icon, color: AppColors.primaryTeal),
title: Text(
title,
style: TextStyle(
color: isDark
? Colors.white
: Theme.of(context).colorScheme.onSurface,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
color: isDark
? Colors.white70
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
trailing: Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
onTap: onTap,
);
}
Widget _buildInfoTile({
required ThemeMode themeMode,
required String title,
required String subtitle,
required IconData icon,
}) {
final isDark = themeMode == ThemeMode.dark;
return ListTile(
leading: Icon(icon, color: AppColors.primaryTeal),
title: Text(
title,
style: TextStyle(
color: isDark
? Colors.white
: Theme.of(context).colorScheme.onSurface,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
color: isDark
? Colors.white70
: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
);
}
}