import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:intl/intl.dart'; import '../models/schedule_item.dart'; import '../services/schedule_service.dart'; class ScheduleListWidget extends StatefulWidget { const ScheduleListWidget({super.key}); @override State createState() => _ScheduleListWidgetState(); } class _ScheduleListWidgetState extends State { Timer? _timer; List _schedules = []; bool _isLoading = true; String? _error; @override void initState() { super.initState(); _fetchSchedules(); _startAutoRefresh(); } void _startAutoRefresh() { _timer = Timer.periodic(const Duration(seconds: 30), (timer) { _fetchSchedules(); }); } Future _fetchSchedules() async { try { final data = await Provider.of( context, listen: false, ).fetchWeeklySchedules(); if (mounted) { setState(() { _schedules = data; _isLoading = false; _error = null; }); } } catch (e) { if (mounted) { setState(() { _error = 'Failed to load schedules'; _isLoading = false; }); } } } @override void dispose() { _timer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: Theme.of(context).cardTheme.color, borderRadius: BorderRadius.circular(16), ), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '주간 일정', style: Theme.of(context).textTheme.titleLarge?.copyWith( color: Colors.white, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), Expanded( child: _buildContent(), ), ], ), ); } Widget _buildContent() { if (_isLoading && _schedules.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (_error != null && _schedules.isEmpty) { return Center( child: Text( _error!, style: const TextStyle(color: Colors.white54), ), ); } // Correctly filter for current week (Sunday to Saturday) final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); // In Dart, weekday is 1 (Mon) to 7 (Sun). // To get Sunday: if Mon(1), subtract 1. if Sun(7), subtract 0. final daysToSubtract = now.weekday % 7; final startOfWeek = today.subtract(Duration(days: daysToSubtract)); final endOfWeek = startOfWeek.add(const Duration(days: 6, hours: 23, minutes: 59, seconds: 59)); final filteredSchedules = _schedules.where((item) { // Overlap check: schedule starts before week ends AND schedule ends after week starts return item.startDate.isBefore(endOfWeek) && item.endDate.isAfter(startOfWeek); }).toList(); if (filteredSchedules.isEmpty) { return const Center( child: Text( '이번 주 일정이 없습니다', style: TextStyle(color: Colors.white54), ), ); } // Sort by date final sortedSchedules = List.from(filteredSchedules); sortedSchedules.sort((a, b) => a.startDate.compareTo(b.startDate)); return ListView.separated( itemCount: sortedSchedules.length, separatorBuilder: (context, index) => const Divider(color: Colors.white10), itemBuilder: (context, index) { final item = sortedSchedules[index]; // Multi-day check final isMultiDay = item.startDate.year != item.endDate.year || item.startDate.month != item.endDate.month || item.startDate.day != item.endDate.day; String? dateRangeStr; if (isMultiDay) { final startStr = DateFormat('MM/dd').format(item.startDate); final endStr = DateFormat('MM/dd').format(item.endDate); dateRangeStr = '$startStr ~ $endStr'; } return ListTile( contentPadding: EdgeInsets.zero, leading: Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 6, ), decoration: BoxDecoration( color: isMultiDay ? Colors.blue.withOpacity(0.2) : Colors.white10, borderRadius: BorderRadius.circular(8), border: isMultiDay ? Border.all(color: Colors.blue.withOpacity(0.5)) : null, ), child: FittedBox( fit: BoxFit.scaleDown, child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( DateFormat('d').format(item.startDate), style: TextStyle( color: isMultiDay ? Colors.blue : Colors.white, fontWeight: FontWeight.bold, fontSize: 18, height: 1.2, ), ), Text( DateFormat('E').format(item.startDate), style: const TextStyle( color: Colors.white70, fontSize: 12, height: 1.2, ), ), ], ), ), ), title: Text( item.title, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.w500, ), ), subtitle: dateRangeStr != null ? Text( dateRangeStr, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ) : null, ); }, ); } }