Files
tasq/lib/screens/programmer_tasks/programmer_task_actions.dart
T
redz1029 627645056b Add Programmer Tasks module (work-log + time tracking)
Separate feature for the `programmer` role to record dev work by category,
distinct from the IT help-desk `tasks` feature. Modeled on the IT Service
Requests pattern (Brick offline-first model -> Riverpod stream/controller ->
list/detail screens); seed of a future Project Management workflow.

- programmer_tasks + programmer_task_activity_logs (category enum, RLS,
  realtime) via supabase migration
- single assignee, self-logged or lead-assigned; assign/reassign logged
- pause-on-switch: starting a task while another runs prompts to pause the
  running one, keeping one active task per user for accurate time attribution
- worked-duration math shared with help-desk tasks via a generic core in
  task_duration.dart (existing callers unchanged)
- list distinguishes running vs paused with a per-task Resume shortcut
- accessible dialog labels; route /programmer-tasks + nav gated to admin/programmer
- unit/widget tests: controller lifecycle, duration math, pause-switch dialog

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-09-27 01:13:33 +08:00

64 lines
2.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../models/programmer_task.model.dart';
import '../../providers/programmer_tasks_provider.dart';
/// 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
/// is shared by the list and detail screens.
///
/// Returns true if the task was started/resumed, false if the user cancelled.
Future<bool> startProgrammerTaskWithPausePrompt(
BuildContext context,
WidgetRef ref,
ProgrammerTask task,
) async {
final controller = ref.read(programmerTasksControllerProvider);
final messenger = ScaffoldMessenger.of(context);
final running = await controller.findRunningTaskForCurrentUser();
if (running != null && running.id != task.id) {
if (!context.mounted) return false;
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
semanticLabel: 'Pause current task',
title: const Text('Pause current task?'),
content: Text(
"You're currently working on \"${running.title}\". "
'Pause it and start "${task.title}"?',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Pause & Start'),
),
],
),
);
if (confirmed != true) return false;
await controller.pauseTask(taskId: running.id);
}
try {
if (task.status == ProgrammerTaskStatus.queued) {
await controller.startTask(taskId: task.id);
} else if (task.status == ProgrammerTaskStatus.inProgress) {
await controller.resumeTask(taskId: task.id);
}
messenger.showSnackBar(
SnackBar(content: Text('Started "${task.title}"')),
);
return true;
} catch (e) {
messenger.showSnackBar(SnackBar(content: Text('Could not start task: $e')));
return false;
}
}