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
@@ -4,6 +4,40 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/programmer_task.model.dart';
import '../../providers/programmer_tasks_provider.dart';
/// Confirms with the user and completes [task]. Body moved verbatim from the
/// detail screen's `_complete` so it can be called from both the card and the
/// detail action bar.
Future<void> completeProgrammerTaskWithConfirm(
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')));
}
/// Starts (or resumes) [task] for the current user, enforcing the single-active
/// task discipline: if the user already has a *running* task, they are prompted
/// to pause it first. This is the headline "proper time management" behavior and