All checks were successful
Build and Release to F-Droid / build-and-deploy (push) Successful in 10m30s
- Covers empty states, celebration state, and scheduled/overdue task rendering - Verifies proper checkbox behavior for future tasks - Tests AppBar for sort dropdown, edit/delete actions, and calendar strip - Adds necessary test helpers and overrides for room-specific tasks
110 lines
3.4 KiB
Dart
110 lines
3.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:household_keeper/core/database/database.dart';
|
|
import 'package:household_keeper/features/tasks/domain/frequency.dart';
|
|
import 'package:household_keeper/features/tasks/domain/relative_date.dart';
|
|
import 'package:household_keeper/features/tasks/presentation/task_providers.dart';
|
|
|
|
/// Warm coral/terracotta color for overdue due date text.
|
|
const _overdueColor = Color(0xFFE07A5F);
|
|
|
|
/// A single task row with leading checkbox, name, relative due date,
|
|
/// and frequency label.
|
|
///
|
|
/// Per user decisions:
|
|
/// - Checkbox marks task done immediately (optimistic UI, no undo)
|
|
/// - Row tap opens edit form
|
|
/// - No swipe gesture
|
|
/// - No effort indicator or description preview on list view
|
|
/// - Overdue: due date text turns warm coral, rest stays normal
|
|
class TaskRow extends ConsumerWidget {
|
|
const TaskRow({
|
|
super.key,
|
|
required this.task,
|
|
this.onDelete,
|
|
});
|
|
|
|
final Task task;
|
|
final VoidCallback? onDelete;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final theme = Theme.of(context);
|
|
final now = DateTime.now();
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
|
|
// Check if task is overdue (due date is before today)
|
|
final dueDate = DateTime(
|
|
task.nextDueDate.year,
|
|
task.nextDueDate.month,
|
|
task.nextDueDate.day,
|
|
);
|
|
final isOverdue = dueDate.isBefore(today);
|
|
final isFuture = dueDate.isAfter(today);
|
|
|
|
// Format relative due date in German
|
|
final relativeDateText = formatRelativeDate(task.nextDueDate, now);
|
|
|
|
// Build frequency label
|
|
final freq = FrequencyInterval(
|
|
intervalType: task.intervalType,
|
|
days: task.intervalDays,
|
|
);
|
|
final frequencyText = freq.label();
|
|
|
|
return ListTile(
|
|
leading: Checkbox(
|
|
value: false, // Always unchecked -- completion is immediate + reschedule
|
|
onChanged: isFuture
|
|
? null // Future tasks cannot be completed yet
|
|
: (_) {
|
|
// Mark done immediately (optimistic UI, no undo per user decision)
|
|
ref.read(taskActionsProvider.notifier).completeTask(task.id);
|
|
},
|
|
),
|
|
title: Text(
|
|
task.name,
|
|
style: theme.textTheme.titleMedium,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
subtitle: Row(
|
|
children: [
|
|
Text(
|
|
relativeDateText,
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
color: isOverdue ? _overdueColor : theme.colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
|
child: Text(
|
|
'\u00b7', // middle dot separator
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
color: theme.colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
),
|
|
Flexible(
|
|
child: Text(
|
|
frequencyText,
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
color: theme.colorScheme.onSurfaceVariant,
|
|
),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
onTap: () {
|
|
// Tap row opens edit form
|
|
context.go('/rooms/${task.roomId}/tasks/${task.id}');
|
|
},
|
|
onLongPress: onDelete,
|
|
);
|
|
}
|
|
}
|