import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../../../core/theme/app_colors.dart'; import '../../../../core/widgets/gentle_nudge_card.dart'; import '../../../../core/widgets/streak_ring.dart'; import '../../../../core/widgets/task_card.dart'; import '../../../../features/auth/presentation/bloc/auth_bloc.dart'; import '../bloc/task_list_bloc.dart'; /// Home screen — the task dashboard. /// /// Layout: /// - AppBar greeting. /// - Focus Mode prominent card at the top. /// - Today's tasks list (limited to preferredTaskLoad). /// - Streak summary cards (horizontal scroll). /// - Bottom nav: Tasks, Streaks, Time, Settings. class TaskDashboardScreen extends StatefulWidget { const TaskDashboardScreen({super.key}); @override State createState() => _TaskDashboardScreenState(); } class _TaskDashboardScreenState extends State { late final TaskListBloc _taskListBloc; int _currentNavIndex = 0; @override void initState() { super.initState(); _taskListBloc = TaskListBloc()..add(const TasksLoaded()); } @override void dispose() { _taskListBloc.close(); super.dispose(); } String _greeting(AuthState authState) { final name = authState is AuthAuthenticated ? authState.user.displayName : 'Friend'; return 'Hey $name! What shall we tackle?'; } void _onNavTap(int index) { switch (index) { case 0: break; // already here case 1: context.go('/streaks'); case 2: context.go('/time'); case 3: context.go('/settings'); } setState(() => _currentNavIndex = index); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return BlocProvider.value( value: _taskListBloc, child: Scaffold( // ── AppBar ─────────────────────────────────────────────── appBar: AppBar( title: BlocBuilder( builder: (context, state) => Text( _greeting(state), style: theme.textTheme.titleMedium, ), ), actions: [ IconButton( icon: const Icon(Icons.notifications_none_rounded), onPressed: () {}, tooltip: 'Notifications', ), ], ), // ── Body ───────────────────────────────────────────────── body: RefreshIndicator( onRefresh: () async => _taskListBloc.add(const TasksLoaded()), child: ListView( padding: const EdgeInsets.only(bottom: 100), children: [ // Focus Mode card _FocusModeCard(onTap: () => context.go('/focus')), // Gentle nudge (shown conditionally) GentleNudgeCard( previousStreak: 7, onStartSmall: () => context.go('/focus'), onDismiss: () {}, ), // ── Streak rings (horizontal scroll) ─────────────── Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text('Your Streaks', style: theme.textTheme.titleMedium), ), SizedBox( height: 120, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 12), children: const [ Padding( padding: EdgeInsets.symmetric(horizontal: 6), child: StreakRing( currentCount: 12, graceDaysRemaining: 2, totalGraceDays: 2, label: 'Daily tasks', ), ), Padding( padding: EdgeInsets.symmetric(horizontal: 6), child: StreakRing( currentCount: 5, graceDaysRemaining: 1, totalGraceDays: 2, label: 'Exercise', ), ), Padding( padding: EdgeInsets.symmetric(horizontal: 6), child: StreakRing( currentCount: 0, isFrozen: true, label: 'Frozen', ), ), ], ), ), // ── Today's tasks ────────────────────────────────── Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text('Today\'s Tasks', style: theme.textTheme.titleMedium), ), BlocBuilder( builder: (context, state) { if (state is TaskListLoading) { return const Center( child: Padding( padding: EdgeInsets.all(32), child: CircularProgressIndicator(), ), ); } if (state is TaskListError) { return _EmptyState( icon: Icons.cloud_off_rounded, title: 'Could not load tasks', subtitle: state.message, ); } if (state is TaskListLoaded) { final tasks = state.tasks; if (tasks.isEmpty) { return const _EmptyState( icon: Icons.check_circle_outline_rounded, title: 'All clear!', subtitle: 'No tasks for today. Enjoy the calm.', ); } return Column( children: tasks .take(5) .map((t) => TaskCard( task: t, onTap: () => context.go('/task/${t.id}'), onComplete: () => _taskListBloc.add(TaskCompleted(t.id)), onSkip: () => _taskListBloc.add(TaskSkipped(t.id)), )) .toList(), ); } return const SizedBox.shrink(); }, ), ], ), ), // ── FAB: create task ───────────────────────────────────── floatingActionButton: FloatingActionButton.extended( onPressed: () => context.go('/task-create'), icon: const Icon(Icons.add_rounded), label: const Text('New Task'), ), // ── Bottom nav ─────────────────────────────────────────── bottomNavigationBar: BottomNavigationBar( currentIndex: _currentNavIndex, onTap: _onNavTap, items: const [ BottomNavigationBarItem(icon: Icon(Icons.task_alt_rounded), label: 'Tasks'), BottomNavigationBarItem(icon: Icon(Icons.local_fire_department_rounded), label: 'Streaks'), BottomNavigationBarItem(icon: Icon(Icons.timer_outlined), label: 'Time'), BottomNavigationBarItem(icon: Icon(Icons.settings_rounded), label: 'Settings'), ], ), ), ); } } // ── Focus Mode Card ──────────────────────────────────────────────── class _FocusModeCard extends StatelessWidget { final VoidCallback onTap; const _FocusModeCard({required this.onTap}); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Card( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), color: AppColors.primary, child: InkWell( borderRadius: BorderRadius.circular(16), onTap: onTap, child: Padding( padding: const EdgeInsets.all(20), child: Row( children: [ const Icon(Icons.self_improvement_rounded, size: 40, color: Colors.white), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Focus Mode', style: theme.textTheme.titleLarge?.copyWith( color: Colors.white, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 4), Text( 'Just do the next thing. One at a time.', style: theme.textTheme.bodyMedium?.copyWith( color: Colors.white.withAlpha(200), ), ), ], ), ), const Icon(Icons.arrow_forward_rounded, color: Colors.white), ], ), ), ), ); } } // ── Empty state ──────────────────────────────────────────────────── class _EmptyState extends StatelessWidget { final IconData icon; final String title; final String subtitle; const _EmptyState({ required this.icon, required this.title, required this.subtitle, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Padding( padding: const EdgeInsets.all(32), child: Column( children: [ Icon(icon, size: 56, color: AppColors.skipped), const SizedBox(height: 12), Text(title, style: theme.textTheme.titleMedium), const SizedBox(height: 4), Text(subtitle, style: theme.textTheme.bodyMedium, textAlign: TextAlign.center), ], ), ); } }