import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import '../../models/project_model.dart'; import '../../models/task_log_model.dart'; import '../../services/project_service.dart'; import '../../services/task_log_service.dart'; import '../project_detail_screen.dart'; import '../project_form_screen.dart'; class ProjectsTab extends StatelessWidget { const ProjectsTab({super.key}); @override Widget build(BuildContext context) { final service = context.read(); return Scaffold( backgroundColor: const Color(0xFFF8FAFC), body: StreamBuilder>( stream: service.getProjects(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } final projects = snapshot.data ?? []; if (projects.isEmpty) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.folder_open_rounded, size: 100, color: Colors.grey.shade200), const SizedBox(height: 16), Text("No projects assigned yet.", style: TextStyle(color: Colors.grey.shade500, fontSize: 13)), const SizedBox(height: 24), ElevatedButton( onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (_) => const ProjectFormScreen()) ), style: ElevatedButton.styleFrom(minimumSize: const Size(200, 50)), child: const Text("CREATE FIRST PROJECT"), ), ], ), ); } return CustomScrollView( slivers: [ const SliverPadding( padding: EdgeInsets.fromLTRB(20, 20, 20, 10), sliver: SliverToBoxAdapter( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Workspace", style: TextStyle(fontSize: 14, color: Color(0xFF64748B), fontWeight: FontWeight.w500), ), Text( "Projects", style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Color(0xFF1E293B)), ), ], ), ), ), SliverPadding( padding: const EdgeInsets.all(20), sliver: SliverList( delegate: SliverChildBuilderDelegate( (context, index) => _ProjectCard(p: projects[index]), childCount: projects.length, ), ), ), ], ); }, ), floatingActionButton: FloatingActionButton.extended( heroTag: "projects_fab", backgroundColor: const Color(0xFF6366F1), onPressed: () => Navigator.push( context, MaterialPageRoute(builder: (_) => const ProjectFormScreen()) ), label: const Text("NEW PROJECT", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)), icon: const Icon(Icons.add_rounded, color: Colors.white), ), ); } } class _ProjectCard extends StatelessWidget { final ProjectModel p; const _ProjectCard({required this.p}); @override Widget build(BuildContext context) { final taskService = context.watch(); return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), border: Border.all(color: Colors.grey.shade100), boxShadow: [ BoxShadow( color: Colors.indigo.withOpacity(0.02), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: InkWell( onTap: () => Navigator.push( context, MaterialPageRoute(builder: (_) => ProjectDetailScreen(project: p)) ), borderRadius: BorderRadius.circular(24), child: Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: const Color(0xFF6366F1).withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: const Icon(Icons.folder_copy_rounded, color: Color(0xFF6366F1), size: 24), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( p.name, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Color(0xFF1E293B)), ), Text( "Created ${DateFormat('MMM yyyy').format(p.createdAt)}", style: TextStyle(color: Colors.grey.shade500, fontSize: 11), ), ], ), ), const Icon(Icons.chevron_right_rounded, color: Color(0xFF94A3B8)), ], ), const SizedBox(height: 16), Text( p.description, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle(color: Color(0xFF475569), fontSize: 13, height: 1.5), ), const SizedBox(height: 16), if (p.flavors.isNotEmpty) ...[ Wrap( spacing: 6, runSpacing: 6, children: p.flavors.map((flavor) => Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: const Color(0xFFF1F5F9), borderRadius: BorderRadius.circular(8), ), child: Text( flavor, style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Color(0xFF64748B)), ), )).toList(), ), const SizedBox(height: 20), ], FutureBuilder( future: taskService.getLatestLogForProject(p.id), builder: (context, snapshot) { if (snapshot.hasError) { return const Text( "Index Error. Click project for link.", style: TextStyle(fontSize: 10, color: Colors.red, fontWeight: FontWeight.bold) ); } final latestLog = snapshot.data; if (latestLog == null) { return const Text( "No activity recorded yet.", style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8), fontStyle: FontStyle.italic) ); } return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFF8FAFC), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ const Icon(Icons.auto_awesome_rounded, size: 14, color: Colors.amber), const SizedBox(width: 8), Expanded( child: Text( "Latest: ${latestLog.userName} on ${DateFormat('MM/dd').format(latestLog.date)}", style: const TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: Color(0xFF334155)), ), ), Text( latestLog.moduleName, style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), ), ], ), ); }, ), ], ), ), ), ); } }