180 lines
6.8 KiB
Dart
180 lines
6.8 KiB
Dart
// Quiet per-task history counters.
|
|
//
|
|
// The app design calls for recovery/reporting features that can notice repeated
|
|
// pushes, backlog moves, burnout skips, and locked-hour leakage. This file keeps
|
|
// that history as immutable counters attached to each task.
|
|
|
|
/// Internal counters used for future filtering, reporting, and scheduling hints.
|
|
///
|
|
/// These counters answer "what has happened to this task over time?" without
|
|
/// changing the primary task state. They are intentionally quiet metadata: daily
|
|
/// task cards should not show all of this by default, but reports and filters can
|
|
/// use it to identify patterns such as tasks repeatedly pushed, skipped during
|
|
/// burnout, or completed inside locked hours.
|
|
///
|
|
/// Like [Task], this is immutable. Increment helpers return a new
|
|
/// [TaskStatistics] value so calling code can update a task through `copyWith`
|
|
/// while retaining predictable before/after behavior.
|
|
class TaskStatistics {
|
|
const TaskStatistics({
|
|
this.skippedDuringBurnoutCount = 0,
|
|
this.manuallyPushedCount = 0,
|
|
this.autoPushedCount = 0,
|
|
this.movedToBacklogCount = 0,
|
|
this.restoredFromBacklogCount = 0,
|
|
this.missedCount = 0,
|
|
this.cancelledCount = 0,
|
|
this.completedLateCount = 0,
|
|
this.completedDuringLockedHoursCount = 0,
|
|
this.completedDuringLockedHoursMinutes = 0,
|
|
this.completedAfterShieldCount = 0,
|
|
this.completedAfterPushCount = 0,
|
|
this.totalPushesBeforeCompletion = 0,
|
|
});
|
|
|
|
/// Number of times this task was skipped during Shield/recovery behavior.
|
|
final int skippedDuringBurnoutCount;
|
|
|
|
/// Number of times the user explicitly pushed this task.
|
|
final int manuallyPushedCount;
|
|
|
|
/// Number of times the scheduler moved this task to make room for something.
|
|
final int autoPushedCount;
|
|
|
|
/// Number of times this task was moved from schedule/today into backlog.
|
|
final int movedToBacklogCount;
|
|
|
|
/// Number of times this task came back from backlog into a planned slot.
|
|
final int restoredFromBacklogCount;
|
|
|
|
/// Number of times this task missed its intended timing.
|
|
final int missedCount;
|
|
|
|
/// Number of times this task was intentionally cancelled.
|
|
final int cancelledCount;
|
|
|
|
/// Number of times this task was completed after its scheduled window.
|
|
final int completedLateCount;
|
|
|
|
/// Number of completion events that overlapped locked hours.
|
|
final int completedDuringLockedHoursCount;
|
|
|
|
/// Total minutes completed while overlapping locked hours.
|
|
final int completedDuringLockedHoursMinutes;
|
|
|
|
/// Dormant V2-compatible counter for future Shield completion workflows.
|
|
final int completedAfterShieldCount;
|
|
|
|
/// Number of completions that happened after at least one push.
|
|
final int completedAfterPushCount;
|
|
|
|
/// Sum of push counts present when completion was recorded.
|
|
final int totalPushesBeforeCompletion;
|
|
|
|
/// Return a copy with selected counters changed.
|
|
///
|
|
/// Counters default to their current values when omitted, which keeps small
|
|
/// increment helpers concise and avoids direct mutation.
|
|
TaskStatistics copyWith({
|
|
int? skippedDuringBurnoutCount,
|
|
int? manuallyPushedCount,
|
|
int? autoPushedCount,
|
|
int? movedToBacklogCount,
|
|
int? restoredFromBacklogCount,
|
|
int? missedCount,
|
|
int? cancelledCount,
|
|
int? completedLateCount,
|
|
int? completedDuringLockedHoursCount,
|
|
int? completedDuringLockedHoursMinutes,
|
|
int? completedAfterShieldCount,
|
|
int? completedAfterPushCount,
|
|
int? totalPushesBeforeCompletion,
|
|
}) {
|
|
return TaskStatistics(
|
|
skippedDuringBurnoutCount:
|
|
skippedDuringBurnoutCount ?? this.skippedDuringBurnoutCount,
|
|
manuallyPushedCount: manuallyPushedCount ?? this.manuallyPushedCount,
|
|
autoPushedCount: autoPushedCount ?? this.autoPushedCount,
|
|
movedToBacklogCount: movedToBacklogCount ?? this.movedToBacklogCount,
|
|
restoredFromBacklogCount:
|
|
restoredFromBacklogCount ?? this.restoredFromBacklogCount,
|
|
missedCount: missedCount ?? this.missedCount,
|
|
cancelledCount: cancelledCount ?? this.cancelledCount,
|
|
completedLateCount: completedLateCount ?? this.completedLateCount,
|
|
completedDuringLockedHoursCount: completedDuringLockedHoursCount ??
|
|
this.completedDuringLockedHoursCount,
|
|
completedDuringLockedHoursMinutes: completedDuringLockedHoursMinutes ??
|
|
this.completedDuringLockedHoursMinutes,
|
|
completedAfterShieldCount:
|
|
completedAfterShieldCount ?? this.completedAfterShieldCount,
|
|
completedAfterPushCount:
|
|
completedAfterPushCount ?? this.completedAfterPushCount,
|
|
totalPushesBeforeCompletion:
|
|
totalPushesBeforeCompletion ?? this.totalPushesBeforeCompletion,
|
|
);
|
|
}
|
|
|
|
/// Record that the task was removed from active planning and stored for later.
|
|
TaskStatistics incrementMovedToBacklog() {
|
|
return copyWith(movedToBacklogCount: movedToBacklogCount + 1);
|
|
}
|
|
|
|
/// Record a recovery/Shield skip. This is distinct from manual cancellation.
|
|
TaskStatistics incrementSkippedDuringBurnout() {
|
|
return copyWith(skippedDuringBurnoutCount: skippedDuringBurnoutCount + 1);
|
|
}
|
|
|
|
/// Record an explicit user push action.
|
|
TaskStatistics incrementManualPush() {
|
|
return copyWith(manuallyPushedCount: manuallyPushedCount + 1);
|
|
}
|
|
|
|
/// Record scheduler-driven movement caused by another placement.
|
|
TaskStatistics incrementAutoPush() {
|
|
return copyWith(autoPushedCount: autoPushedCount + 1);
|
|
}
|
|
|
|
/// Record that a backlog item was scheduled again.
|
|
TaskStatistics incrementRestoredFromBacklog() {
|
|
return copyWith(restoredFromBacklogCount: restoredFromBacklogCount + 1);
|
|
}
|
|
|
|
/// Record a missed intended time or required task handling event.
|
|
TaskStatistics incrementMissed() {
|
|
return copyWith(missedCount: missedCount + 1);
|
|
}
|
|
|
|
/// Record that the task was deliberately cancelled.
|
|
TaskStatistics incrementCancelled() {
|
|
return copyWith(cancelledCount: cancelledCount + 1);
|
|
}
|
|
|
|
/// Record that the task was completed after its planned end.
|
|
TaskStatistics incrementCompletedLate() {
|
|
return copyWith(completedLateCount: completedLateCount + 1);
|
|
}
|
|
|
|
/// Record completion that overlapped locked time by [minutes].
|
|
///
|
|
/// Both count and minutes are tracked because reports may want either "how
|
|
/// often did this happen?" or "how much time leaked into locked blocks?"
|
|
TaskStatistics incrementCompletedDuringLockedHours(int minutes) {
|
|
return copyWith(
|
|
completedDuringLockedHoursCount: completedDuringLockedHoursCount + 1,
|
|
completedDuringLockedHoursMinutes:
|
|
completedDuringLockedHoursMinutes + minutes,
|
|
);
|
|
}
|
|
|
|
/// Record that completion happened after [pushCount] prior pushes.
|
|
TaskStatistics recordPushesBeforeCompletion(int pushCount) {
|
|
if (pushCount <= 0) {
|
|
return this;
|
|
}
|
|
|
|
return copyWith(
|
|
completedAfterPushCount: completedAfterPushCount + 1,
|
|
totalPushesBeforeCompletion: totalPushesBeforeCompletion + pushCount,
|
|
);
|
|
}
|
|
}
|