refactor(programmer): shared task card driven by run states

Extract _TaskCard from the list screen into ProgrammerTaskCard, a
shared ConsumerWidget that reads programmerRunStatesProvider so the
paused-task pill and Start/Resume/Complete buttons are consistent
across any surface that embeds it.

Move the _complete body verbatim to completeProgrammerTaskWithConfirm
in programmer_task_actions.dart; the detail screen's _ActionBar now
calls the shared function.

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-09-27 21:40:07 +08:00
parent cdfeb954fd
commit f8c3422715
5 changed files with 245 additions and 142 deletions
@@ -325,7 +325,8 @@ class _ActionBar extends ConsumerWidget {
),
if (isRunning || isPaused)
OutlinedButton.icon(
onPressed: () => _complete(context, ref, task),
onPressed: () =>
completeProgrammerTaskWithConfirm(context, ref, task),
icon: const Icon(Icons.check_rounded),
label: const Text('Complete'),
),
@@ -340,35 +341,6 @@ class _ActionBar extends ConsumerWidget {
}
Future<void> _complete(
BuildContext context,
WidgetRef ref,
ProgrammerTask task,
) async {
final messenger = ScaffoldMessenger.of(context);
final ok = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
semanticLabel: 'Complete task',
title: const Text('Complete task?'),
content: Text('Mark "${task.title}" as completed?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Complete'),
),
],
),
);
if (ok != true) return;
await ref.read(programmerTasksControllerProvider).completeTask(taskId: task.id);
messenger.showSnackBar(const SnackBar(content: Text('Task completed')));
}
Future<void> _cancel(
BuildContext context,
WidgetRef ref,