2026-01-13 18:12:22 +09:00
|
|
|
/// 일정 컨트롤러 (MVCS의 Controller 레이어)
|
|
|
|
|
///
|
|
|
|
|
/// 비즈니스 로직과 상태 관리를 담당합니다.
|
|
|
|
|
/// View는 이 Controller를 통해 데이터에 접근합니다.
|
|
|
|
|
library;
|
|
|
|
|
|
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
|
import 'package:intl/intl.dart';
|
|
|
|
|
import '../models/schedule.dart';
|
|
|
|
|
import '../services/schedules_service.dart';
|
|
|
|
|
|
|
|
|
|
/// 일정 상태
|
|
|
|
|
class ScheduleState {
|
|
|
|
|
final DateTime selectedDate;
|
|
|
|
|
final List<Schedule> schedules;
|
|
|
|
|
final bool isLoading;
|
|
|
|
|
final String? error;
|
|
|
|
|
|
|
|
|
|
const ScheduleState({
|
|
|
|
|
required this.selectedDate,
|
|
|
|
|
this.schedules = const [],
|
|
|
|
|
this.isLoading = false,
|
|
|
|
|
this.error,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/// 상태 복사 (불변성 유지)
|
|
|
|
|
ScheduleState copyWith({
|
|
|
|
|
DateTime? selectedDate,
|
|
|
|
|
List<Schedule>? schedules,
|
|
|
|
|
bool? isLoading,
|
|
|
|
|
String? error,
|
|
|
|
|
}) {
|
|
|
|
|
return ScheduleState(
|
|
|
|
|
selectedDate: selectedDate ?? this.selectedDate,
|
|
|
|
|
schedules: schedules ?? this.schedules,
|
|
|
|
|
isLoading: isLoading ?? this.isLoading,
|
|
|
|
|
error: error,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 선택된 날짜의 일정 목록
|
|
|
|
|
List<Schedule> get selectedDateSchedules {
|
|
|
|
|
final dateStr = DateFormat('yyyy-MM-dd').format(selectedDate);
|
|
|
|
|
return schedules.where((s) => s.date.split('T')[0] == dateStr).toList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 특정 날짜의 일정 (점 표시용, 최대 3개)
|
|
|
|
|
List<Schedule> getDaySchedules(DateTime date) {
|
|
|
|
|
final dateStr = DateFormat('yyyy-MM-dd').format(date);
|
|
|
|
|
return schedules.where((s) => s.date.split('T')[0] == dateStr).take(3).toList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 해당 달의 모든 날짜 배열
|
|
|
|
|
List<DateTime> get daysInMonth {
|
|
|
|
|
final year = selectedDate.year;
|
|
|
|
|
final month = selectedDate.month;
|
|
|
|
|
final lastDay = DateTime(year, month + 1, 0).day;
|
|
|
|
|
return List.generate(lastDay, (i) => DateTime(year, month, i + 1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 일정 컨트롤러
|
|
|
|
|
class ScheduleController extends Notifier<ScheduleState> {
|
|
|
|
|
@override
|
|
|
|
|
ScheduleState build() {
|
|
|
|
|
// 초기 상태
|
|
|
|
|
final initialState = ScheduleState(selectedDate: DateTime.now());
|
|
|
|
|
// 초기 데이터 로드
|
|
|
|
|
Future.microtask(() => loadSchedules());
|
|
|
|
|
return initialState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 월별 일정 로드
|
|
|
|
|
Future<void> loadSchedules() async {
|
|
|
|
|
state = state.copyWith(isLoading: true, error: null);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
final schedules = await getSchedules(
|
|
|
|
|
state.selectedDate.year,
|
|
|
|
|
state.selectedDate.month,
|
|
|
|
|
);
|
|
|
|
|
state = state.copyWith(schedules: schedules, isLoading: false);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
state = state.copyWith(isLoading: false, error: e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 날짜 선택
|
|
|
|
|
void selectDate(DateTime date) {
|
|
|
|
|
state = state.copyWith(selectedDate: date);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 월 변경
|
|
|
|
|
void changeMonth(int delta) {
|
|
|
|
|
final newDate = DateTime(
|
|
|
|
|
state.selectedDate.year,
|
|
|
|
|
state.selectedDate.month + delta,
|
|
|
|
|
1,
|
|
|
|
|
);
|
|
|
|
|
final today = DateTime.now();
|
|
|
|
|
|
|
|
|
|
// 이번 달이면 오늘 날짜, 다른 달이면 1일 선택
|
|
|
|
|
final selectedDay = (newDate.year == today.year && newDate.month == today.month)
|
|
|
|
|
? today.day
|
|
|
|
|
: 1;
|
|
|
|
|
|
|
|
|
|
state = state.copyWith(
|
|
|
|
|
selectedDate: DateTime(newDate.year, newDate.month, selectedDay),
|
|
|
|
|
);
|
|
|
|
|
loadSchedules();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 18:25:14 +09:00
|
|
|
/// 특정 날짜로 이동 (달력에서 선택 시)
|
|
|
|
|
void goToDate(DateTime date) {
|
|
|
|
|
final currentMonth = state.selectedDate.month;
|
|
|
|
|
final currentYear = state.selectedDate.year;
|
|
|
|
|
|
|
|
|
|
state = state.copyWith(selectedDate: date);
|
|
|
|
|
|
|
|
|
|
// 월이 변경되면 일정 다시 로드
|
|
|
|
|
if (date.month != currentMonth || date.year != currentYear) {
|
|
|
|
|
loadSchedules();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 18:12:22 +09:00
|
|
|
/// 오늘 여부
|
|
|
|
|
bool isToday(DateTime date) {
|
|
|
|
|
final today = DateTime.now();
|
|
|
|
|
return date.year == today.year &&
|
|
|
|
|
date.month == today.month &&
|
|
|
|
|
date.day == today.day;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 선택된 날짜 여부
|
|
|
|
|
bool isSelected(DateTime date) {
|
|
|
|
|
return date.year == state.selectedDate.year &&
|
|
|
|
|
date.month == state.selectedDate.month &&
|
|
|
|
|
date.day == state.selectedDate.day;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 일정 Provider
|
|
|
|
|
final scheduleProvider = NotifierProvider<ScheduleController, ScheduleState>(
|
|
|
|
|
ScheduleController.new,
|
|
|
|
|
);
|