import 'package:cloud_functions/cloud_functions.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/firebase/firebase_providers.dart'; import '../../../core/widgets/app_drawer.dart'; import '../../../l10n/generated/app_localizations.dart'; import '../data/household_providers.dart'; import '../domain/household.dart'; /// Haushalt: Mitglieder mit Rollen, Einladen per Code, Beitreten per Code. class HouseholdScreen extends ConsumerStatefulWidget { const HouseholdScreen({super.key}); @override ConsumerState createState() => _HouseholdScreenState(); } class _HouseholdScreenState extends ConsumerState { final _codeController = TextEditingController(); bool _joining = false; @override void dispose() { _codeController.dispose(); super.dispose(); } Future _createInvite(HouseholdRole role) async { final l10n = AppLocalizations.of(context); final householdId = ref.read(householdIdProvider).value; if (householdId == null) return; final code = await ref .read(householdRepositoryProvider) .createInvite(householdId: householdId, role: role); if (!mounted) return; await showDialog( context: context, builder: (dialogContext) => AlertDialog( title: Text(l10n.inviteCodeTitle), content: Column( mainAxisSize: MainAxisSize.min, children: [ SelectableText( code, style: Theme.of(dialogContext) .textTheme .displaySmall ?.copyWith(letterSpacing: 6, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 12), Text(l10n.inviteCodeHint), ], ), actions: [ TextButton.icon( icon: const Icon(Icons.copy), label: Text(l10n.copyCode), onPressed: () async { final messenger = ScaffoldMessenger.of(context); await Clipboard.setData(ClipboardData(text: code)); messenger.showSnackBar( SnackBar(content: Text(l10n.codeCopied)), ); }, ), FilledButton( onPressed: () => Navigator.pop(dialogContext), child: const Text('OK'), ), ], ), ); } Future _join() async { final l10n = AppLocalizations.of(context); final code = _codeController.text.trim(); if (code.isEmpty) return; final confirmed = await showDialog( context: context, builder: (dialogContext) => AlertDialog( title: Text(l10n.joinWarningTitle), content: Text(l10n.joinWarningBody), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), child: Text(l10n.cancel), ), FilledButton( onPressed: () => Navigator.pop(dialogContext, true), child: Text(l10n.joinButton), ), ], ), ); if (confirmed != true || !mounted) return; setState(() => _joining = true); try { final name = await ref.read(householdRepositoryProvider).joinHousehold(code); if (!mounted) return; _codeController.clear(); ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar(SnackBar(content: Text(l10n.joinSuccess(name)))); } on FirebaseFunctionsException catch (e) { if (!mounted) return; final message = switch (e.code) { 'not-found' => l10n.joinErrorInvalid, 'failed-precondition' => l10n.joinErrorUsed, _ => l10n.authErrorGeneric, }; ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar(SnackBar(content: Text(message))); } catch (_) { if (!mounted) return; ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar(SnackBar(content: Text(l10n.authErrorGeneric))); } finally { if (mounted) setState(() => _joining = false); } } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final theme = Theme.of(context); final household = ref.watch(householdProvider).value; final myRole = ref.watch(myRoleProvider); final myUid = ref.watch(authStateProvider).value?.uid; return Scaffold( appBar: AppBar(title: Text(household?.name ?? l10n.householdTitle)), drawer: const AppDrawer(), body: ListView( padding: const EdgeInsets.all(16), children: [ Text(l10n.householdMembers, style: theme.textTheme.titleMedium), const SizedBox(height: 8), if (household != null) for (final member in household.members) ListTile( contentPadding: EdgeInsets.zero, leading: CircleAvatar( child: Icon(member.role == HouseholdRole.sitter ? Icons.volunteer_activism : Icons.person), ), title: Text( member.uid == myUid && member.email.isEmpty ? l10n.meLabel : member.email, ), subtitle: Text(member.role == HouseholdRole.sitter ? l10n.roleSitter : l10n.roleMember), trailing: member.uid == myUid ? Chip(label: Text(l10n.meLabel)) : null, ), if (myRole == HouseholdRole.member) ...[ const Divider(height: 32), Text(l10n.inviteTitle, style: theme.textTheme.titleMedium), const SizedBox(height: 4), Text( l10n.inviteExplanation, style: theme.textTheme.bodyMedium ?.copyWith(color: theme.colorScheme.onSurfaceVariant), ), const SizedBox(height: 12), FilledButton.tonalIcon( onPressed: () => _createInvite(HouseholdRole.member), icon: const Icon(Icons.person_add), label: Text(l10n.inviteMember), ), const SizedBox(height: 8), FilledButton.tonalIcon( onPressed: () => _createInvite(HouseholdRole.sitter), icon: const Icon(Icons.volunteer_activism), label: Text(l10n.inviteSitter), ), ], const Divider(height: 32), Text(l10n.joinTitle, style: theme.textTheme.titleMedium), const SizedBox(height: 12), TextField( controller: _codeController, decoration: InputDecoration( labelText: l10n.joinCodeLabel, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.key), ), textCapitalization: TextCapitalization.characters, autocorrect: false, ), const SizedBox(height: 12), FilledButton.icon( onPressed: _joining ? null : _join, icon: _joining ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.group_add), label: Text(l10n.joinButton), ), ], ), ); } }