timetracker/lib/features/settings/presentation/settings_screen.dart
2026-08-03 21:51:48 +02:00

160 lines
5.5 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:timetrack/features/settings/domain/settings_provider.dart';
import 'package:timetrack/features/settings/presentation/widgets/export_sheet.dart';
class SettingsScreen extends ConsumerWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final themeMode = ref.watch(themeModeNotifierProvider);
final locale = ref.watch(localeNotifierProvider);
final quickAccessCount = ref.watch(quickAccessCountNotifierProvider);
return Scaffold(
appBar: AppBar(title: const Text('Settings')),
body: ListView(
children: [
// Appearance
_SectionHeader(label: 'Appearance'),
ListTile(
leading: const Icon(Icons.brightness_6_outlined),
title: const Text('Theme'),
trailing: DropdownButton<ThemeMode>(
value: themeMode,
underline: const SizedBox.shrink(),
items: const [
DropdownMenuItem(value: ThemeMode.system, child: Text('System')),
DropdownMenuItem(value: ThemeMode.light, child: Text('Light')),
DropdownMenuItem(value: ThemeMode.dark, child: Text('Dark')),
],
onChanged: (mode) {
if (mode != null) {
ref.read(themeModeNotifierProvider.notifier).setThemeMode(mode);
}
},
),
),
ListTile(
leading: const Icon(Icons.language_outlined),
title: const Text('Language'),
trailing: DropdownButton<Locale?>(
value: locale,
underline: const SizedBox.shrink(),
items: const [
DropdownMenuItem(value: null, child: Text('System')),
DropdownMenuItem(value: Locale('en'), child: Text('English')),
DropdownMenuItem(value: Locale('de'), child: Text('Deutsch')),
],
onChanged: (l) {
ref.read(localeNotifierProvider.notifier).setLocale(l);
},
),
),
const Divider(),
// Timer
_SectionHeader(label: 'Timer'),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Row(
children: [
const Icon(Icons.bolt_outlined, size: 20),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Quick access projects',
style: Theme.of(context).textTheme.bodyLarge,
),
Text(
'Number of frequently used projects shown above the project picker (${QuickAccessCountNotifier.minCount}${QuickAccessCountNotifier.maxCount})',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
),
Text(
'$quickAccessCount',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
],
),
),
Slider(
value: quickAccessCount.toDouble(),
min: QuickAccessCountNotifier.minCount.toDouble(),
max: QuickAccessCountNotifier.maxCount.toDouble(),
divisions: QuickAccessCountNotifier.maxCount - QuickAccessCountNotifier.minCount,
label: '$quickAccessCount',
onChanged: (value) {
ref
.read(quickAccessCountNotifierProvider.notifier)
.setCount(value.round());
},
),
const Divider(),
// Data
_SectionHeader(label: 'Data'),
ListTile(
leading: const Icon(Icons.upload_outlined),
title: const Text('Export data'),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () => ExportSheet.show(context),
),
const Divider(),
// About
_SectionHeader(label: 'About'),
const ListTile(
leading: Icon(Icons.info_outline),
title: Text('Version'),
trailing: Text('0.1.0'),
),
ListTile(
leading: const Icon(Icons.article_outlined),
title: const Text('Licences'),
onTap: () => showLicensePage(
context: context,
applicationName: 'Timetrack',
applicationVersion: '0.1.0',
),
),
],
),
);
}
}
class _SectionHeader extends StatelessWidget {
const _SectionHeader({required this.label});
final String label;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 4),
child: Text(
label,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: Theme.of(context).colorScheme.primary,
),
),
);
}
}