import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:habo/habits/habits_manager.dart'; import 'package:habo/habits/habit.dart'; import 'package:habo/model/habit_data.dart'; import 'package:habo/habits/calendar_column.dart'; import 'package:habo/settings/settings_manager.dart'; import 'package:habo/navigation/app_state_manager.dart'; import 'package:habo/constants.dart'; import 'package:reorderables/reorderables.dart'; class HabitsScreen extends StatefulWidget { const HabitsScreen({super.key}); @override State createState() => _HabitsScreenState(); } class _HabitsScreenState extends State { @override Widget build(BuildContext context) { final habitsManager = context.watch(); final settings = context.watch(); final appState = context.read(); final activeHabits = habitsManager.activeHabits; return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: AppBar( title: Row( mainAxisSize: MainAxisSize.min, children: [ Text( 'Habo', style: TextStyle( color: HaboColors.primary, fontWeight: FontWeight.bold, ), ), const SizedBox(width: 8), Icon(Icons.check_circle, color: HaboColors.primary, size: 20), ], ), actions: [ IconButton( icon: const Icon(Icons.bar_chart), tooltip: 'Statistics', onPressed: () => appState.goStatistics(true), ), IconButton( icon: const Icon(Icons.settings), tooltip: 'Settings', onPressed: () => appState.goSettings(true), ), ], backgroundColor: Theme.of(context).appBarTheme.backgroundColor, ), body: activeHabits.isEmpty ? _buildEmptyState(context) : _buildHabitList(context, activeHabits), floatingActionButton: FloatingActionButton( backgroundColor: HaboColors.primary, child: const Icon(Icons.add, color: Colors.white), onPressed: () => appState.goCreateHabit(true), ), ); } Widget _buildEmptyState(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( 'assets/images/emptyList.svg', width: 200, height: 200, errorBuilder: (_, __, ___) => Icon( Icons.track_changes, size: 120, color: Colors.grey.shade300, ), ), const SizedBox(height: 24), Text( 'Empty list', style: Theme.of(context).textTheme.headlineSmall?.copyWith( color: Colors.grey.shade600, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 8), Text( 'Create your first habit.', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Colors.grey.shade500, ), ), const SizedBox(height: 32), ElevatedButton.icon( onPressed: () => context.read().goCreateHabit(true), icon: const Icon(Icons.add), label: const Text('Create your first habit'), style: ElevatedButton.styleFrom( backgroundColor: HaboColors.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), ), ), ], ), ); } Widget _buildHabitList(BuildContext context, List habits) { return Column( children: [ Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), child: Row( children: [ Text( 'Habits:', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(width: 8), Text( '${habits.length}', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: HaboColors.primary, fontWeight: FontWeight.bold, ), ), ], ), ), Expanded( child: ReorderableColumn( crossAxisAlignment: CrossAxisAlignment.start, children: habits .map((habit) => Padding( key: ValueKey(habit.habitData.id), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), child: HabitCard(habit: habit), )) .toList(), onReorder: (oldIndex, newIndex) { context.read().reorderList(oldIndex, newIndex); }, ), ), ], ); } } class HabitCard extends StatelessWidget { final Habit habit; const HabitCard({super.key, required this.habit}); @override Widget build(BuildContext context) { final data = habit.habitData; return Card( elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title row Row( children: [ Icon( data.archived ? Icons.archive : Icons.check_circle, color: data.archived ? Colors.grey : HaboColors.primary, size: 22, ), const SizedBox(width: 8), Expanded( child: Text( data.title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), // Streak badge if (data.streakVisible) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: HaboColors.primary, borderRadius: BorderRadius.circular(12), ), child: Text( '🔥 ${data.streak} days', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, ), ), ), if (data.orangeStreak) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: HaboColors.orange, borderRadius: BorderRadius.circular(12), ), child: Text( '⚠️ ${data.streak} days', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, ), ), ), ], ), const SizedBox(height: 8), // Mini calendar - last 14 days _buildMiniCalendar(context), const SizedBox(height: 8), // Info row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( data.twoDayRule ? '📏 Two Day Rule ON' : '', style: TextStyle( fontSize: 11, color: Colors.grey.shade500, ), ), if (data.habitType == HabitType.numeric) Text( '📊 ${data.targetValue} ${data.unit}', style: TextStyle( fontSize: 11, color: Colors.blue.shade600, ), ), ], ), ], ), ), ); } Widget _buildMiniCalendar(BuildContext context) { final today = DateTime.now(); final dots = []; for (int i = 13; i >= 0; i--) { final date = DateTime(today.year, today.month, today.day - i); final event = data.events[date]; Color dotColor = Colors.grey.shade300; String label = _shortDay(date); if (event != null) { final dayType = event[0] is DayType ? event[0] as DayType : DayType.values[event[0] as int]; switch (dayType) { case DayType.check: dotColor = HaboColors.primary; break; case DayType.fail: dotColor = HaboColors.red; break; case DayType.skip: dotColor = HaboColors.skip; break; case DayType.progress: dotColor = HaboColors.progress; break; case DayType.clear: break; } } // Check if today final isToday = i == 0; dots.add( Column( mainAxisSize: MainAxisSize.min, children: [ Text( label, style: TextStyle( fontSize: 9, color: isToday ? HaboColors.primary : Colors.grey.shade500, fontWeight: isToday ? FontWeight.bold : FontWeight.normal, ), ), const SizedBox(height: 2), Container( width: 18, height: 18, decoration: BoxDecoration( color: dotColor, shape: BoxShape.circle, border: isToday ? Border.all(color: HaboColors.primary, width: 2) : null, ), ), ], ), ); } return Wrap( spacing: 6, runSpacing: 2, children: dots, ); } String _shortDay(DateTime date) { const days = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']; return days[date.weekday % 7]; } // Need access to habit data HabitData get data => habit.habitData; }