fromis_9/app/lib/models/schedule.dart
caadiq 0ddde32bed feat(app): 홈 화면 일정 API를 새 응답 형식에 맞게 업데이트
- Schedule 모델: category/source 중첩 객체, members 배열 파싱
- 일정 서비스: { schedules: [] } 래핑된 응답 처리
- 홈/웹 일정 카드: sourceName을 별도 줄로 분리하여 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:15:19 +09:00

173 lines
4.6 KiB
Dart

/// 일정 모델
library;
/// 멤버 정보
class ScheduleMember {
final int id;
final String name;
ScheduleMember({required this.id, required this.name});
factory ScheduleMember.fromJson(Map<String, dynamic> 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<String, dynamic> 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 String? description;
final int categoryId;
final String? categoryName;
final String? categoryColor;
final String? sourceUrl;
final String? sourceName;
final String? imageUrl;
final List<String> images;
final String? locationName;
final String? locationAddress;
final String? locationLat;
final String? locationLng;
final List<ScheduleMember> members;
final List<RelatedDate> relatedDates;
ScheduleDetail({
required this.id,
required this.title,
required this.date,
this.time,
this.description,
required this.categoryId,
this.categoryName,
this.categoryColor,
this.sourceUrl,
this.sourceName,
this.imageUrl,
this.images = const [],
this.locationName,
this.locationAddress,
this.locationLat,
this.locationLng,
this.members = const [],
this.relatedDates = const [],
});
factory ScheduleDetail.fromJson(Map<String, dynamic> json) {
return ScheduleDetail(
id: json['id'] as int,
title: json['title'] as String,
date: json['date'] as String,
time: json['time'] as String?,
description: json['description'] as String?,
categoryId: json['category_id'] as int,
categoryName: json['category_name'] as String?,
categoryColor: json['category_color'] as String?,
sourceUrl: json['source_url'] as String?,
sourceName: json['source_name'] as String?,
imageUrl: json['image_url'] as String?,
images: (json['images'] as List<dynamic>?)?.cast<String>() ?? [],
locationName: json['location_name'] as String?,
locationAddress: json['location_address'] as String?,
locationLat: json['location_lat'] as String?,
locationLng: json['location_lng'] as String?,
members: (json['members'] as List<dynamic>?)
?.map((m) => ScheduleMember.fromJson(m))
.toList() ??
[],
relatedDates: (json['related_dates'] as List<dynamic>?)
?.map((r) => RelatedDate.fromJson(r))
.toList() ??
[],
);
}
/// 시간 포맷 (HH:mm)
String? get formattedTime {
if (time == null) return null;
return time!.length >= 5 ? time!.substring(0, 5) : time;
}
}
class Schedule {
final int id;
final String title;
final String date;
final String? time;
final int? categoryId;
final String? categoryName;
final String? categoryColor;
final List<String> members;
final String? sourceName;
final String? sourceUrl;
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,
});
factory Schedule.fromJson(Map<String, dynamic> json) {
// category 중첩 객체 파싱
final category = json['category'] as Map<String, dynamic>?;
// members 배열 파싱
final membersList = (json['members'] as List<dynamic>?)
?.map((m) => m is String ? m : m.toString())
.toList() ?? [];
// source 중첩 객체 파싱
final source = json['source'] as Map<String, dynamic>?;
return Schedule(
id: json['id'] is String ? int.parse(json['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: membersList,
sourceName: source?['name'] as String?,
sourceUrl: source?['url'] as String?,
);
}
/// 멤버 리스트 반환
List<String> get memberList => members;
/// 시간 포맷 (HH:mm)
String? get formattedTime {
if (time == null) return null;
return time!.length >= 5 ? time!.substring(0, 5) : time;
}
}