Files

9.8 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
08-task-delete 02 execute 2
08-01
lib/features/tasks/presentation/task_providers.dart
lib/features/tasks/presentation/task_form_screen.dart
true
DEL-01
DEL-04
truths artifacts key_links
User sees a red delete button at the bottom of the task edit form
Tapping delete shows a confirmation dialog before any action
Confirming delete on a task with no completions removes it from the database
Confirming delete on a task with completions deactivates it (hidden from views)
After deletion the user is navigated back to the room task list
path provides contains
lib/features/tasks/presentation/task_form_screen.dart Delete button and confirmation dialog in edit mode taskDeleteConfirmTitle
path provides contains
lib/features/tasks/presentation/task_providers.dart Smart delete method using getCompletionCount softDeleteTask
from to via pattern
lib/features/tasks/presentation/task_form_screen.dart lib/features/tasks/presentation/task_providers.dart TaskActions.smartDeleteTask call from delete button callback smartDeleteTask
from to via pattern
lib/features/tasks/presentation/task_providers.dart lib/features/tasks/data/tasks_dao.dart getCompletionCount + conditional deleteTask or softDeleteTask getCompletionCount.*softDeleteTask|deleteTask
Add the delete button and confirmation dialog to the task edit form, with smart delete logic in the provider layer.

Purpose: Users can remove tasks they no longer need. The smart behavior (hard vs soft delete) is invisible to the user -- they just see "delete" with a confirmation.

Output: Working delete flow on the task edit form: red button -> confirmation dialog -> smart delete -> navigate back.

<execution_context> @/home/jlmak/.claude/get-shit-done/workflows/execute-plan.md @/home/jlmak/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/08-task-delete/08-CONTEXT.md @.planning/phases/08-task-delete/08-01-SUMMARY.md

From lib/features/tasks/presentation/task_providers.dart (existing TaskActions):

@riverpod
class TaskActions extends _$TaskActions {
  @override
  FutureOr<void> build() {}

  Future<int> createTask({...}) async { ... }
  Future<void> updateTask(Task task) async { ... }
  Future<void> deleteTask(int taskId) async { ... }  // calls DAO hard delete
  Future<void> completeTask(int taskId) async { ... }
}

From lib/features/tasks/data/tasks_dao.dart (after Plan 01):

class TasksDao {
  Future<void> deleteTask(int taskId);       // hard delete (cascade)
  Future<void> softDeleteTask(int taskId);   // sets isActive = false
  Future<int> getCompletionCount(int taskId); // count completions
}

From lib/features/tasks/presentation/task_form_screen.dart (edit mode section):

// History section (edit mode only) — delete button goes AFTER this
if (widget.isEditing) ...[
  const SizedBox(height: 24),
  const Divider(),
  ListTile(
    leading: const Icon(Icons.history),
    title: Text(l10n.taskHistoryTitle),
    trailing: const Icon(Icons.chevron_right),
    onTap: () => showTaskHistorySheet(
      context: context,
      taskId: widget.taskId!,
    ),
  ),
],

From lib/l10n/app_de.arb (existing delete l10n strings):

"taskDeleteConfirmTitle": "Aufgabe l\u00f6schen?",
"taskDeleteConfirmMessage": "Die Aufgabe wird unwiderruflich gel\u00f6scht.",
"taskDeleteConfirmAction": "L\u00f6schen"

Room delete dialog pattern (from lib/features/rooms/presentation/rooms_screen.dart:165-189):

showDialog(
  context: context,
  builder: (ctx) => AlertDialog(
    title: Text(l10n.roomDeleteConfirmTitle),
    content: Text(l10n.roomDeleteConfirmMessage),
    actions: [
      TextButton(
        onPressed: () => Navigator.pop(ctx),
        child: Text(l10n.cancel),
      ),
      FilledButton(
        style: FilledButton.styleFrom(
          backgroundColor: Theme.of(ctx).colorScheme.error,
        ),
        onPressed: () { ... },
        child: Text(l10n.roomDeleteConfirmAction),
      ),
    ],
  ),
);
Task 1: Add smartDeleteTask to TaskActions provider lib/features/tasks/presentation/task_providers.dart Add a `smartDeleteTask` method to the `TaskActions` class in task_providers.dart. This method checks the completion count and routes to hard delete or soft delete accordingly:
/// Smart delete: hard-deletes tasks with no completions, soft-deletes tasks with completions.
Future<void> smartDeleteTask(int taskId) async {
  final db = ref.read(appDatabaseProvider);
  final completionCount = await db.tasksDao.getCompletionCount(taskId);
  if (completionCount == 0) {
    await db.tasksDao.deleteTask(taskId);
  } else {
    await db.tasksDao.softDeleteTask(taskId);
  }
}

Keep the existing deleteTask method unchanged (it is still a valid hard delete for other uses like room cascade delete).

Run dart run build_runner build --delete-conflicting-outputs to regenerate the provider code. cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && dart analyze --fatal-infos lib/features/tasks/presentation/task_providers.dart - smartDeleteTask method exists on TaskActions - Method checks completion count and routes to hard or soft delete - dart analyze passes with zero issues

Task 2: Add delete button and confirmation dialog to TaskFormScreen lib/features/tasks/presentation/task_form_screen.dart 1. In the TaskFormScreen build method's ListView children, AFTER the history section (the existing `if (widget.isEditing) ...` block ending at line ~204), add the delete button section inside the same `if (widget.isEditing)` block:
if (widget.isEditing) ...[
  const SizedBox(height: 24),
  const Divider(),
  // History ListTile (existing)
  ListTile(
    leading: const Icon(Icons.history),
    title: Text(l10n.taskHistoryTitle),
    trailing: const Icon(Icons.chevron_right),
    onTap: () => showTaskHistorySheet(
      context: context,
      taskId: widget.taskId!,
    ),
  ),
  // DELETE BUTTON — new
  const Divider(),
  const SizedBox(height: 8),
  SizedBox(
    width: double.infinity,
    child: FilledButton.icon(
      style: FilledButton.styleFrom(
        backgroundColor: theme.colorScheme.error,
        foregroundColor: theme.colorScheme.onError,
      ),
      onPressed: _isLoading ? null : _onDelete,
      icon: const Icon(Icons.delete_outline),
      label: Text(l10n.taskDeleteConfirmAction),
    ),
  ),
],
  1. Add a _onDelete method to _TaskFormScreenState:
Future<void> _onDelete() async {
  final l10n = AppLocalizations.of(context);
  final confirmed = await showDialog<bool>(
    context: context,
    builder: (ctx) => AlertDialog(
      title: Text(l10n.taskDeleteConfirmTitle),
      content: Text(l10n.taskDeleteConfirmMessage),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(ctx, false),
          child: Text(l10n.cancel),
        ),
        FilledButton(
          style: FilledButton.styleFrom(
            backgroundColor: Theme.of(ctx).colorScheme.error,
          ),
          onPressed: () => Navigator.pop(ctx, true),
          child: Text(l10n.taskDeleteConfirmAction),
        ),
      ],
    ),
  );

  if (confirmed != true || !mounted) return;

  setState(() => _isLoading = true);
  try {
    await ref.read(taskActionsProvider.notifier).smartDeleteTask(widget.taskId!);
    if (mounted) {
      context.pop();
    }
  } finally {
    if (mounted) {
      setState(() => _isLoading = false);
    }
  }
}

Note: The l10n.cancel string should already exist from the room delete dialog. If not, use MaterialLocalizations.of(context).cancelButtonLabel.

  1. Verify cancel l10n key exists. If it does not exist in app_de.arb, check for the existing cancel button pattern in rooms_screen.dart and use the same approach. cd /home/jlmak/Projects/jlmak/HouseHoldKeaper && flutter test --reporter compact && dart analyze --fatal-infos
    • Red delete button visible at bottom of task edit form (below history, separated by divider)
    • Delete button only shows in edit mode (not create mode)
    • Tapping delete shows AlertDialog with title "Aufgabe loschen?" and error-colored confirm button
    • Canceling dialog does nothing
    • Confirming dialog calls smartDeleteTask and pops back to room task list
    • Button is disabled while loading (_isLoading)
    • All existing tests pass, dart analyze clean
- Task edit form shows red delete button below history section with divider separator - Delete button is NOT shown in create mode - Tapping delete shows confirmation dialog matching room delete dialog pattern - Confirming deletes/deactivates the task and navigates back - Canceling returns to the form without changes - All tests pass: `flutter test --reporter compact` - Code quality: `dart analyze --fatal-infos` reports zero issues

<success_criteria>

  • Complete delete flow works: open task -> scroll to bottom -> tap delete -> confirm -> back to room task list
  • Smart delete is invisible to user: tasks with completions are deactivated, tasks without are removed
  • Delete button follows Material 3 error color pattern
  • Confirmation dialog uses existing German l10n strings
  • All 137+ tests pass </success_criteria>
After completion, create `.planning/phases/08-task-delete/08-02-SUMMARY.md`