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

340 lines
9.4 KiB
Dart

enum ScheduleSourceType { manual, imported, agentGenerated }
enum ScheduleStatus { active, archived }
class Subscriber {
final String userId;
final String? username;
final String? avatarUrl;
final String? phone;
final int permission;
final String status;
final DateTime subscribedAt;
static const int permissionView = 1;
static const int permissionInvite = 2;
static const int permissionEdit = 4;
static const int permissionDelete = 8;
static const int permissionOwner = 15;
bool get canEdit => (permission & permissionEdit) != 0;
bool get canInvite => (permission & permissionInvite) != 0;
bool get canDelete => (permission & permissionDelete) != 0;
bool get canView => (permission & permissionView) != 0;
Subscriber({
required this.userId,
this.username,
this.avatarUrl,
this.phone,
required this.permission,
required this.status,
required this.subscribedAt,
});
factory Subscriber.fromJson(Map<String, dynamic> json) {
return Subscriber(
userId: json['user_id'] as String,
username: json['username'] as String?,
avatarUrl: json['avatar_url'] as String?,
phone: json['phone'] as String?,
permission: json['permission'] as int,
status: json['status'] as String,
subscribedAt: DateTime.parse(json['subscribed_at'] as String).toLocal(),
);
}
}
class ScheduleItemModel {
final String id;
final String ownerId;
final int permission;
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;
final List<Subscriber> subscribers;
static const int permissionView = 1;
static const int permissionInvite = 2;
static const int permissionEdit = 4;
static const int permissionDelete = 8;
static const int permissionOwner = 15;
bool get canEdit => (permission & permissionEdit) != 0;
bool get canInvite => (permission & permissionInvite) != 0;
bool get canDelete => (permission & permissionDelete) != 0;
bool get isOwner => (permission & permissionOwner) != 0;
ScheduleItemModel({
required this.id,
required this.ownerId,
this.permission = 1,
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,
this.subscribers = const [],
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
ScheduleItemModel copyWith({
String? id,
String? ownerId,
int? permission,
String? title,
String? description,
DateTime? startAt,
DateTime? endAt,
String? timezone,
ScheduleMetadata? metadata,
ScheduleSourceType? sourceType,
ScheduleStatus? status,
DateTime? createdAt,
DateTime? updatedAt,
List<Subscriber>? subscribers,
}) {
return ScheduleItemModel(
id: id ?? this.id,
ownerId: ownerId ?? this.ownerId,
permission: permission ?? this.permission,
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,
subscribers: subscribers ?? this.subscribers,
);
}
factory ScheduleItemModel.fromJson(Map<String, dynamic> json) {
final subscribersList = json['subscribers'] as List<dynamic>?;
final subscribers =
subscribersList
?.map((s) => Subscriber.fromJson(s as Map<String, dynamic>))
.toList() ??
[];
return ScheduleItemModel(
id: json['id'] as String,
ownerId: json['owner_id'] as String,
permission: json['permission'] as int,
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,
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: DateTime.parse(json['created_at'] as String).toLocal(),
updatedAt: DateTime.parse(json['updated_at'] as String).toLocal(),
subscribers: subscribers,
);
}
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'] as List<dynamic>;
final attachments = rawAttachments
.map((item) => Attachment.fromJson(item as Map<String, dynamic>))
.toList(growable: false);
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,
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'] as List<dynamic>;
final visibleTo = rawVisibleTo.map((item) => item.toString()).toList();
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,
);
}
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':
return ScheduleSourceType.manual;
default:
throw StateError('Unsupported schedule source type: $raw');
}
}
ScheduleStatus _statusFromApi(String raw) {
switch (raw) {
case 'archived':
return ScheduleStatus.archived;
case 'active':
return ScheduleStatus.active;
default:
throw StateError('Unsupported schedule status: $raw');
}
}
String _statusToApi(ScheduleStatus status) {
switch (status) {
case ScheduleStatus.active:
return 'active';
case ScheduleStatus.archived:
return 'archived';
}
}