import 'package:flutter/material.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; class CalendarTab extends StatefulWidget { const CalendarTab({super.key}); @override State createState() => _CalendarTabState(); } class _CalendarTabState extends State { CalendarFormat _calendarFormat = CalendarFormat.week; late DateTime _focusedDay; DateTime? _selectedDay; Map>> _events = {}; bool _isLoading = false; String? _currentUserId; String? _userRole; @override void initState() { super.initState(); _focusedDay = DateTime.now(); _selectedDay = _focusedDay; _currentUserId = FirebaseAuth.instance.currentUser?.uid; _initializeData(); } Future _initializeData() async { if (_currentUserId != null) { final userDoc = await FirebaseFirestore.instance .collection('User') .doc(_currentUserId) .get(); if (userDoc.exists) { setState(() { _userRole = userDoc.data()?['role'] as String?; }); await _loadEvents(); } } } Future _loadEvents() async { if (_userRole == null) return; setState(() => _isLoading = true); try { QuerySnapshot trainersSnapshot; if (_userRole == 'trainer') { // Trainer sieht nur seine eigenen Trainings trainersSnapshot = await FirebaseFirestore.instance .collection('User') .where('role', isEqualTo: 'trainer') .where(FieldPath.documentId, isEqualTo: _currentUserId) .get(); } else { // Spieler sehen alle Trainings trainersSnapshot = await FirebaseFirestore.instance .collection('User') .where('role', isEqualTo: 'trainer') .get(); } final events = >>{}; for (var trainerDoc in trainersSnapshot.docs) { final trainerData = trainerDoc.data() as Map; final trainingTimes = trainerData['trainingTimes'] as Map? ?? {}; final trainingDurations = trainerData['trainingDurations'] as Map? ?? {}; final cancelledTrainings = trainerData['cancelledTrainings'] as List? ?? []; trainingTimes.forEach((day, timeStr) { if (timeStr == null) return; final duration = trainingDurations[day] as int? ?? 60; final timeParts = (timeStr as String).split(':'); if (timeParts.length != 2) return; final hour = int.tryParse(timeParts[0]) ?? 0; final minute = int.tryParse(timeParts[1]) ?? 0; final now = DateTime.now(); final daysUntilNext = _getDaysUntilNext(day, now.weekday); final eventDate = DateTime(now.year, now.month, now.day + daysUntilNext, hour, minute); // Erstelle Trainings für ein ganzes Jahr for (var i = 0; i < 52; i++) { final date = eventDate.add(Duration(days: i * 7)); final normalizedDate = DateTime(date.year, date.month, date.day); // Prüfe, ob das Training an diesem Tag abgesagt wurde final isCancelled = cancelledTrainings.any((cancelled) { if (cancelled is Map) { final cancelledDate = DateTime.parse(cancelled['date'] as String); return isSameDay(cancelledDate, normalizedDate); } return false; }); if (!isCancelled) { final event = { 'trainerName': trainerData['name'] ?? 'Unbekannter Trainer', 'time': timeStr, 'duration': duration, 'trainerId': trainerDoc.id, 'isCurrentUser': trainerDoc.id == _currentUserId, 'day': day, 'date': normalizedDate.toIso8601String(), }; if (events.containsKey(normalizedDate)) { events[normalizedDate]!.add(event); } else { events[normalizedDate] = [event]; } } } }); } setState(() { _events = events; _isLoading = false; }); } catch (e) { print('Error loading events: $e'); setState(() => _isLoading = false); } } Future _deleteTraining(Map event) async { if (_userRole != 'trainer' || !event['isCurrentUser']) return; try { final userDoc = await FirebaseFirestore.instance .collection('User') .doc(_currentUserId) .get(); if (!userDoc.exists) return; final data = userDoc.data() as Map; final cancelledTrainings = List>.from(data['cancelledTrainings'] ?? []); // Füge das Training zur Liste der abgesagten Trainings hinzu cancelledTrainings.add({ 'date': event['date'], 'day': event['day'], 'time': event['time'], 'duration': event['duration'], }); // Aktualisiere die Daten in Firestore await FirebaseFirestore.instance .collection('User') .doc(_currentUserId) .update({ 'cancelledTrainings': cancelledTrainings, }); // Lade die Events neu await _loadEvents(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Training wurde gelöscht')), ); } } catch (e) { print('Error deleting training: $e'); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Fehler beim Löschen des Trainings')), ); } } } int _getDaysUntilNext(String day, int currentWeekday) { final weekdays = { 'Montag': 1, 'Dienstag': 2, 'Mittwoch': 3, 'Donnerstag': 4, 'Freitag': 5, 'Samstag': 6, 'Sonntag': 7, }; final targetWeekday = weekdays[day] ?? 1; var daysUntilNext = targetWeekday - currentWeekday; if (daysUntilNext <= 0) { daysUntilNext += 7; } return daysUntilNext; } List> _getEventsForDay(DateTime day) { final normalizedDate = DateTime(day.year, day.month, day.day); return _events[normalizedDate] ?? []; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Kalender'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _isLoading ? null : _loadEvents, ), ], ), body: SafeArea( child: Column( children: [ Container( padding: const EdgeInsets.all(8.0), child: TableCalendar( firstDay: DateTime.utc(2024, 1, 1), lastDay: DateTime.utc(2025, 12, 31), focusedDay: _focusedDay, calendarFormat: _calendarFormat, selectedDayPredicate: (day) { return isSameDay(_selectedDay, day); }, onDaySelected: (selectedDay, focusedDay) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; }); }, onFormatChanged: (format) { setState(() { _calendarFormat = format; }); }, onPageChanged: (focusedDay) { setState(() { _focusedDay = focusedDay; }); }, eventLoader: _getEventsForDay, calendarStyle: const CalendarStyle( markersMaxCount: 1, markerDecoration: BoxDecoration( color: Colors.blue, shape: BoxShape.circle, ), ), headerStyle: const HeaderStyle( formatButtonVisible: true, titleCentered: true, ), calendarBuilders: CalendarBuilders( markerBuilder: (context, date, events) { if (events.isEmpty) return null; return Positioned( bottom: 1, child: Container( width: 8, height: 8, decoration: const BoxDecoration( color: Colors.blue, shape: BoxShape.circle, ), ), ); }, ), startingDayOfWeek: StartingDayOfWeek.monday, daysOfWeekStyle: const DaysOfWeekStyle( weekdayStyle: TextStyle(fontWeight: FontWeight.bold), weekendStyle: TextStyle(color: Colors.red), ), availableCalendarFormats: const { CalendarFormat.week: 'Woche', CalendarFormat.month: 'Monat', }, ), ), const Divider(), Expanded( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _selectedDay == null ? const Center(child: Text('Bitte wähle einen Tag aus')) : ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: _getEventsForDay(_selectedDay!).length, itemBuilder: (context, index) { final event = _getEventsForDay(_selectedDay!)[index]; final isCurrentUser = event['isCurrentUser'] as bool; return Card( margin: const EdgeInsets.only(bottom: 8), color: isCurrentUser ? Colors.blue.withOpacity(0.1) : null, child: ListTile( leading: Icon( Icons.sports, color: isCurrentUser ? Colors.blue : null, ), title: Text( isCurrentUser ? 'Training' : event['trainerName'], style: TextStyle( fontWeight: isCurrentUser ? FontWeight.bold : null, ), ), subtitle: Text( '${event['time']} - ${event['duration']} Minuten', ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.info), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text(isCurrentUser ? 'Training' : event['trainerName']), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Zeit: ${event['time']}'), const SizedBox(height: 8), Text('Dauer: ${event['duration']} Minuten'), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Schließen'), ), ], ), ); }, ), if (isCurrentUser) IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Training löschen'), content: const Text('Möchten Sie dieses Training wirklich löschen?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Abbrechen'), ), TextButton( onPressed: () { Navigator.pop(context); _deleteTraining(event); }, child: const Text('Löschen', style: TextStyle(color: Colors.red)), ), ], ), ); }, ), ], ), ), ); }, ), ), ], ), ), ); } }