326 lines
7.9 KiB
Dart
326 lines
7.9 KiB
Dart
import 'task_statistics.dart';
|
|
|
|
/// Scheduling behavior category.
|
|
enum TaskType {
|
|
/// Movable planned work.
|
|
flexible,
|
|
|
|
/// Required visible block that should not be moved automatically.
|
|
inflexible,
|
|
|
|
/// Required visible task that remains actionable if missed.
|
|
critical,
|
|
|
|
/// Hidden scheduling constraint, not a task card.
|
|
locked,
|
|
|
|
/// Unplanned completed/logged task.
|
|
surprise,
|
|
|
|
/// Intentional rest time.
|
|
freeSlot,
|
|
}
|
|
|
|
/// Current lifecycle state of a task.
|
|
enum TaskStatus {
|
|
/// Scheduled or queued work that has not started.
|
|
planned,
|
|
|
|
/// Work currently in progress.
|
|
active,
|
|
|
|
/// Work finished by the user.
|
|
completed,
|
|
|
|
/// Work that was not completed in its intended time.
|
|
missed,
|
|
|
|
/// Work intentionally removed from the plan.
|
|
cancelled,
|
|
|
|
/// Work intentionally dismissed because it no longer applies.
|
|
noLongerRelevant,
|
|
|
|
/// Unscheduled work kept for later planning.
|
|
backlog,
|
|
}
|
|
|
|
/// User-facing importance level.
|
|
enum PriorityLevel {
|
|
/// Lowest priority.
|
|
veryLow,
|
|
|
|
/// Low priority.
|
|
low,
|
|
|
|
/// Default middle priority.
|
|
medium,
|
|
|
|
/// High priority.
|
|
high,
|
|
|
|
/// Highest priority.
|
|
veryHigh,
|
|
}
|
|
|
|
/// Expected reward or payoff from completing a task.
|
|
enum RewardLevel {
|
|
/// No reward level has been captured; this is not equivalent to low reward.
|
|
notSet,
|
|
|
|
/// Very low expected reward.
|
|
veryLow,
|
|
|
|
/// Low expected reward.
|
|
low,
|
|
|
|
/// Medium expected reward.
|
|
medium,
|
|
|
|
/// High expected reward.
|
|
high,
|
|
|
|
/// Very high expected reward.
|
|
veryHigh,
|
|
}
|
|
|
|
/// Expected effort or activation difficulty for a task.
|
|
enum DifficultyLevel {
|
|
/// No difficulty has been captured yet.
|
|
notSet,
|
|
|
|
/// Very easy to start or complete.
|
|
veryEasy,
|
|
|
|
/// Easy to start or complete.
|
|
easy,
|
|
|
|
/// Medium effort.
|
|
medium,
|
|
|
|
/// Hard to start or complete.
|
|
hard,
|
|
|
|
/// Very hard to start or complete.
|
|
veryHard,
|
|
}
|
|
|
|
/// Reminder intensity preference.
|
|
enum ReminderProfile {
|
|
/// No reminder nudges.
|
|
silent,
|
|
|
|
/// Low-friction reminder nudges.
|
|
gentle,
|
|
|
|
/// Repeated reminder nudges.
|
|
persistent,
|
|
|
|
/// Strong reminder behavior for required items.
|
|
strict,
|
|
}
|
|
|
|
/// Lightweight backlog-only metadata.
|
|
enum BacklogTag {
|
|
/// Task is intentionally saved as a someday/wishlist item.
|
|
wishlist,
|
|
}
|
|
|
|
/// Starter task model for the scheduling core.
|
|
///
|
|
/// This is a public placeholder API for early V1 chunks. Keep behavior changes
|
|
/// explicit and covered by tests as the model becomes more complete.
|
|
class Task {
|
|
const Task({
|
|
required this.id,
|
|
required this.title,
|
|
required this.projectId,
|
|
required this.type,
|
|
required this.status,
|
|
required this.createdAt,
|
|
required this.updatedAt,
|
|
this.priority,
|
|
this.reward = RewardLevel.notSet,
|
|
this.difficulty = DifficultyLevel.notSet,
|
|
this.durationMinutes,
|
|
this.scheduledStart,
|
|
this.scheduledEnd,
|
|
this.parentTaskId,
|
|
this.backlogTags = const <BacklogTag>{},
|
|
this.stats = const TaskStatistics(),
|
|
});
|
|
|
|
/// Create a minimal captured task without requiring planning details.
|
|
factory Task.quickCapture({
|
|
required String id,
|
|
required String title,
|
|
required DateTime createdAt,
|
|
String projectId = 'inbox',
|
|
TaskType type = TaskType.flexible,
|
|
TaskStatus status = TaskStatus.backlog,
|
|
PriorityLevel priority = PriorityLevel.medium,
|
|
RewardLevel reward = RewardLevel.notSet,
|
|
DifficultyLevel difficulty = DifficultyLevel.notSet,
|
|
Set<BacklogTag> backlogTags = const <BacklogTag>{},
|
|
DateTime? updatedAt,
|
|
}) {
|
|
if (title.trim().isEmpty) {
|
|
throw ArgumentError.value(title, 'title', 'Title is required.');
|
|
}
|
|
|
|
return Task(
|
|
id: id,
|
|
title: title.trim(),
|
|
projectId: projectId,
|
|
type: type,
|
|
status: status,
|
|
priority: priority,
|
|
reward: reward,
|
|
difficulty: difficulty,
|
|
createdAt: createdAt,
|
|
updatedAt: updatedAt ?? createdAt,
|
|
backlogTags: backlogTags,
|
|
);
|
|
}
|
|
|
|
final String id;
|
|
final String title;
|
|
final String projectId;
|
|
final TaskType type;
|
|
final TaskStatus status;
|
|
final PriorityLevel? priority;
|
|
final RewardLevel reward;
|
|
final DifficultyLevel difficulty;
|
|
final int? durationMinutes;
|
|
final DateTime? scheduledStart;
|
|
final DateTime? scheduledEnd;
|
|
final String? parentTaskId;
|
|
final Set<BacklogTag> backlogTags;
|
|
final DateTime createdAt;
|
|
final DateTime updatedAt;
|
|
final TaskStatistics stats;
|
|
|
|
bool get isFlexible => type == TaskType.flexible;
|
|
bool get isRequiredVisible =>
|
|
type == TaskType.critical || type == TaskType.inflexible;
|
|
bool get isLocked => type == TaskType.locked;
|
|
bool get isBacklog => status == TaskStatus.backlog;
|
|
|
|
Task copyWith({
|
|
String? id,
|
|
String? title,
|
|
String? projectId,
|
|
TaskType? type,
|
|
TaskStatus? status,
|
|
PriorityLevel? priority,
|
|
RewardLevel? reward,
|
|
DifficultyLevel? difficulty,
|
|
int? durationMinutes,
|
|
DateTime? scheduledStart,
|
|
DateTime? scheduledEnd,
|
|
String? parentTaskId,
|
|
Set<BacklogTag>? backlogTags,
|
|
DateTime? createdAt,
|
|
DateTime? updatedAt,
|
|
TaskStatistics? stats,
|
|
bool clearSchedule = false,
|
|
}) {
|
|
return Task(
|
|
id: id ?? this.id,
|
|
title: title ?? this.title,
|
|
projectId: projectId ?? this.projectId,
|
|
type: type ?? this.type,
|
|
status: status ?? this.status,
|
|
priority: priority ?? this.priority,
|
|
reward: reward ?? this.reward,
|
|
difficulty: difficulty ?? this.difficulty,
|
|
durationMinutes: durationMinutes ?? this.durationMinutes,
|
|
scheduledStart:
|
|
clearSchedule ? null : (scheduledStart ?? this.scheduledStart),
|
|
scheduledEnd: clearSchedule ? null : (scheduledEnd ?? this.scheduledEnd),
|
|
parentTaskId: parentTaskId ?? this.parentTaskId,
|
|
backlogTags: backlogTags ?? this.backlogTags,
|
|
createdAt: createdAt ?? this.createdAt,
|
|
updatedAt: updatedAt ?? this.updatedAt,
|
|
stats: stats ?? this.stats,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Starter project defaults used when creating or scheduling tasks.
|
|
class ProjectProfile {
|
|
const ProjectProfile({
|
|
required this.id,
|
|
required this.name,
|
|
required this.colorKey,
|
|
this.defaultPriority = PriorityLevel.medium,
|
|
this.defaultReward = RewardLevel.notSet,
|
|
this.defaultDifficulty = DifficultyLevel.notSet,
|
|
this.defaultReminderProfile = ReminderProfile.gentle,
|
|
this.defaultDurationMinutes,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final String colorKey;
|
|
final PriorityLevel defaultPriority;
|
|
final RewardLevel defaultReward;
|
|
final DifficultyLevel defaultDifficulty;
|
|
final ReminderProfile defaultReminderProfile;
|
|
final int? defaultDurationMinutes;
|
|
|
|
/// Create a task using project defaults while allowing explicit overrides.
|
|
Task createTask({
|
|
required String id,
|
|
required String title,
|
|
required DateTime createdAt,
|
|
TaskType type = TaskType.flexible,
|
|
TaskStatus status = TaskStatus.backlog,
|
|
PriorityLevel? priority,
|
|
RewardLevel? reward,
|
|
DifficultyLevel? difficulty,
|
|
int? durationMinutes,
|
|
DateTime? scheduledStart,
|
|
DateTime? scheduledEnd,
|
|
String? parentTaskId,
|
|
Set<BacklogTag> backlogTags = const <BacklogTag>{},
|
|
DateTime? updatedAt,
|
|
}) {
|
|
return Task(
|
|
id: id,
|
|
title: title,
|
|
projectId: this.id,
|
|
type: type,
|
|
status: status,
|
|
priority: priority ?? defaultPriority,
|
|
reward: reward ?? defaultReward,
|
|
difficulty: difficulty ?? defaultDifficulty,
|
|
durationMinutes: durationMinutes ?? defaultDurationMinutes,
|
|
scheduledStart: scheduledStart,
|
|
scheduledEnd: scheduledEnd,
|
|
parentTaskId: parentTaskId,
|
|
backlogTags: backlogTags,
|
|
createdAt: createdAt,
|
|
updatedAt: updatedAt ?? createdAt,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Starter time range value used by scheduling helpers.
|
|
class TimeInterval {
|
|
const TimeInterval({
|
|
required this.start,
|
|
required this.end,
|
|
this.label,
|
|
});
|
|
|
|
final DateTime start;
|
|
final DateTime end;
|
|
final String? label;
|
|
|
|
Duration get duration => end.difference(start);
|
|
|
|
bool overlaps(TimeInterval other) {
|
|
return start.isBefore(other.end) && end.isAfter(other.start);
|
|
}
|
|
}
|