ionic-planb-logistic-app-fl.../lib/pages/settings_page.dart
Mathias Beaulieu-Duncan edb106a7fd Refactor theme system and remove unused platforms
- Overhaul theme system with Svrnty design and WCAG AAA compliance
- Remove android, macos, and web platform files (iOS-only focus)
- Update components with improved dark mode map and UI refinements
- Enhance settings page with additional configuration options
- Add theme system documentation in lib/theme/README.md
- Update CLAUDE.md with comprehensive theme guidelines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 14:47:51 -05:00

318 lines
13 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../l10n/app_localizations.dart';
import '../providers/providers.dart';
class SettingsPage extends ConsumerWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userProfile = ref.watch(userProfileProvider);
final languageAsync = ref.watch(languageProvider);
final themeMode = ref.watch(themeModeProvider);
final l10n = AppLocalizations.of(context);
final language = languageAsync.maybeWhen(
data: (value) => value,
orElse: () => 'system',
);
return Scaffold(
appBar: AppBar(
title: Text(l10n.settings),
),
body: ListView(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.profile,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
userProfile.when(
data: (profile) {
if (profile == null) {
return Text(l10n.noProfileInfo);
}
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 32,
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
child: Text(
profile.firstName[0].toUpperCase(),
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: FontWeight.w700,
),
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
profile.fullName,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
Text(
profile.email,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: FilledButton.tonalIcon(
onPressed: () async {
final authService = ref.read(authServiceProvider);
await authService.logout();
if (context.mounted) {
// ignore: unused_result
ref.refresh(isAuthenticatedProvider);
if (context.mounted) {
Navigator.of(context).pushReplacementNamed('/');
}
}
},
icon: const Icon(Icons.logout),
label: Text(
l10n.logout,
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 16,
),
),
style: FilledButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.errorContainer,
foregroundColor: Theme.of(context).colorScheme.onErrorContainer,
),
),
),
],
),
),
);
},
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) => Text(l10n.error(error.toString())),
),
],
),
),
const Divider(),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.preferences,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
ListTile(
title: Text(
l10n.language,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w700,
fontSize: 16,
),
),
subtitle: Text(
language == 'system'
? l10n.systemLanguage
: language == 'fr'
? l10n.french
: l10n.english,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
trailing: DropdownButton<String>(
value: language,
onChanged: (String? newValue) {
if (newValue != null) {
ref.read(languageProvider.notifier).setLanguage(newValue);
}
},
items: [
DropdownMenuItem(
value: 'system',
child: Text(
l10n.systemLanguage,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
DropdownMenuItem(
value: 'en',
child: Text(
l10n.english,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
DropdownMenuItem(
value: 'fr',
child: Text(
l10n.french,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
),
),
const SizedBox(height: 16),
ListTile(
title: Text(
l10n.theme,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w700,
fontSize: 16,
),
),
subtitle: Text(
themeMode == ThemeMode.light
? l10n.themeLight
: themeMode == ThemeMode.dark
? l10n.themeDark
: 'Device',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
trailing: DropdownButton<ThemeMode>(
value: themeMode,
onChanged: (ThemeMode? newValue) {
if (newValue != null) {
ref.read(themeModeProvider.notifier).setThemeMode(newValue);
}
},
items: [
DropdownMenuItem(
value: ThemeMode.light,
child: Text(
l10n.themeLight,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
DropdownMenuItem(
value: ThemeMode.dark,
child: Text(
l10n.themeDark,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
DropdownMenuItem(
value: ThemeMode.system,
child: Text(
'Device',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
),
),
],
),
),
const Divider(),
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.about,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
ListTile(
title: Text(
l10n.appVersion,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w700,
fontSize: 16,
),
),
subtitle: Text(
'1.0.0',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
),
),
],
),
);
}
}