Line data Source code
1 : import 'package:flutter/material.dart';
2 : import 'package:provider/provider.dart';
3 : import 'package:table_calendar/table_calendar.dart';
4 : import 'package:intl/intl.dart';
5 :
6 : import '../../models/event_model.dart';
7 : import '../../services/event_service.dart';
8 : import '../../services/auth_service.dart';
9 : import '../../services/club_service.dart';
10 : import 'event_details_screen.dart';
11 :
12 : class EventCalendarScreen extends StatefulWidget {
13 24 : const EventCalendarScreen({super.key});
14 :
15 0 : @override
16 0 : State<EventCalendarScreen> createState() => _EventCalendarScreenState();
17 : }
18 :
19 : class _EventCalendarScreenState extends State<EventCalendarScreen> {
20 : CalendarFormat _calendarFormat = CalendarFormat.month;
21 : DateTime _focusedDay = DateTime.now();
22 : DateTime? _selectedDay;
23 : Map<DateTime, List<Event>> _events = {};
24 : bool _isLoading = true;
25 :
26 0 : @override
27 : void initState() {
28 0 : super.initState();
29 0 : _loadEvents();
30 : }
31 :
32 0 : Future<void> _loadEvents() async {
33 0 : setState(() {
34 0 : _isLoading = true;
35 : });
36 :
37 : try {
38 0 : final authService = Provider.of<AuthService>(context, listen: false);
39 0 : final clubService = Provider.of<ClubService>(context, listen: false);
40 0 : final eventService = Provider.of<EventService>(context, listen: false);
41 :
42 0 : if (clubService.currentClub != null) {
43 0 : eventService.initialize(authService.token!);
44 0 : await eventService.fetchClubEvents();
45 :
46 : // 이벤트를 날짜별로 그룹화
47 0 : final Map<DateTime, List<Event>> eventMap = {};
48 :
49 0 : for (final event in eventService.events) {
50 0 : final date = DateTime(
51 0 : event.startDate.year,
52 0 : event.startDate.month,
53 0 : event.startDate.day,
54 : );
55 :
56 0 : if (eventMap[date] == null) {
57 0 : eventMap[date] = [];
58 : }
59 :
60 0 : eventMap[date]!.add(event);
61 : }
62 :
63 0 : setState(() {
64 0 : _events = eventMap;
65 0 : _isLoading = false;
66 : });
67 : }
68 : } catch (e) {
69 0 : setState(() {
70 0 : _isLoading = false;
71 : });
72 :
73 0 : if (mounted) {
74 0 : ScaffoldMessenger.of(context).showSnackBar(
75 0 : SnackBar(content: Text('이벤트를 불러오는데 실패했습니다: $e')),
76 : );
77 : }
78 : }
79 : }
80 :
81 0 : List<Event> _getEventsForDay(DateTime day) {
82 0 : final normalizedDay = DateTime(day.year, day.month, day.day);
83 0 : return _events[normalizedDay] ?? [];
84 : }
85 :
86 0 : @override
87 : Widget build(BuildContext context) {
88 0 : return Scaffold(
89 0 : appBar: AppBar(
90 : title: const Text('이벤트 캘린더'),
91 0 : actions: [
92 0 : IconButton(
93 : icon: const Icon(Icons.refresh),
94 0 : onPressed: _loadEvents,
95 : ),
96 : ],
97 : ),
98 0 : body: _isLoading
99 : ? const Center(child: CircularProgressIndicator())
100 0 : : Column(
101 0 : children: [
102 0 : TableCalendar(
103 0 : firstDay: DateTime.now().subtract(const Duration(days: 365)),
104 0 : lastDay: DateTime.now().add(const Duration(days: 365)),
105 0 : focusedDay: _focusedDay,
106 0 : calendarFormat: _calendarFormat,
107 0 : selectedDayPredicate: (day) {
108 0 : return isSameDay(_selectedDay, day);
109 : },
110 0 : onDaySelected: (selectedDay, focusedDay) {
111 0 : setState(() {
112 0 : _selectedDay = selectedDay;
113 0 : _focusedDay = focusedDay;
114 : });
115 : },
116 0 : onFormatChanged: (format) {
117 0 : setState(() {
118 0 : _calendarFormat = format;
119 : });
120 : },
121 0 : onPageChanged: (focusedDay) {
122 0 : _focusedDay = focusedDay;
123 : },
124 0 : eventLoader: _getEventsForDay,
125 : calendarStyle: const CalendarStyle(
126 : markersMaxCount: 3,
127 : markerDecoration: BoxDecoration(
128 : color: Colors.blue,
129 : shape: BoxShape.circle,
130 : ),
131 : ),
132 : headerStyle: const HeaderStyle(
133 : formatButtonShowsNext: false,
134 : titleCentered: true,
135 : ),
136 : ),
137 : const SizedBox(height: 8),
138 0 : Expanded(
139 0 : child: _selectedDay == null
140 : ? const Center(child: Text('날짜를 선택하세요'))
141 0 : : _buildEventList(),
142 : ),
143 : ],
144 : ),
145 : );
146 : }
147 :
148 0 : Widget _buildEventList() {
149 0 : final events = _getEventsForDay(_selectedDay!);
150 0 : final dateFormat = DateFormat('HH:mm');
151 :
152 0 : if (events.isEmpty) {
153 : return const Center(child: Text('선택한 날짜에 이벤트가 없습니다'));
154 : }
155 :
156 0 : return ListView.builder(
157 0 : itemCount: events.length,
158 0 : itemBuilder: (context, index) {
159 0 : final event = events[index];
160 0 : return Card(
161 : margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
162 0 : child: ListTile(
163 0 : leading: Container(
164 : width: 48,
165 : height: 48,
166 0 : decoration: BoxDecoration(
167 0 : color: Colors.blue[100],
168 0 : borderRadius: BorderRadius.circular(8),
169 : ),
170 : child: const Icon(Icons.event, color: Colors.blue),
171 : ),
172 0 : title: Text(
173 0 : event.title,
174 : style: const TextStyle(fontWeight: FontWeight.bold),
175 : ),
176 0 : subtitle: Column(
177 : crossAxisAlignment: CrossAxisAlignment.start,
178 0 : children: [
179 0 : Text(dateFormat.format(event.startDate)),
180 0 : if (event.location != null) Text(event.location!),
181 : ],
182 : ),
183 0 : onTap: () => _navigateToEventDetails(event),
184 : ),
185 : );
186 : },
187 : );
188 : }
189 :
190 0 : void _navigateToEventDetails(Event event) {
191 0 : Navigator.of(context).push(
192 0 : MaterialPageRoute(
193 0 : builder: (context) => EventDetailsScreen(event: event),
194 : ),
195 0 : ).then((result) {
196 0 : if (result == true) {
197 : // 이벤트가 수정되었으면 목록 새로고침
198 0 : _loadEvents();
199 : }
200 : });
201 : }
202 : }
|