- Update localization imports to use package path - Remove unused provider import from main.dart - Fix default test file - Refactor settings dialogs to use Radio widget
236 lines
6.1 KiB
Dart
236 lines
6.1 KiB
Dart
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 '../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<SettingsViewModel>();
|
|
|
|
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.general),
|
|
ListTile(
|
|
leading: const Icon(Icons.language),
|
|
title: Text(l10n.language),
|
|
subtitle: Text(
|
|
settingsVm.locale != null
|
|
? settingsVm.getLanguageName(settingsVm.locale!)
|
|
: l10n.systemDefault,
|
|
),
|
|
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'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
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,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
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 Locale? _selectedLocale;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_selectedLocale = widget.vm.locale;
|
|
}
|
|
|
|
@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<Locale>(
|
|
value: locale,
|
|
groupValue: _selectedLocale,
|
|
onChanged: (value) {
|
|
setState(() => _selectedLocale = value);
|
|
if (value != null) {
|
|
widget.vm.setLocale(value);
|
|
Navigator.pop(context);
|
|
}
|
|
},
|
|
),
|
|
onTap: () {
|
|
setState(() => _selectedLocale = locale);
|
|
widget.vm.setLocale(locale);
|
|
Navigator.pop(context);
|
|
},
|
|
);
|
|
}).toList(),
|
|
),
|
|
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<ThemeMode>(
|
|
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,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|