215 lines
6.1 KiB
Dart
215 lines
6.1 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
|
|
// Данные будильника
|
|
class AlarmData {
|
|
final String id;
|
|
final DateTime dateTime;
|
|
final bool isRepeating;
|
|
final String repeatPattern;
|
|
final List<int> repeatDays;
|
|
final bool isEnabled;
|
|
|
|
AlarmData({
|
|
required this.id,
|
|
required this.dateTime,
|
|
this.isRepeating = false,
|
|
this.repeatPattern = 'daily',
|
|
this.repeatDays = const [],
|
|
this.isEnabled = true,
|
|
});
|
|
|
|
factory AlarmData.fromMap(Map<String, dynamic> map) {
|
|
return AlarmData(
|
|
id: map['id'] ?? '',
|
|
dateTime: (map['dateTime'] as Timestamp).toDate(),
|
|
isRepeating: map['isRepeating'] ?? false,
|
|
repeatPattern: map['repeatPattern'] ?? 'daily',
|
|
repeatDays: List<int>.from(map['repeatDays'] ?? []),
|
|
isEnabled: map['isEnabled'] ?? true,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'id': id,
|
|
'dateTime': Timestamp.fromDate(dateTime),
|
|
'isRepeating': isRepeating,
|
|
'repeatPattern': repeatPattern,
|
|
'repeatDays': repeatDays,
|
|
'isEnabled': isEnabled,
|
|
};
|
|
}
|
|
}
|
|
|
|
enum TaskStatus {
|
|
todo,
|
|
inProgress,
|
|
review,
|
|
done,
|
|
archived,
|
|
}
|
|
|
|
enum TaskPriority {
|
|
low,
|
|
medium,
|
|
high,
|
|
urgent,
|
|
}
|
|
|
|
class TaskModel {
|
|
final String id;
|
|
final String title;
|
|
final String? description;
|
|
final String projectId;
|
|
final String? parentTaskId; // For mind-map hierarchy
|
|
final TaskStatus status;
|
|
final TaskPriority priority;
|
|
final String? assigneeId;
|
|
final String? creatorId;
|
|
final List<String> tags;
|
|
final DateTime? dueDate;
|
|
final DateTime? startDate;
|
|
final DateTime? completedDate;
|
|
final List<AlarmData> alarms; // Будильники для задачи
|
|
final int estimatedHours;
|
|
final int spentHours;
|
|
final Map<String, dynamic> aiMetadata; // AI-generated suggestions
|
|
final DateTime createdAt;
|
|
final DateTime updatedAt;
|
|
|
|
TaskModel({
|
|
required this.id,
|
|
required this.title,
|
|
this.description,
|
|
required this.projectId,
|
|
this.parentTaskId,
|
|
this.status = TaskStatus.todo,
|
|
this.priority = TaskPriority.medium,
|
|
this.assigneeId,
|
|
this.creatorId,
|
|
this.tags = const [],
|
|
this.dueDate,
|
|
this.startDate,
|
|
this.completedDate,
|
|
this.alarms = const [],
|
|
this.estimatedHours = 0,
|
|
this.spentHours = 0,
|
|
this.aiMetadata = const {},
|
|
required this.createdAt,
|
|
required this.updatedAt,
|
|
});
|
|
|
|
factory TaskModel.fromFirestore(DocumentSnapshot doc) {
|
|
final data = doc.data() as Map<String, dynamic>;
|
|
return TaskModel(
|
|
id: doc.id,
|
|
title: data['title'] ?? '',
|
|
description: data['description'],
|
|
projectId: data['projectId'] ?? '',
|
|
parentTaskId: data['parentTaskId'],
|
|
status: TaskStatus.values.firstWhere(
|
|
(e) => e.name == data['status'],
|
|
orElse: () => TaskStatus.todo,
|
|
),
|
|
priority: TaskPriority.values.firstWhere(
|
|
(e) => e.name == data['priority'],
|
|
orElse: () => TaskPriority.medium,
|
|
),
|
|
assigneeId: data['assigneeId'],
|
|
creatorId: data['creatorId'],
|
|
tags: List<String>.from(data['tags'] ?? []),
|
|
dueDate: data['dueDate'] != null
|
|
? (data['dueDate'] as Timestamp).toDate()
|
|
: null,
|
|
startDate: data['startDate'] != null
|
|
? (data['startDate'] as Timestamp).toDate()
|
|
: null,
|
|
completedDate: data['completedDate'] != null
|
|
? (data['completedDate'] as Timestamp).toDate()
|
|
: null,
|
|
alarms: (data['alarms'] as List<dynamic>?)
|
|
?.map((a) => AlarmData.fromMap(a as Map<String, dynamic>))
|
|
.toList() ??
|
|
[],
|
|
estimatedHours: data['estimatedHours'] ?? 0,
|
|
spentHours: data['spentHours'] ?? 0,
|
|
aiMetadata: data['aiMetadata'] ?? {},
|
|
createdAt: (data['createdAt'] as Timestamp).toDate(),
|
|
updatedAt: (data['updatedAt'] as Timestamp).toDate(),
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toFirestore() {
|
|
return {
|
|
'title': title,
|
|
'description': description,
|
|
'projectId': projectId,
|
|
'parentTaskId': parentTaskId,
|
|
'status': status.name,
|
|
'priority': priority.name,
|
|
'assigneeId': assigneeId,
|
|
'creatorId': creatorId,
|
|
'tags': tags,
|
|
'dueDate': dueDate != null ? Timestamp.fromDate(dueDate!) : null,
|
|
'startDate': startDate != null ? Timestamp.fromDate(startDate!) : null,
|
|
'completedDate':
|
|
completedDate != null ? Timestamp.fromDate(completedDate!) : null,
|
|
'alarms': alarms.map((a) => a.toMap()).toList(),
|
|
'estimatedHours': estimatedHours,
|
|
'spentHours': spentHours,
|
|
'aiMetadata': aiMetadata,
|
|
'createdAt': Timestamp.fromDate(createdAt),
|
|
'updatedAt': Timestamp.fromDate(updatedAt),
|
|
};
|
|
}
|
|
|
|
TaskModel copyWith({
|
|
String? id,
|
|
String? title,
|
|
String? description,
|
|
String? projectId,
|
|
String? parentTaskId,
|
|
TaskStatus? status,
|
|
TaskPriority? priority,
|
|
String? assigneeId,
|
|
String? creatorId,
|
|
List<String>? tags,
|
|
DateTime? dueDate,
|
|
DateTime? startDate,
|
|
DateTime? completedDate,
|
|
List<AlarmData>? alarms,
|
|
int? estimatedHours,
|
|
int? spentHours,
|
|
Map<String, dynamic>? aiMetadata,
|
|
DateTime? createdAt,
|
|
DateTime? updatedAt,
|
|
}) {
|
|
return TaskModel(
|
|
id: id ?? this.id,
|
|
title: title ?? this.title,
|
|
description: description ?? this.description,
|
|
projectId: projectId ?? this.projectId,
|
|
parentTaskId: parentTaskId ?? this.parentTaskId,
|
|
status: status ?? this.status,
|
|
priority: priority ?? this.priority,
|
|
assigneeId: assigneeId ?? this.assigneeId,
|
|
creatorId: creatorId ?? this.creatorId,
|
|
tags: tags ?? this.tags,
|
|
dueDate: dueDate ?? this.dueDate,
|
|
startDate: startDate ?? this.startDate,
|
|
completedDate: completedDate ?? this.completedDate,
|
|
alarms: alarms ?? this.alarms,
|
|
estimatedHours: estimatedHours ?? this.estimatedHours,
|
|
spentHours: spentHours ?? this.spentHours,
|
|
aiMetadata: aiMetadata ?? this.aiMetadata,
|
|
createdAt: createdAt ?? this.createdAt,
|
|
updatedAt: updatedAt ?? this.updatedAt,
|
|
);
|
|
}
|
|
|
|
bool get isOverdue {
|
|
if (dueDate == null) return false;
|
|
return DateTime.now().isAfter(dueDate!) && status != TaskStatus.done;
|
|
}
|
|
}
|