import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../domain/team.dart'; import '../infrastructure/teams_repository.dart'; import 'widgets/team_card.dart'; /// Top-level Teams tab. Renders a responsive grid of team cards on wider /// viewports and a single-column list on mobile. class TeamsScreen extends ConsumerWidget { const TeamsScreen({super.key}); /// Width at which the layout switches from list to 2-column grid. static const double _gridBreakpoint = 640; @override Widget build(BuildContext context, WidgetRef ref) { final teamsAsync = ref.watch(teamsStreamProvider); return Scaffold( appBar: AppBar(title: const Text('Teams')), floatingActionButton: FloatingActionButton.extended( onPressed: () => context.go('/teams/new'), icon: const Icon(Icons.add), label: const Text('CREATE A TEAM'), ), body: teamsAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (error, _) => _ErrorState( message: error.toString(), onRetry: () => ref.invalidate(teamsStreamProvider), ), data: (teams) { if (teams.isEmpty) return const _EmptyState(); return LayoutBuilder( builder: (context, constraints) { final isWide = constraints.maxWidth >= _gridBreakpoint; return isWide ? _TeamsGrid(teams: teams, maxWidth: constraints.maxWidth) : _TeamsList(teams: teams); }, ); }, ), ); } } class _TeamsList extends StatelessWidget { const _TeamsList({required this.teams}); final List teams; @override Widget build(BuildContext context) { return ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), itemCount: teams.length, separatorBuilder: (_, _) => const SizedBox(height: 8), itemBuilder: (context, index) => TeamCard(team: teams[index]), ); } } class _TeamsGrid extends StatelessWidget { const _TeamsGrid({required this.teams, required this.maxWidth}); final List teams; final double maxWidth; @override Widget build(BuildContext context) { // Wider viewports get more columns: 2 up to ~1024, then 3. final crossAxisCount = maxWidth >= 1024 ? 3 : 2; // Slightly taller than wide so the top-scorer pill never crowds. const aspect = 1.55; return GridView.builder( padding: const EdgeInsets.all(16), itemCount: teams.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, crossAxisSpacing: 16, mainAxisSpacing: 16, childAspectRatio: aspect, ), itemBuilder: (context, index) => TeamCard(team: teams[index]), ); } } 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.groups_outlined, size: 64, color: theme.colorScheme.onSurfaceVariant, ), const SizedBox(height: 16), Text('No teams yet', style: theme.textTheme.titleMedium), const SizedBox(height: 8), Text( 'Teams will appear here once rosters are submitted for an event.', 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 teams', 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'), ), ], ), ), ); } }