/// 일정 모델 library; /// 멤버 정보 class ScheduleMember { final int id; final String name; ScheduleMember({required this.id, required this.name}); factory ScheduleMember.fromJson(Map json) { return ScheduleMember( id: json['id'] as int, name: json['name'] as String, ); } } /// 관련 일정 (콘서트 회차 등) class RelatedDate { final int id; final String date; final String? time; RelatedDate({required this.id, required this.date, this.time}); factory RelatedDate.fromJson(Map json) { return RelatedDate( id: json['id'] as int, date: json['date'] as String, time: json['time'] as String?, ); } } /// 일정 상세 모델 class ScheduleDetail { final int id; final String title; final String date; final String? time; final int? categoryId; final String? categoryName; final String? categoryColor; final List members; // YouTube 관련 final String? channelName; final String? videoId; final String? videoType; final String? videoUrl; final String? bannerUrl; // X 관련 final String? postId; final String? username; final String? content; final List imageUrls; final String? postUrl; ScheduleDetail({ required this.id, required this.title, required this.date, this.time, this.categoryId, this.categoryName, this.categoryColor, this.members = const [], this.channelName, this.videoId, this.videoType, this.videoUrl, this.bannerUrl, this.postId, this.username, this.content, this.imageUrls = const [], this.postUrl, }); factory ScheduleDetail.fromJson(Map json) { // category 중첩 객체 파싱 final category = json['category'] as Map?; return ScheduleDetail( id: json['id'] as int, title: json['title'] as String, date: json['date'] as String, time: json['time'] as String?, categoryId: category?['id'] as int?, categoryName: category?['name'] as String?, categoryColor: category?['color'] as String?, members: (json['members'] as List?) ?.map((m) => ScheduleMember.fromJson(m)) .toList() ?? [], channelName: json['channelName'] as String?, videoId: json['videoId'] as String?, videoType: json['videoType'] as String?, videoUrl: json['videoUrl'] as String?, bannerUrl: json['bannerUrl'] as String?, postId: json['postId'] as String?, username: json['username'] as String?, content: json['content'] as String?, imageUrls: (json['imageUrls'] as List?)?.cast() ?? [], postUrl: json['postUrl'] as String?, ); } /// 시간 포맷 (HH:mm) String? get formattedTime { if (time == null) return null; return time!.length >= 5 ? time!.substring(0, 5) : time; } } class Schedule { /// ID (일반 일정: int, 생일/기념일: String) final dynamic id; final String title; final String date; final String? time; final int? categoryId; final String? categoryName; final String? categoryColor; final List members; final String? sourceName; final String? sourceUrl; // 특별 일정 필드 final bool isBirthday; final bool isDebut; final bool isAnniversary; final String? memberImage; final int? anniversaryYear; Schedule({ required this.id, required this.title, required this.date, this.time, this.categoryId, this.categoryName, this.categoryColor, this.members = const [], this.sourceName, this.sourceUrl, this.isBirthday = false, this.isDebut = false, this.isAnniversary = false, this.memberImage, this.anniversaryYear, }); factory Schedule.fromJson(Map json) { // category 중첩 객체 파싱 final category = json['category'] as Map?; // members 배열 파싱 final membersList = (json['members'] as List?) ?.map((m) => m is String ? m : m.toString()) .toList() ?? []; // source 중첩 객체 파싱 final source = json['source'] as Map?; return Schedule( id: json['id'], // int 또는 String (생일/기념일) title: json['title'] as String, date: json['date'] as String, time: json['time'] as String?, categoryId: category?['id'] as int?, categoryName: category?['name'] as String?, categoryColor: category?['color'] as String?, members: membersList, sourceName: source?['name'] as String?, sourceUrl: source?['url'] as String?, isBirthday: json['is_birthday'] == true, isDebut: json['is_debut'] == true, isAnniversary: json['is_anniversary'] == true, memberImage: json['member_image'] as String?, anniversaryYear: (json['anniversary_year'] as num?)?.toInt(), ); } /// 특별 일정 여부 (생일, 데뷔, 기념일) bool get isSpecial => isBirthday || isDebut || isAnniversary; /// 일반 일정의 int ID (특별 일정은 null) int? get numericId => id is int ? id : null; /// 멤버 리스트 반환 List get memberList => members; /// 시간 포맷 (HH:mm) String? get formattedTime { if (time == null) return null; return time!.length >= 5 ? time!.substring(0, 5) : time; } }