import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../models/profile.model.dart'; import '../../../models/programmer_task.model.dart'; import '../../../providers/programmer_day_data_provider.dart'; import '../../../providers/programmer_projects_provider.dart'; import '../../../theme/app_status_colors.dart'; import '../../../utils/app_time.dart'; import '../../../widgets/m3_card.dart'; import '../../../widgets/status_pill.dart'; import '../../../widgets/tech_chip.dart'; import '../programmer_task_actions.dart'; import '../programmer_task_status_kind.dart'; /// Shared task card that reflects the current run state (running / paused / /// not started) sourced from [programmerRunStatesProvider]. /// /// Used by the task list screen (and any future surface) so the paused-task /// pill and action buttons are consistent everywhere. class ProgrammerTaskCard extends ConsumerWidget { const ProgrammerTaskCard({ super.key, required this.task, this.assignee, required this.isMine, this.readOnly = false, }); final ProgrammerTask task; final Profile? assignee; final bool isMine; final bool readOnly; @override Widget build(BuildContext context, WidgetRef ref) { final tt = Theme.of(context).textTheme; final cs = Theme.of(context).colorScheme; final runStates = ref.watch(programmerRunStatesProvider); final runInfo = runStates[task.id]; final isPaused = runInfo?.state == ProgrammerRunState.paused; final isRunning = runInfo?.state == ProgrammerRunState.running; final canStart = isMine && !readOnly && task.status == ProgrammerTaskStatus.queued; final canResume = isMine && !readOnly && isPaused; final canComplete = isMine && !readOnly && (isRunning || isPaused); final project = task.projectId == null ? null : ref.watch(programmerProjectByIdProvider(task.projectId!)); final pillKind = isPaused ? StatusKind.warning : programmerTaskStatusKind(task.status); final pillLabel = isPaused ? 'Paused' : ProgrammerTaskStatus.label(task.status); return M3Card.outlined( onTap: () => context.go('/programmer-tasks/${task.id}'), child: Padding( padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Text( task.title, style: tt.titleMedium?.copyWith(fontWeight: FontWeight.w600), maxLines: 2, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), StatusPill.kind(pillKind, label: pillLabel), ], ), const SizedBox(height: 10), Wrap( spacing: 8, runSpacing: 8, crossAxisAlignment: WrapCrossAlignment.center, children: [ TechChip(task.category, icon: Icons.category_outlined, dense: true), if (project != null) TechChip(project.name, icon: Icons.folder_outlined, dense: true), if (assignee != null && !isMine) Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.person_outline, size: 14, color: cs.onSurfaceVariant), const SizedBox(width: 4), Text( assignee!.fullName, style: tt.bodySmall ?.copyWith(color: cs.onSurfaceVariant), ), ], ), Text( AppTime.relative(task.createdAt), style: tt.bodySmall?.copyWith(color: cs.onSurfaceVariant), ), ], ), if (canStart || canResume) ...[ const SizedBox(height: 12), Align( alignment: Alignment.centerRight, child: FilledButton.tonalIcon( onPressed: () => startProgrammerTaskWithPausePrompt(context, ref, task), icon: const Icon(Icons.play_arrow_rounded, size: 18), label: Text(canResume ? 'Resume' : 'Start'), ), ), ], if (canComplete) ...[ const SizedBox(height: 8), Align( alignment: Alignment.centerRight, child: OutlinedButton.icon( onPressed: () => completeProgrammerTaskWithConfirm(context, ref, task), icon: const Icon(Icons.check_rounded, size: 18), label: const Text('Complete'), ), ), ], ], ), ), ); } }