import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; import '../domain/bracket.dart'; import '../infrastructure/brackets_repository.dart'; import 'widgets/bracket_tree_widget.dart'; /// Top-level Brackets tab. /// /// Routing behavior: /// * No brackets → empty state. /// * Exactly one bracket → render its tree inline (the common case for the /// MVP, where each event has a single main draw). /// * Multiple brackets → list view, tap to drill into `/brackets/:id`. class BracketsScreen extends ConsumerWidget { const BracketsScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final bracketsAsync = ref.watch(bracketsStreamProvider); return Scaffold( appBar: AppBar(title: const Text('Brackets')), body: bracketsAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => _ErrorState( message: error.toString(), onRetry: () => ref.invalidate(bracketsStreamProvider), ), data: (brackets) { if (brackets.isEmpty) { return const _EmptyState(); } if (brackets.length == 1) { return _SingleBracketView(bracket: brackets.first); } return _BracketsList(brackets: brackets); }, ), ); } } class _SingleBracketView extends StatelessWidget { const _SingleBracketView({required this.bracket}); final Bracket bracket; @override Widget build(BuildContext context) { final theme = Theme.of(context); final scheme = theme.colorScheme; return Column( children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 12, 16, 8), child: Row( children: [ Icon(Icons.emoji_events, color: scheme.primary), const SizedBox(width: 8), Expanded( child: Text( bracket.name, style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w700, ), ), ), ], ), ), Expanded( child: Center(child: BracketTreeWidget(bracket: bracket)), ), Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), decoration: BoxDecoration( color: scheme.surfaceContainerHighest, border: Border(top: BorderSide(color: scheme.outlineVariant)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.swap_horiz, size: 18, color: scheme.onSurfaceVariant, ), const SizedBox(width: 6), Text( 'Scroll horizontally to see all rounds', style: theme.textTheme.bodySmall?.copyWith( color: scheme.onSurfaceVariant, ), ), ], ), ), ], ); } } class _BracketsList extends StatelessWidget { const _BracketsList({required this.brackets}); final List brackets; @override Widget build(BuildContext context) { final theme = Theme.of(context); final scheme = theme.colorScheme; final dateFormat = DateFormat('MMM d, y'); return ListView.separated( padding: const EdgeInsets.symmetric(vertical: 8), itemCount: brackets.length, separatorBuilder: (_, _) => const SizedBox(height: 4), itemBuilder: (context, index) { final bracket = brackets[index]; final totalMatches = bracket.rounds.fold(0, (sum, r) => sum + r.matches.length); return Card( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), clipBehavior: Clip.antiAlias, child: InkWell( onTap: () => context.go('/brackets/${bracket.id}'), child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ CircleAvatar( backgroundColor: scheme.primaryContainer, foregroundColor: scheme.onPrimaryContainer, child: const Icon(Icons.emoji_events), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( bracket.name, style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w700, ), ), const SizedBox(height: 4), Text( '${bracket.rounds.length} rounds · ' '$totalMatches matches · ' 'Created ${dateFormat.format(bracket.createdAt)}', style: theme.textTheme.bodySmall?.copyWith( color: scheme.onSurfaceVariant, ), ), ], ), ), Icon(Icons.chevron_right, color: scheme.onSurfaceVariant), ], ), ), ), ); }, ); } } class _EmptyState extends StatelessWidget { const _EmptyState(); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.emoji_events_outlined, size: 64, color: theme.colorScheme.onSurfaceVariant, ), const SizedBox(height: 16), Text( 'No brackets yet', style: theme.textTheme.titleMedium, ), const SizedBox(height: 8), Text( 'Tournament brackets will appear here once an event reaches ' 'its draw stage.', textAlign: TextAlign.center, style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), ), ); } } class _ErrorState extends StatelessWidget { const _ErrorState({required this.message, required this.onRetry}); final String message; final VoidCallback onRetry; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Center( child: Padding( padding: const EdgeInsets.all(32), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.error_outline, size: 64, color: theme.colorScheme.error), const SizedBox(height: 16), Text( 'Could not load brackets', style: theme.textTheme.titleMedium, ), const SizedBox(height: 8), Text( message, textAlign: TextAlign.center, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 16), FilledButton.tonalIcon( onPressed: onRetry, icon: const Icon(Icons.refresh), label: const Text('Try again'), ), ], ), ), ); } }