Files
social-app/apps/lib/features/calendar/data/models/schedule_item_model.dart
T

290 lines
7.6 KiB
Dart
Raw Normal View History

import 'package:flutter/material.dart';
enum ScheduleSourceType { manual, imported, agentGenerated }
enum ScheduleStatus { active, completed, canceled, archived }
class ScheduleItemModel {
final String id;
final String title;
final String? description;
final DateTime startAt;
final DateTime? endAt;
final String timezone;
final ScheduleMetadata? metadata;
final ScheduleSourceType sourceType;
final ScheduleStatus status;
final DateTime createdAt;
final DateTime updatedAt;
ScheduleItemModel({
required this.id,
required this.title,
this.description,
required this.startAt,
this.endAt,
this.timezone = 'Asia/Shanghai',
this.metadata,
this.sourceType = ScheduleSourceType.manual,
this.status = ScheduleStatus.active,
DateTime? createdAt,
DateTime? updatedAt,
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
ScheduleItemModel copyWith({
String? id,
String? title,
String? description,
DateTime? startAt,
DateTime? endAt,
String? timezone,
ScheduleMetadata? metadata,
ScheduleSourceType? sourceType,
ScheduleStatus? status,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return ScheduleItemModel(
id: id ?? this.id,
title: title ?? this.title,
description: description ?? this.description,
startAt: startAt ?? this.startAt,
endAt: endAt ?? this.endAt,
timezone: timezone ?? this.timezone,
metadata: metadata ?? this.metadata,
sourceType: sourceType ?? this.sourceType,
status: status ?? this.status,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
factory ScheduleItemModel.fromJson(Map<String, dynamic> json) {
return ScheduleItemModel(
id: json['id'] as String,
title: json['title'] as String,
description: json['description'] as String?,
startAt: DateTime.parse(json['start_at'] as String).toLocal(),
endAt: json['end_at'] != null
? DateTime.parse(json['end_at'] as String).toLocal()
: null,
timezone: (json['timezone'] as String?) ?? 'UTC',
metadata: json['metadata'] is Map<String, dynamic>
? ScheduleMetadata.fromJson(json['metadata'] as Map<String, dynamic>)
: null,
sourceType: _sourceTypeFromApi(json['source_type'] as String?),
status: _statusFromApi(json['status'] as String?),
createdAt: json['created_at'] != null
? DateTime.parse(json['created_at'] as String).toLocal()
: DateTime.now(),
updatedAt: json['updated_at'] != null
? DateTime.parse(json['updated_at'] as String).toLocal()
: DateTime.now(),
);
}
Map<String, dynamic> toCreateJson() {
return {
'title': title,
'description': description,
'start_at': startAt.toUtc().toIso8601String(),
'end_at': endAt?.toUtc().toIso8601String(),
'timezone': timezone,
'metadata': metadata?.toJson(),
};
}
Map<String, dynamic> toUpdateJson() {
return {
'title': title,
'description': description,
'start_at': startAt.toUtc().toIso8601String(),
'end_at': endAt?.toUtc().toIso8601String(),
'timezone': timezone,
'metadata': metadata?.toJson(),
'status': _statusToApi(status),
};
}
}
class ScheduleMetadata {
final String? color;
final String? location;
final String? notes;
final int? reminderMinutes;
final List<Attachment> attachments;
final int version;
final Map<String, dynamic> raw;
ScheduleMetadata({
this.color,
this.location,
this.notes,
this.reminderMinutes,
List<Attachment>? attachments,
this.version = 1,
Map<String, dynamic>? raw,
}) : attachments = attachments ?? const [],
raw = raw ?? const {};
ScheduleMetadata copyWith({
String? color,
String? location,
String? notes,
int? reminderMinutes,
List<Attachment>? attachments,
int? version,
Map<String, dynamic>? raw,
}) {
return ScheduleMetadata(
color: color ?? this.color,
location: location ?? this.location,
notes: notes ?? this.notes,
reminderMinutes: reminderMinutes ?? this.reminderMinutes,
attachments: attachments ?? this.attachments,
version: version ?? this.version,
raw: raw ?? this.raw,
);
}
factory ScheduleMetadata.fromJson(Map<String, dynamic> json) {
final rawAttachments = json['attachments'];
final attachments = rawAttachments is List
? rawAttachments
.whereType<Map<String, dynamic>>()
.map(Attachment.fromJson)
.toList()
: <Attachment>[];
return ScheduleMetadata(
color: json['color'] as String?,
location: json['location'] as String?,
notes: json['notes'] as String?,
reminderMinutes: json['reminder_minutes'] as int?,
attachments: attachments,
version: (json['version'] as int?) ?? 1,
raw: Map<String, dynamic>.from(json),
);
}
Map<String, dynamic> toJson() {
return {
'color': color,
'location': location,
'notes': notes,
'reminder_minutes': reminderMinutes,
'attachments': attachments.map((item) => item.toJson()).toList(),
'version': version,
};
}
}
class Attachment {
final String name;
final List<String> visibleTo;
final String? url;
final String? note;
final String? content;
final String type;
Attachment({
required this.name,
this.visibleTo = const [],
this.url,
this.note,
this.content,
this.type = 'document',
});
Attachment copyWith({
String? name,
List<String>? visibleTo,
String? url,
String? note,
String? content,
String? type,
}) {
return Attachment(
name: name ?? this.name,
visibleTo: visibleTo ?? this.visibleTo,
url: url ?? this.url,
note: note ?? this.note,
content: content ?? this.content,
type: type ?? this.type,
);
}
factory Attachment.fromJson(Map<String, dynamic> json) {
final rawVisibleTo = json['visible_to'];
final visibleTo = rawVisibleTo is List
? rawVisibleTo.map((item) => item.toString()).toList()
: <String>[];
return Attachment(
name: (json['name'] as String?) ?? '',
visibleTo: visibleTo,
url: json['url'] as String?,
note: json['note'] as String?,
content: json['content'] as String?,
type: (json['type'] as String?) ?? 'document',
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'visible_to': visibleTo,
'url': url,
'note': note,
'content': content,
'type': type,
};
}
}
ScheduleSourceType _sourceTypeFromApi(String? raw) {
switch (raw) {
case 'imported':
return ScheduleSourceType.imported;
case 'agent_generated':
return ScheduleSourceType.agentGenerated;
case 'manual':
default:
return ScheduleSourceType.manual;
}
}
ScheduleStatus _statusFromApi(String? raw) {
switch (raw) {
case 'completed':
return ScheduleStatus.completed;
case 'canceled':
return ScheduleStatus.canceled;
case 'archived':
return ScheduleStatus.archived;
case 'active':
default:
return ScheduleStatus.active;
}
}
String _statusToApi(ScheduleStatus status) {
switch (status) {
case ScheduleStatus.active:
return 'active';
case ScheduleStatus.completed:
return 'completed';
case ScheduleStatus.canceled:
return 'canceled';
case ScheduleStatus.archived:
return 'archived';
}
}
const defaultColors = [
Color(0xFF3B82F6),
Color(0xFF8B5CF6),
Color(0xFF10B981),
Color(0xFFF59E0B),
Color(0xFFEF4444),
];