Add tick boxes to task rows
Tasks now carry a tick box rather than being read-only rows. Ticking strikes the title through and leaves the item in place, so a day still reads as a record of what was asked rather than only what is left. New in designs/Checkbox.dart: - TickBox the square box itself, animating between empty and filled - TickRow box + struck-through title + caller-supplied detail and trailing - addTaskAffordance the centred "Add new task" control beneath a day's list Applied to the home plan, the overdue queue and the goal task list. Each screen holds a set of optimistically ticked ids so the tick lands immediately and rolls back if the call fails; the set is reconciled whenever fresh data arrives. A tick completes the item outright, whatever its proof requirement. The proof flow is still reachable from the Complete button in the overdue queue, so tasks that need an artefact have a route that asks for one — but the tick itself no longer enforces it. Late completes stay visually distinct: the row keeps a Late pill and the warning accent, and the user is told the window had already closed. flutter analyze lib/ reports no errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mfu2gQLSFN21YRBcU2NrTt
This commit is contained in:
@@ -9,6 +9,7 @@ import '../../about/internal/application/NotificationType.dart';
|
||||
import '../../about/internal/application/ProofType.dart';
|
||||
import '../../about/internal/application/Standing.dart';
|
||||
import '../../about/internal/application/TextType.dart';
|
||||
import '../../designs/Checkbox.dart';
|
||||
import '../../designs/Component.dart';
|
||||
import '../../designs/Responsive.dart';
|
||||
import '../../designs/Shell.dart';
|
||||
@@ -36,6 +37,9 @@ class OverdueQueueState extends State<OverdueQueue>
|
||||
|
||||
bool _changed = false;
|
||||
|
||||
/// Ticked locally, awaiting the server. Rolls back on failure.
|
||||
final Set<String> _ticked = <String>{};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<ViewOverdueQueue>.reactive(
|
||||
@@ -66,6 +70,27 @@ class OverdueQueueState extends State<OverdueQueue>
|
||||
Navigator.pop(context, _changed);
|
||||
}
|
||||
|
||||
/// The tick completes the item outright. The Complete button still runs the
|
||||
/// proof flow, so a task that needs an artefact has a route that asks for
|
||||
/// one — the tick is the quick path, not the only one.
|
||||
void _onTick(Commitment item) {
|
||||
if (item.id == null || _ticked.contains(item.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_ticked.add(item.id!);
|
||||
});
|
||||
|
||||
_model?.complete(
|
||||
item,
|
||||
CompletionRequest(
|
||||
commitmentId: item.id ?? "",
|
||||
proofType: item.proofType.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onComplete(Commitment item) {
|
||||
// Honour proof settles immediately; everything else has to produce its
|
||||
// artefact before the completion is accepted.
|
||||
@@ -526,31 +551,19 @@ class OverdueQueueState extends State<OverdueQueue>
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
text(item.title, 17, TextType.Medium,
|
||||
color: colorPrimaryDark, maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis),
|
||||
const SizedBox(height: 8),
|
||||
text(formatWindow(item), 11, TextType.Regular,
|
||||
color: colorGrey2),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
pill(
|
||||
classLabel(item.commitmentClass),
|
||||
accent,
|
||||
classBackground(item.commitmentClass),
|
||||
textSize: 9,
|
||||
),
|
||||
],
|
||||
TickRow(
|
||||
checked: _ticked.contains(item.id),
|
||||
title: item.title,
|
||||
accent: accent,
|
||||
onTick: () => _onTick(item),
|
||||
detail: text(formatWindow(item), 11, TextType.Regular,
|
||||
color: colorGrey2),
|
||||
trailing: pill(
|
||||
classLabel(item.commitmentClass),
|
||||
accent,
|
||||
classBackground(item.commitmentClass),
|
||||
textSize: 9,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
@@ -625,6 +638,7 @@ class OverdueQueueState extends State<OverdueQueue>
|
||||
@override
|
||||
void onQueueLoaded(List<Commitment> queue, Standing standing, double debt) {
|
||||
setState(() {
|
||||
_ticked.removeWhere((id) => queue.every((item) => item.id != id));
|
||||
_queue = queue;
|
||||
_standing = standing;
|
||||
_debt = debt;
|
||||
|
||||
Reference in New Issue
Block a user