leafittome/lib/features/settings/presentation/settings_screen.dart
cschlaefke 53ee30c598 Firestore und Auth: echte Daten statt Demo, Login mit E-Mail+Passwort, Security Rules
- Datenmodell: users/{uid}, households/{id} mit memberUids, plants/locations als Subcollections
- StreamProvider liefern Live-Daten, Repositories kapseln Schreibzugriffe
- Login-Screen mit Registrierung (legt Haushalt automatisch an), Logout in Einstellungen
- Router-Redirect bei Login/Logout, firestore.rules mit Haushalts-Prinzip
- Tests auf firebase_auth_mocks + fake_cloud_firestore umgestellt
- Verifiziert: analyze/test grün, Android-Debug-Build erfolgreich

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 22:53:09 +02:00

127 lines
4.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/firebase/firebase_providers.dart';
import '../../../core/settings/settings_provider.dart';
import '../../../core/widgets/app_drawer.dart';
import '../../../l10n/generated/app_localizations.dart';
import '../../auth/data/auth_repository.dart';
class SettingsScreen extends ConsumerWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context);
final settings = ref.watch(settingsProvider);
final notifier = ref.read(settingsProvider.notifier);
return Scaffold(
appBar: AppBar(title: Text(l10n.settingsTitle)),
drawer: const AppDrawer(),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_SectionTitle(l10n.settingsAppearance),
SegmentedButton<ThemeMode>(
segments: [
ButtonSegment(
value: ThemeMode.system,
label: Text(l10n.themeSystem),
icon: const Icon(Icons.brightness_auto),
),
ButtonSegment(
value: ThemeMode.light,
label: Text(l10n.themeLight),
icon: const Icon(Icons.light_mode),
),
ButtonSegment(
value: ThemeMode.dark,
label: Text(l10n.themeDark),
icon: const Icon(Icons.dark_mode),
),
],
selected: {settings.themeMode},
onSelectionChanged: (selection) =>
notifier.setThemeMode(selection.first),
),
const SizedBox(height: 24),
_SectionTitle(l10n.settingsTextSize),
SegmentedButton<AppTextSize>(
segments: [
ButtonSegment(
value: AppTextSize.normal,
label: Text(l10n.textSizeNormal),
),
ButtonSegment(
value: AppTextSize.large,
label: Text(l10n.textSizeLarge),
),
ButtonSegment(
value: AppTextSize.extraLarge,
label: Text(l10n.textSizeXLarge),
),
],
selected: {settings.textSize},
onSelectionChanged: (selection) =>
notifier.setTextSize(selection.first),
),
const SizedBox(height: 16),
SwitchListTile(
title: Text(l10n.settingsHighContrast),
value: settings.highContrast,
onChanged: notifier.setHighContrast,
contentPadding: EdgeInsets.zero,
),
const Divider(height: 32),
_SectionTitle(l10n.settingsReminderTime),
ListTile(
contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.notifications_active),
title: Text(
settings.reminderTime.format(context),
style: Theme.of(context).textTheme.titleLarge,
),
subtitle: Text(l10n.settingsReminderTimeHint),
trailing: const Icon(Icons.chevron_right),
onTap: () async {
final picked = await showTimePicker(
context: context,
initialTime: settings.reminderTime,
);
if (picked != null) {
notifier.setReminderTime(picked);
}
},
),
const Divider(height: 32),
_SectionTitle(l10n.settingsAccount),
ListTile(
contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.person),
title: Text(
ref.watch(authStateProvider).value?.email ?? '',
),
subtitle: Text(l10n.logout),
trailing: const Icon(Icons.logout),
onTap: () => ref.read(authRepositoryProvider).signOut(),
),
],
),
);
}
}
class _SectionTitle extends StatelessWidget {
const _SectionTitle(this.title);
final String title;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Text(title, style: Theme.of(context).textTheme.titleMedium),
);
}
}