diff --git a/trainerbox/lib/main.dart b/trainerbox/lib/main.dart index 0317838..d92ba98 100644 --- a/trainerbox/lib/main.dart +++ b/trainerbox/lib/main.dart @@ -2,13 +2,15 @@ // Einstiegspunkt der App und globale Konfigurationen import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'firebase_options.dart'; +import 'package:trainerbox/firebase_options.dart'; import 'screens/home_screen.dart'; import 'screens/login_screen.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); runApp(const MyApp()); } @@ -37,10 +39,10 @@ class _MyAppState extends State { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Trainer App', + title: 'TrainerBox', debugShowCheckedModeBanner: false, theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.pink), + colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: _loggedIn diff --git a/trainerbox/lib/screens/calendar_tab.dart b/trainerbox/lib/screens/calendar_tab.dart index 9cc00fb..7c8566b 100644 --- a/trainerbox/lib/screens/calendar_tab.dart +++ b/trainerbox/lib/screens/calendar_tab.dart @@ -1,5 +1,7 @@ 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}); @@ -9,165 +11,373 @@ class CalendarTab extends StatefulWidget { } class _CalendarTabState extends State { - CalendarFormat _calendarFormat = CalendarFormat.month; - DateTime _focusedDay = DateTime.now(); + CalendarFormat _calendarFormat = CalendarFormat.week; + late DateTime _focusedDay; DateTime? _selectedDay; Map>> _events = {}; + bool _isLoading = false; + String? _currentUserId; + String? _userRole; @override void initState() { super.initState(); - _selectedDay = DateTime.now(); - final now = DateTime.now(); - _focusedDay = DateTime(now.year, now.month, now.day); + _focusedDay = DateTime.now(); + _selectedDay = _focusedDay; + _currentUserId = FirebaseAuth.instance.currentUser?.uid; + _initializeData(); + } - // Beispiel-Events - _events = { - _focusedDay: [ - { - 'title': 'Ganzkörper Workout', - 'time': '09:00', - 'duration': '45 Minuten', - }, - {'title': 'Yoga Session', 'time': '17:30', 'duration': '30 Minuten'}, - ], - _focusedDay.add(const Duration(days: 1)): [ - {'title': 'HIIT Training', 'time': '08:00', 'duration': '30 Minuten'}, - ], + 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) { - return _events[DateTime(day.year, day.month, day.day)] ?? []; + final normalizedDate = DateTime(day.year, day.month, day.day); + return _events[normalizedDate] ?? []; } @override Widget build(BuildContext context) { - final firstDay = DateTime.utc(1900, 1, 1); - final lastDay = DateTime.utc(2999, 12, 31); - - if (_focusedDay.isBefore(firstDay)) { - _focusedDay = firstDay; - } else if (_focusedDay.isAfter(lastDay)) { - _focusedDay = lastDay; - } - return Scaffold( appBar: AppBar( - title: const Text('Trainingsplan'), + title: const Text('Kalender'), actions: [ IconButton( - icon: const Icon(Icons.add), - onPressed: () { - // TODO: Implement add workout to calendar - }, + icon: const Icon(Icons.refresh), + onPressed: _isLoading ? null : _loadEvents, ), ], ), - body: Column( - children: [ - TableCalendar( - firstDay: firstDay, - lastDay: lastDay, - 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, + 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: - _getEventsForDay(_selectedDay!).isEmpty - ? const Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.event_busy, size: 64, color: Colors.grey), - SizedBox(height: 16), - Text( - 'Keine Trainings geplant', - style: TextStyle(fontSize: 18, color: Colors.grey), - ), - SizedBox(height: 8), - Text( - 'Füge Trainings zu deinem Kalender hinzu', - style: TextStyle(fontSize: 14, color: Colors.grey), - ), - ], - ), - ) - : ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: _getEventsForDay(_selectedDay!).length, - itemBuilder: (context, index) { - final event = _getEventsForDay(_selectedDay!)[index]; - return Card( - margin: const EdgeInsets.only(bottom: 16), - child: ListTile( - leading: Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: Colors.blue[100], - borderRadius: BorderRadius.circular(8), + 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)), + ), + ], + ), + ); + }, + ), + ], + ), ), - child: const Icon( - Icons.fitness_center, - color: Colors.blue, - ), - ), - title: Text( - event['title'], - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text( - '${event['time']} • ${event['duration']}', - ), - trailing: IconButton( - icon: const Icon(Icons.delete_outline), - onPressed: () { - // TODO: Implement delete workout from calendar - }, - ), - ), - ); - }, - ), - ), - ], - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - // TODO: Implement add workout to calendar - }, - child: const Icon(Icons.add), + ); + }, + ), + ), + ], + ), ), ); } diff --git a/trainerbox/lib/screens/profile_tab.dart b/trainerbox/lib/screens/profile_tab.dart index 271ccb1..a1b0234 100644 --- a/trainerbox/lib/screens/profile_tab.dart +++ b/trainerbox/lib/screens/profile_tab.dart @@ -2,179 +2,308 @@ import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; -class ProfileTab extends StatelessWidget { +class ProfileTab extends StatefulWidget { final VoidCallback? onLogoutSuccess; const ProfileTab({super.key, this.onLogoutSuccess}); - Future _logout(BuildContext context) async { - await FirebaseAuth.instance.signOut(); - if (onLogoutSuccess != null) { - onLogoutSuccess!(); + @override + State createState() => _ProfileTabState(); +} + +class _ProfileTabState extends State { + final _formKey = GlobalKey(); + bool _isTrainer = false; + bool _isLoading = false; + Map _trainingTimes = {}; + Map _trainingDurations = {}; + + @override + void initState() { + super.initState(); + _loadUserData(); + } + + Future _loadUserData() async { + final user = FirebaseAuth.instance.currentUser; + if (user == null) return; + + try { + final doc = await FirebaseFirestore.instance.collection('User').doc(user.uid).get(); + if (doc.exists) { + final data = doc.data()!; + setState(() { + _isTrainer = data['role'] == 'trainer'; + if (_isTrainer) { + _trainingTimes = Map.from( + (data['trainingTimes'] ?? {}).map( + (key, value) => MapEntry( + key, + TimeOfDay( + hour: int.parse(value.split(':')[0]), + minute: int.parse(value.split(':')[1]), + ), + ), + ), + ); + _trainingDurations = Map.from(data['trainingDurations'] ?? {}); + } + }); + } + } catch (e) { + print('Error loading user data: $e'); + } + } + + Future _saveTrainingTime(String day, TimeOfDay? time, int? duration) async { + if (time == null || duration == null) return; + + setState(() => _isLoading = true); + try { + final user = FirebaseAuth.instance.currentUser; + if (user == null) return; + + final timeString = '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}'; + + await FirebaseFirestore.instance.collection('User').doc(user.uid).update({ + 'trainingTimes.$day': timeString, + 'trainingDurations.$day': duration, + }); + + setState(() { + _trainingTimes[day] = time; + _trainingDurations[day] = duration; + }); + + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Trainingszeit gespeichert')), + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Fehler beim Speichern: $e')), + ); + } finally { + setState(() => _isLoading = false); + } + } + + Future _removeTrainingTime(String day) async { + setState(() => _isLoading = true); + try { + final user = FirebaseAuth.instance.currentUser; + if (user == null) return; + + await FirebaseFirestore.instance.collection('User').doc(user.uid).update({ + 'trainingTimes.$day': FieldValue.delete(), + 'trainingDurations.$day': FieldValue.delete(), + }); + + setState(() { + _trainingTimes.remove(day); + _trainingDurations.remove(day); + }); + + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Trainingszeit entfernt')), + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Fehler beim Entfernen: $e')), + ); + } finally { + setState(() => _isLoading = false); + } + } + + Future _selectTime(BuildContext context, String day) async { + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: _trainingTimes[day] ?? TimeOfDay.now(), + ); + if (picked != null) { + final duration = await showDialog( + context: context, + builder: (context) => _DurationDialog( + initialDuration: _trainingDurations[day] ?? 60, + ), + ); + if (duration != null) { + await _saveTrainingTime(day, picked, duration); + } } } @override Widget build(BuildContext context) { final user = FirebaseAuth.instance.currentUser; - final email = user?.email ?? 'Keine E-Mail gefunden'; - final uid = user?.uid; + if (user == null) { + return const Center(child: Text('Nicht eingeloggt')); + } return Scaffold( - body: uid == null - ? const Center(child: Text('Nicht eingeloggt')) - : FutureBuilder( - future: FirebaseFirestore.instance.collection('User').doc(uid).get(), + appBar: AppBar( + title: const Text('Profil'), + actions: [ + IconButton( + icon: const Icon(Icons.logout), + onPressed: () async { + await FirebaseAuth.instance.signOut(); + if (widget.onLogoutSuccess != null) { + widget.onLogoutSuccess!(); + } + }, + ), + ], + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Persönliche Informationen', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + FutureBuilder( + future: FirebaseFirestore.instance.collection('User').doc(user.uid).get(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (!snapshot.hasData || !snapshot.data!.exists) { - return const Center(child: Text('Keine Profildaten gefunden')); + return const Center(child: Text('Keine Daten gefunden')); } final data = snapshot.data!.data() as Map; - final name = data['name'] ?? 'Unbekannt'; - final role = data['role'] == 'trainer' ? 'Trainer' : 'Spieler'; - final createdAt = (data['createdAt'] is Timestamp) - ? (data['createdAt'] as Timestamp).toDate() - : null; - final createdAtStr = createdAt != null - ? '${createdAt.day.toString().padLeft(2, '0')}.${createdAt.month.toString().padLeft(2, '0')}.${createdAt.year}' - : 'Unbekannt'; - // Beispiel-Benutzerdaten (Statistiken als Demo) - final Map userData = { - 'name': name, - 'level': role, - 'joinedDate': createdAtStr, - 'workoutsCompleted': 42, - 'totalMinutes': 1260, - }; - - return CustomScrollView( - slivers: [ - SliverAppBar( - expandedHeight: 200, - pinned: true, - flexibleSpace: FlexibleSpaceBar( - title: Text(userData['name']), - background: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Colors.blue[700]!, Colors.blue[500]!], - ), - ), - child: const Center( - child: Icon(Icons.person, size: 80, color: Colors.white), - ), + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Name: ${data['name'] ?? '-'}'), + const SizedBox(height: 8), + Text('E-Mail: ${user.email ?? '-'}'), + const SizedBox(height: 8), + Text('Rolle: ${data['role'] ?? '-'}'), + if (_isTrainer) ...[ + const SizedBox(height: 24), + const Text( + 'Trainingszeiten', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, ), ), - ), - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildInfoCard( - title: 'Persönliche Informationen', - child: Column( - children: [ - _buildInfoRow('E-Mail', email, Icons.email), - const Divider(), - _buildInfoRow('Name', name, Icons.person), - const Divider(), - _buildInfoRow('Rolle', role, Icons.badge), - const Divider(), - _buildInfoRow( - 'Mitglied seit', - userData['joinedDate'], - Icons.calendar_today, + const SizedBox(height: 16), + ...['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'] + .map((day) => Card( + margin: const EdgeInsets.only(bottom: 8), + child: ListTile( + title: Text(day), + subtitle: _trainingTimes[day] != null + ? Text( + '${_trainingTimes[day]!.format(context)} - ${_trainingDurations[day]} Minuten', + ) + : const Text('Keine Trainingszeit'), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon( + _trainingTimes[day] != null + ? Icons.edit + : Icons.add, + ), + onPressed: _isLoading + ? null + : () => _selectTime(context, day), + ), + if (_trainingTimes[day] != null) + IconButton( + icon: const Icon(Icons.delete), + onPressed: _isLoading + ? null + : () => _removeTrainingTime(day), + ), + ], ), - ], - ), - ), - const SizedBox(height: 16), - _buildInfoCard( - title: 'Einstellungen', - child: Column( - children: [ - ListTile( - leading: const Icon(Icons.notifications), - title: const Text('Benachrichtigungen'), - trailing: Switch( - value: true, - onChanged: (value) {}, - ), - ), - const Divider(), - ListTile( - leading: const Icon(Icons.dark_mode), - title: const Text('Dark Mode'), - trailing: Switch( - value: false, - onChanged: (value) {}, - ), - ), - const Divider(), - ListTile( - leading: const Icon(Icons.language), - title: const Text('Sprache'), - trailing: const Text('Deutsch'), - onTap: () {}, - ), - ], - ), - ), - const SizedBox(height: 16), - Center( - child: TextButton.icon( - onPressed: () => _logout(context), - icon: const Icon(Icons.logout), - label: const Text('Abmelden'), - style: TextButton.styleFrom(foregroundColor: Colors.red), - ), - ), - ], - ), - ), - ), + ), + )) + .toList(), + ], ], ); }, ), - ); - } - - Widget _buildInfoCard({required String title, required Widget child}) { - return Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - title, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - ), - child, - ], - ), - ); - } - - Widget _buildInfoRow(String label, String value, IconData icon) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), - child: Row( - children: [ - Icon(icon, color: Colors.blue), - const SizedBox(width: 16), - Expanded(child: Text(label)), - Text(value, style: TextStyle(color: Colors.grey[600])), - ], + ], + ), ), ); } } + +class _DurationDialog extends StatefulWidget { + final int initialDuration; + + const _DurationDialog({required this.initialDuration}); + + @override + State<_DurationDialog> createState() => _DurationDialogState(); +} + +class _DurationDialogState extends State<_DurationDialog> { + late int _duration; + + @override + void initState() { + super.initState(); + _duration = widget.initialDuration; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Trainingsdauer'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text('Wähle die Dauer der Trainingseinheit in Minuten:'), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + icon: const Icon(Icons.remove), + onPressed: () { + if (_duration > 15) { + setState(() => _duration -= 15); + } + }, + ), + Text( + '$_duration Minuten', + style: const TextStyle(fontSize: 18), + ), + IconButton( + icon: const Icon(Icons.add), + onPressed: () { + setState(() => _duration += 15); + }, + ), + ], + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Abbrechen'), + ), + ElevatedButton( + onPressed: () => Navigator.pop(context, _duration), + child: const Text('Bestätigen'), + ), + ], + ); + } +} diff --git a/trainerbox/pubspec.lock b/trainerbox/pubspec.lock index 4a289ff..301671d 100644 --- a/trainerbox/pubspec.lock +++ b/trainerbox/pubspec.lock @@ -316,10 +316,10 @@ packages: dependency: transitive description: name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.20.2" + version: "0.19.0" leak_tracker: dependency: transitive description: @@ -465,10 +465,10 @@ packages: dependency: "direct main" description: name: table_calendar - sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982" + sha256: b2896b7c86adf3a4d9c911d860120fe3dbe03c85db43b22fd61f14ee78cdbb63 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.1.3" term_glyph: dependency: transitive description: