import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:timetrack/features/projects/domain/project.dart'; import 'package:timetrack/features/projects/domain/projects_provider.dart'; import 'package:timetrack/features/projects/presentation/widgets/project_form_sheet.dart'; import 'package:timetrack/features/projects/presentation/widgets/project_list_tile.dart'; class ProjectsScreen extends ConsumerStatefulWidget { const ProjectsScreen({super.key}); @override ConsumerState createState() => _ProjectsScreenState(); } class _ProjectsScreenState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); } @override void dispose() { _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Projects'), actions: [ IconButton( icon: const Icon(Icons.add), tooltip: 'New project', onPressed: () => ProjectFormSheet.show(context), ), ], bottom: TabBar( controller: _tabController, tabs: const [ Tab(text: 'Active'), Tab(text: 'Archived'), ], ), ), body: TabBarView( controller: _tabController, children: const [ _ProjectList(archived: false), _ProjectList(archived: true), ], ), ); } } class _ProjectList extends ConsumerWidget { const _ProjectList({required this.archived}); final bool archived; @override Widget build(BuildContext context, WidgetRef ref) { final projectsAsync = archived ? ref.watch(allProjectsProvider) : ref.watch(activeProjectsProvider); return projectsAsync.when( data: (allProjects) { final projects = archived ? allProjects.where((p) => p.archivedAt != null).toList() : allProjects; if (projects.isEmpty) { return Center( key: Key(archived ? 'archived_empty' : 'active_empty'), child: Text( archived ? 'No archived projects.' : 'No projects yet.', ), ); } return ListView.builder( itemCount: projects.length, itemBuilder: (context, index) { final project = projects[index]; return ProjectListTile( key: Key('project_tile_${project.id}'), project: project, totalDuration: Duration.zero, // TODO: wire up from reports repo onTap: () => ProjectFormSheet.show(context, existing: project), onArchive: () => _toggleArchive(context, ref, project), onDelete: () => _confirmDelete(context, ref, project), ); }, ); }, loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('Error: $e')), ); } void _toggleArchive(BuildContext context, WidgetRef ref, Project project) { final notifier = ref.read(projectsNotifierProvider.notifier); if (project.archivedAt == null) { notifier.archive(project.id); } else { notifier.unarchive(project.id); } } Future _confirmDelete( BuildContext context, WidgetRef ref, Project project, ) async { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Delete project?'), content: Text( 'Delete "${project.name}"? This cannot be undone.\n\n' 'Projects with existing entries cannot be deleted.', ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('Cancel'), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), style: FilledButton.styleFrom( backgroundColor: Theme.of(ctx).colorScheme.error, ), child: const Text('Delete'), ), ], ), ); if (confirmed == true) { try { await ref.read(projectsNotifierProvider.notifier).delete(project.id); } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Cannot delete — project has time entries.'), ), ); } } } } }