Files
GroundedHelper/frontend/lib/Grounded/see/goal/ViewGoalDetail.dart
alvocool c88887b639 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
2026-07-31 21:51:15 +03:00

56 lines
1.7 KiB
Dart

import '../../about/external/data/Commitment.dart';
import '../../about/external/data/Goal.dart';
import '../../about/external/initial/CompletionRequest.dart';
import '../../about/external/initial/IdRequest.dart';
import '../../utils/ObjectConvertors.dart';
import '../parent/ParentViewModel.dart';
import 'ConnectGoalDetail.dart';
class ViewGoalDetail extends ParentViewModel {
ConnectGoalDetail connection;
ViewGoalDetail(super.context, this.connection);
void loadTasks(Goal goal) async {
if (!await hasNetwork(() => loadTasks(goal))) return;
showLoading("Loading ${goal.title}");
try {
final response =
await getDataManager().getGoalTasks(IdRequest(id: goal.id ?? ""));
closeLoading();
connection.onGoalLoaded(goal, getCommitmentList(response.data));
} catch (e) {
handleError(e, () => loadTasks(goal), () => dismissError(), "Retry");
}
}
/// Completes a task straight from the goal list.
void tick(Commitment task) async {
if (!await hasNetwork(() => tick(task))) return;
try {
await getDataManager().completeCommitmentEntry(CompletionRequest(
commitmentId: task.id ?? "",
proofType: task.proofType.name,
));
connection.onTaskTicked(task, task.wouldBeLate);
} catch (e) {
connection.onTickFailed(task);
handleError(e, () => tick(task), () => dismissError(), "Retry");
}
}
/// Stashes the task as the active one before the runner opens, so the
/// ongoing notification and any relaunch land back on the right thing.
void startTask(Commitment task) async {
await getDataManager().setActiveCommitment(task);
connection.onTaskReady(task);
}
}