// screens/home_screen.dart // Enthält die BottomNavigationBar-Logik und Navigation zwischen den Hauptscreens import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:intl/intl.dart'; import 'search_tab.dart'; import 'favorites_tab.dart'; import 'calendar_tab.dart'; import 'profile_tab.dart'; class HomeScreen extends StatefulWidget { final VoidCallback? onLogoutSuccess; const HomeScreen({super.key, this.onLogoutSuccess}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { int _selectedIndex = 0; Map? _nextTraining; bool _isLoading = true; DateTime? _calendarInitialDate; @override void initState() { super.initState(); _loadNextTraining(); } Future _loadNextTraining() async { setState(() => _isLoading = true); try { final user = FirebaseAuth.instance.currentUser; if (user == null) return; final userDoc = await FirebaseFirestore.instance .collection('User') .doc(user.uid) .get(); if (!userDoc.exists) return; final userData = userDoc.data() as Map; final userRole = userData['role'] as String?; final userClub = userData['club'] as String?; 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: user.uid) .get(); } else { // Spieler sieht nur Trainings von Trainern seines Vereins if (userClub == null || userClub.isEmpty) { setState(() { _nextTraining = null; _isLoading = false; }); return; } trainersSnapshot = await FirebaseFirestore.instance .collection('User') .where('role', isEqualTo: 'trainer') .where('club', isEqualTo: userClub) .get(); } final now = DateTime.now(); DateTime? nextTrainingDate; Map? nextTraining; 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 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 daysUntilNext = _getDaysUntilNext(day, now.weekday); final eventDate = DateTime(now.year, now.month, now.day + daysUntilNext, hour, minute); // Prüfe die nächsten 4 Wochen for (var i = 0; i < 4; i++) { final date = eventDate.add(Duration(days: i * 7)); final normalizedDate = DateTime(date.year, date.month, date.day); final dateString = normalizedDate.toIso8601String(); 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 && (nextTrainingDate == null || date.isBefore(nextTrainingDate!))) { nextTrainingDate = date; nextTraining = { 'date': dateString, 'time': timeStr, 'duration': trainingDurations[day] ?? 60, 'trainerName': trainerData['name'] ?? 'Unbekannter Trainer', 'day': day, }; } } }); } setState(() { _nextTraining = nextTraining; _isLoading = false; }); } catch (e) { print('Error loading next training: $e'); setState(() { _isLoading = false; }); } } 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; } bool isSameDay(DateTime a, DateTime b) { return a.year == b.year && a.month == b.month && a.day == b.day; } void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } List get _screens => [ _buildHomeTab(), const SearchTab(), const FavoritesTab(), CalendarTab(initialDate: _calendarInitialDate), ProfileTab(onLogoutSuccess: widget.onLogoutSuccess), ]; @override Widget build(BuildContext context) { return Scaffold( body: _screens[_selectedIndex], bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, currentIndex: _selectedIndex, onTap: _onItemTapped, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'), BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Suche'), BottomNavigationBarItem( icon: Icon(Icons.favorite_border), label: 'Favoriten', ), BottomNavigationBarItem( icon: Icon(Icons.calendar_today), label: 'Kalender', ), BottomNavigationBarItem( icon: Icon(Icons.person_outline), label: 'Profil', ), ], ), ); } Widget _buildHomeTab() { return SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), const Center( child: Text( 'Hallo Trainer!', style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Color(0xFFE57399), ), ), ), const SizedBox(height: 24), GestureDetector( onTap: () { if (_nextTraining != null) { setState(() { _calendarInitialDate = DateTime.parse(_nextTraining!['date']); _selectedIndex = 3; }); } else { setState(() => _selectedIndex = 3); } }, child: Stack( children: [ Container( height: 140, width: double.infinity, decoration: BoxDecoration( color: Colors.pink[100], borderRadius: BorderRadius.circular(20), ), child: const Center( child: Icon(Icons.sports_handball, size: 80, color: Colors.white70), ), ), Positioned( left: 20, bottom: 20, child: Text( 'Dein nächstes Training', style: TextStyle( color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold, shadows: [ Shadow( blurRadius: 8, color: Colors.black.withOpacity(0.5), offset: Offset(2, 2), ), ], ), ), ), if (_isLoading) const Positioned.fill( child: Center(child: CircularProgressIndicator()), ) else if (_nextTraining != null) Positioned( right: 20, bottom: 20, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.black54, borderRadius: BorderRadius.circular(12), ), child: Text( DateFormat('EEEE, dd.MM.yyyy', 'de_DE').format( DateTime.parse(_nextTraining!['date']), ), style: const TextStyle(color: Colors.white, fontSize: 14), ), ), ), ], ), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Favoriten', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.chevron_right), onPressed: () {}, ), ], ), Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ _buildFavoriteCircle('Aufwärmen & Mobilisation', Icons.directions_run, categoryColors['Aufwärmen & Mobilisation']!), _buildFavoriteCircle('Wurf- & Torabschluss', Icons.sports_handball, categoryColors['Wurf- & Torabschluss']!), _buildFavoriteCircle('Torwarttraining', Icons.sports, categoryColors['Torwarttraining']!), _buildFavoriteCircle('Athletik', Icons.fitness_center, categoryColors['Athletik']!), _buildFavoriteCircle('Pass', Icons.compare_arrows, categoryColors['Pass']!), _buildFavoriteCircle('Koordination', Icons.directions_walk, categoryColors['Koordination']!), ], ), ), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Vorschläge', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.chevron_right), onPressed: () {}, ), ], ), SizedBox( height: 170, child: ListView( scrollDirection: Axis.horizontal, children: [ _buildSuggestionCard('Wurf- & Torabschluss', 'Sprungwurf', Icons.sports_handball, categoryColors['Wurf- & Torabschluss']!), _buildSuggestionCard('Pass', 'Doppelpass', Icons.compare_arrows, categoryColors['Pass']!), _buildSuggestionCard('Koordination', 'Leiterlauf', Icons.directions_walk, categoryColors['Koordination']!), ], ), ), ], ), ), ); } Widget _buildFavoriteCircle(String label, IconData icon, Color color) { return Padding( padding: const EdgeInsets.only(right: 16.0), child: Column( children: [ CircleAvatar( radius: 24, backgroundColor: color.withOpacity(0.2), child: Icon(icon, color: color, size: 26), ), const SizedBox(height: 4), SizedBox( width: 60, child: Text( label, style: const TextStyle(fontSize: 12), textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, ), ), ], ), ); } Widget _buildSuggestionCard(String category, String title, IconData icon, Color color) { return Container( width: 130, margin: const EdgeInsets.only(right: 16), child: Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), elevation: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 80, width: double.infinity, decoration: BoxDecoration( color: color.withOpacity(0.15), borderRadius: const BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), child: Center( child: Icon(icon, color: color, size: 40), ), ), Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(category, style: const TextStyle(fontSize: 12, color: Colors.grey)), const SizedBox(height: 4), Text(title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), ], ), ), ], ), ), ); } } const Map categoryColors = { 'Aufwärmen & Mobilisation': Colors.deepOrange, 'Wurf- & Torabschluss': Colors.orange, 'Torwarttraining': Colors.green, 'Athletik': Colors.blue, 'Pass': Colors.purple, 'Koordination': Colors.teal, };