import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/todo_item.dart'; import '../models/family_member.dart'; import '../services/todo_service.dart'; import '../services/family_service.dart'; class TodoListWidget extends StatelessWidget { const TodoListWidget({super.key}); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: Theme.of(context).cardTheme.color, borderRadius: BorderRadius.circular(16), ), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Today's Todos", style: Theme.of(context).textTheme.titleLarge?.copyWith( color: Colors.white, fontWeight: FontWeight.bold, ), ), Icon( Icons.check_circle_outline, color: Theme.of(context).colorScheme.secondary, ), ], ), const SizedBox(height: 12), Expanded( child: FutureBuilder>( future: Future.wait([ Provider.of( context, listen: false, ).fetchTodayTodos(), Provider.of( context, listen: false, ).fetchFamilyMembers(), ]), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return const Center( child: Text( 'Failed to load todos', style: TextStyle(color: Colors.white54), ), ); } if (!snapshot.hasData) { return const Center( child: Text( 'No todos today', style: TextStyle(color: Colors.white54), ), ); } final todos = snapshot.data![0] as List; final members = snapshot.data![1] as List; if (todos.isEmpty) { return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.thumb_up, color: Colors.white24, size: 32), SizedBox(height: 8), Text( 'All done for today!', style: TextStyle(color: Colors.white54), ), ], ), ); } return ListView.separated( itemCount: todos.length, separatorBuilder: (context, index) => const Divider(color: Colors.white10), itemBuilder: (context, index) { final todo = todos[index]; final member = members.firstWhere( (m) => m.id == todo.familyMemberId, orElse: () => const FamilyMember( id: '', name: 'Unknown', iconUrl: '', emoji: '👤', color: '#888888', order: 0, ), ); // Parse color Color memberColor; try { String cleanHex = member.color.replaceAll('#', '').replaceAll('0x', ''); if (cleanHex.length == 6) { cleanHex = 'FF$cleanHex'; } if (cleanHex.length == 8) { memberColor = Color(int.parse('0x$cleanHex')); } else { memberColor = Colors.grey; } } catch (_) { memberColor = Colors.grey; } return ListTile( contentPadding: EdgeInsets.zero, leading: CircleAvatar( backgroundColor: memberColor.withOpacity(0.2), backgroundImage: member.iconUrl.isNotEmpty ? NetworkImage(member.iconUrl) : null, child: member.iconUrl.isEmpty ? (member.name.isNotEmpty ? Text( member.name[0].toUpperCase(), style: TextStyle( color: memberColor, fontWeight: FontWeight.bold, fontSize: 20, ), ) : Icon( Icons.person, color: memberColor, )) : null, ), title: Text( todo.title, style: TextStyle( color: todo.completed ? Colors.white54 : Colors.white, decoration: todo.completed ? TextDecoration.lineThrough : null, decorationColor: Colors.white54, ), ), trailing: Checkbox( value: todo.completed, onChanged: (val) async { // Toggle completion final updated = TodoItem( id: todo.id, familyMemberId: todo.familyMemberId, title: todo.title, completed: val ?? false, dueDate: todo.dueDate, ); await Provider.of( context, listen: false, ).updateTodo(updated); // Force rebuild? In a real app we'd use a reactive state. // Here we rely on the parent or timer to refresh, or we could convert this to StatefulWidget. // For now, let's just let the next refresh cycle pick it up, or if the user interacts, maybe we should optimistic update? // Given it's a TV dashboard, interaction might be rare, but if it is interactive: (context as Element) .markNeedsBuild(); // HACK to refresh }, activeColor: Theme.of(context).colorScheme.secondary, checkColor: Colors.black, ), ); }, ); }, ), ), ], ), ); } }