CPD-Gitty/trainerbox/lib/screens/calendar_tab.dart

385 lines
14 KiB
Dart

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<CalendarTab> createState() => _CalendarTabState();
}
class _CalendarTabState extends State<CalendarTab> {
CalendarFormat _calendarFormat = CalendarFormat.week;
late DateTime _focusedDay;
DateTime? _selectedDay;
Map<DateTime, List<Map<String, dynamic>>> _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<void> _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<void> _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 = <DateTime, List<Map<String, dynamic>>>{};
for (var trainerDoc in trainersSnapshot.docs) {
final trainerData = trainerDoc.data() as Map<String, dynamic>;
final trainingTimes = trainerData['trainingTimes'] as Map<String, dynamic>? ?? {};
final trainingDurations = trainerData['trainingDurations'] as Map<String, dynamic>? ?? {};
final cancelledTrainings = trainerData['cancelledTrainings'] as List<dynamic>? ?? [];
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<String, dynamic>) {
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<void> _deleteTraining(Map<String, dynamic> 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<String, dynamic>;
final cancelledTrainings = List<Map<String, dynamic>>.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<Map<String, dynamic>> _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)),
),
],
),
);
},
),
],
),
),
);
},
),
),
],
),
),
);
}
}