Traingsplan anlegen added
parent
d706f8e9a2
commit
9689d4b9ba
|
|
@ -126,13 +126,14 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
final cancelledTrainings = trainerData['cancelledTrainings'] as List<dynamic>? ?? [];
|
final cancelledTrainings = trainerData['cancelledTrainings'] as List<dynamic>? ?? [];
|
||||||
final trainingExercises = trainerData['trainingExercises'] as Map<String, dynamic>? ?? {};
|
final trainingExercises = trainerData['trainingExercises'] as Map<String, dynamic>? ?? {};
|
||||||
|
|
||||||
|
// 1. Wochentagsbasierte Trainings (wie gehabt)
|
||||||
trainingTimes.forEach((day, timeStr) {
|
trainingTimes.forEach((day, timeStr) {
|
||||||
|
// Prüfe, ob der Key KEIN Datum ist (also ein Wochentag)
|
||||||
|
if (DateTime.tryParse(day) != null) return;
|
||||||
if (timeStr == null) return;
|
if (timeStr == null) return;
|
||||||
|
|
||||||
final duration = trainingDurations[day] as int? ?? 60;
|
final duration = trainingDurations[day] as int? ?? 60;
|
||||||
final timeParts = (timeStr as String).split(':');
|
final timeParts = (timeStr as String).split(':');
|
||||||
if (timeParts.length != 2) return;
|
if (timeParts.length != 2) return;
|
||||||
|
|
||||||
final hour = int.tryParse(timeParts[0]) ?? 0;
|
final hour = int.tryParse(timeParts[0]) ?? 0;
|
||||||
final minute = int.tryParse(timeParts[1]) ?? 0;
|
final minute = int.tryParse(timeParts[1]) ?? 0;
|
||||||
|
|
||||||
|
|
@ -144,7 +145,6 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
final date = eventDate.add(Duration(days: i * 7));
|
final date = eventDate.add(Duration(days: i * 7));
|
||||||
final normalizedDate = DateTime(date.year, date.month, date.day);
|
final normalizedDate = DateTime(date.year, date.month, date.day);
|
||||||
final dateString = normalizedDate.toIso8601String();
|
final dateString = normalizedDate.toIso8601String();
|
||||||
|
|
||||||
final isCancelled = cancelledTrainings.any((cancelled) {
|
final isCancelled = cancelledTrainings.any((cancelled) {
|
||||||
if (cancelled is Map<String, dynamic>) {
|
if (cancelled is Map<String, dynamic>) {
|
||||||
final cancelledDate = DateTime.parse(cancelled['date'] as String);
|
final cancelledDate = DateTime.parse(cancelled['date'] as String);
|
||||||
|
|
@ -152,8 +152,11 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
// NEU: Prüfe, ob es ein datumsspezifisches Training für diesen Tag gibt
|
||||||
if (!isCancelled) {
|
final hasDateSpecific = trainingTimes.containsKey(dateString);
|
||||||
|
if (!isCancelled || hasDateSpecific) {
|
||||||
|
// Wenn es ein datumsspezifisches Training gibt, blende das wochentagsbasierte Training aus
|
||||||
|
if (isCancelled && hasDateSpecific) continue;
|
||||||
final exercises = trainingExercises[dateString] as List<dynamic>? ?? [];
|
final exercises = trainingExercises[dateString] as List<dynamic>? ?? [];
|
||||||
final totalExerciseDuration = exercises.fold<int>(0, (sum, exercise) {
|
final totalExerciseDuration = exercises.fold<int>(0, (sum, exercise) {
|
||||||
if (exercise is Map<String, dynamic>) {
|
if (exercise is Map<String, dynamic>) {
|
||||||
|
|
@ -161,7 +164,6 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
});
|
});
|
||||||
|
|
||||||
final event = {
|
final event = {
|
||||||
'trainerName': trainerData['name'] ?? 'Unbekannter Trainer',
|
'trainerName': trainerData['name'] ?? 'Unbekannter Trainer',
|
||||||
'time': timeStr,
|
'time': timeStr,
|
||||||
|
|
@ -174,7 +176,6 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
'remainingTime': duration - totalExerciseDuration,
|
'remainingTime': duration - totalExerciseDuration,
|
||||||
'club': trainerData['club'] ?? 'Kein Verein',
|
'club': trainerData['club'] ?? 'Kein Verein',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (events.containsKey(normalizedDate)) {
|
if (events.containsKey(normalizedDate)) {
|
||||||
events[normalizedDate]!.add(event);
|
events[normalizedDate]!.add(event);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -183,6 +184,47 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 2. Datumsspezifische Trainings (NEU)
|
||||||
|
trainingTimes.forEach((key, timeStr) {
|
||||||
|
// Prüfe, ob der Key ein Datum ist
|
||||||
|
final date = DateTime.tryParse(key);
|
||||||
|
if (date == null) return;
|
||||||
|
if (timeStr == null) return;
|
||||||
|
final duration = trainingDurations[key] 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 normalizedDate = DateTime(date.year, date.month, date.day);
|
||||||
|
final dateString = normalizedDate.toIso8601String();
|
||||||
|
// Für datumsspezifische Trainings: cancelledTrainings ignorieren!
|
||||||
|
// Event immer erzeugen
|
||||||
|
final exercises = trainingExercises[dateString] as List<dynamic>? ?? [];
|
||||||
|
final totalExerciseDuration = exercises.fold<int>(0, (sum, exercise) {
|
||||||
|
if (exercise is Map<String, dynamic>) {
|
||||||
|
return sum + (exercise['duration'] as int? ?? 0);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
});
|
||||||
|
final event = {
|
||||||
|
'trainerName': trainerData['name'] ?? 'Unbekannter Trainer',
|
||||||
|
'time': timeStr,
|
||||||
|
'duration': duration,
|
||||||
|
'trainerId': trainerDoc.id,
|
||||||
|
'isCurrentUser': trainerDoc.id == _currentUserId,
|
||||||
|
'day': key,
|
||||||
|
'date': dateString,
|
||||||
|
'exercises': exercises,
|
||||||
|
'remainingTime': duration - totalExerciseDuration,
|
||||||
|
'club': trainerData['club'] ?? 'Kein Verein',
|
||||||
|
};
|
||||||
|
if (events.containsKey(normalizedDate)) {
|
||||||
|
events[normalizedDate]!.add(event);
|
||||||
|
} else {
|
||||||
|
events[normalizedDate] = [event];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -269,9 +311,21 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
|
|
||||||
final data = userDoc.data() as Map<String, dynamic>;
|
final data = userDoc.data() as Map<String, dynamic>;
|
||||||
final cancelledTrainings = List<Map<String, dynamic>>.from(data['cancelledTrainings'] ?? []);
|
final cancelledTrainings = List<Map<String, dynamic>>.from(data['cancelledTrainings'] ?? []);
|
||||||
|
final trainingTimes = Map<String, dynamic>.from(data['trainingTimes'] ?? {});
|
||||||
|
final trainingDurations = Map<String, dynamic>.from(data['trainingDurations'] ?? {});
|
||||||
|
final trainingExercises = Map<String, dynamic>.from(data['trainingExercises'] ?? {});
|
||||||
|
|
||||||
|
// Stelle sicher, dass das Datum im richtigen Format gespeichert wird
|
||||||
|
final date = DateTime.parse(event['date']);
|
||||||
|
final normalizedDateString = DateTime(date.year, date.month, date.day).toIso8601String();
|
||||||
|
|
||||||
|
// Entferne ALLE Einträge für das Datum
|
||||||
|
trainingTimes.remove(normalizedDateString);
|
||||||
|
trainingDurations.remove(normalizedDateString);
|
||||||
|
trainingExercises.remove(normalizedDateString);
|
||||||
|
|
||||||
cancelledTrainings.add({
|
cancelledTrainings.add({
|
||||||
'date': event['date'],
|
'date': normalizedDateString,
|
||||||
'day': event['day'],
|
'day': event['day'],
|
||||||
'time': event['time'],
|
'time': event['time'],
|
||||||
'duration': event['duration'],
|
'duration': event['duration'],
|
||||||
|
|
@ -282,6 +336,9 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
.doc(_currentUserId)
|
.doc(_currentUserId)
|
||||||
.update({
|
.update({
|
||||||
'cancelledTrainings': cancelledTrainings,
|
'cancelledTrainings': cancelledTrainings,
|
||||||
|
'trainingTimes': trainingTimes,
|
||||||
|
'trainingDurations': trainingDurations,
|
||||||
|
'trainingExercises': trainingExercises,
|
||||||
});
|
});
|
||||||
|
|
||||||
await _loadEvents();
|
await _loadEvents();
|
||||||
|
|
@ -371,6 +428,7 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final isTrainer = _userRole == 'trainer';
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Kalender'),
|
title: const Text('Kalender'),
|
||||||
|
|
@ -449,17 +507,53 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (isTrainer && _selectedDay != null) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
label: const Text('Training an diesem Tag hinzufügen'),
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await showDialog<Map<String, dynamic>>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _TrainingEditDialog(
|
||||||
|
date: _selectedDay!,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result != null) {
|
||||||
|
await _addOrEditTraining(_selectedDay!, result['time'], result['duration'], isException: false);
|
||||||
|
await _loadEvents();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
const Divider(),
|
const Divider(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _isLoading
|
child: _isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: _selectedDay == null
|
: _selectedDay == null
|
||||||
? const Center(child: Text('Bitte wähle einen Tag aus'))
|
? const Center(child: Text('Bitte wähle einen Tag aus'))
|
||||||
: ListView.builder(
|
: (() {
|
||||||
|
final events = _getEventsForDay(_selectedDay!);
|
||||||
|
// Sortiere nach Uhrzeit (Format: 'HH:mm')
|
||||||
|
events.sort((a, b) {
|
||||||
|
final aTime = a['time'] as String? ?? '00:00';
|
||||||
|
final bTime = b['time'] as String? ?? '00:00';
|
||||||
|
final aParts = aTime.split(':').map(int.parse).toList();
|
||||||
|
final bParts = bTime.split(':').map(int.parse).toList();
|
||||||
|
final aMinutes = aParts[0] * 60 + aParts[1];
|
||||||
|
final bMinutes = bParts[0] * 60 + bParts[1];
|
||||||
|
return aMinutes.compareTo(bMinutes);
|
||||||
|
});
|
||||||
|
return ListView.builder(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
itemCount: _getEventsForDay(_selectedDay!).length,
|
itemCount: events.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final event = _getEventsForDay(_selectedDay!)[index];
|
final event = events[index];
|
||||||
final isCurrentUser = event['isCurrentUser'] as bool;
|
final isCurrentUser = event['isCurrentUser'] as bool;
|
||||||
final exercises = event['exercises'] as List<dynamic>;
|
final exercises = event['exercises'] as List<dynamic>;
|
||||||
final remainingTime = event['remainingTime'] as int;
|
final remainingTime = event['remainingTime'] as int;
|
||||||
|
|
@ -486,6 +580,24 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
if (isCurrentUser)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.edit),
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await showDialog<Map<String, dynamic>>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _TrainingEditDialog(
|
||||||
|
date: _selectedDay!,
|
||||||
|
initialTime: event['time'],
|
||||||
|
initialDuration: event['duration'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (result != null) {
|
||||||
|
await _addOrEditTraining(_selectedDay!, result['time'], result['duration'], isException: true);
|
||||||
|
await _loadEvents();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
if (isCurrentUser)
|
if (isCurrentUser)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
|
|
@ -602,32 +714,6 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isCurrentUser)
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.delete, color: Colors.red, size: 20),
|
|
||||||
onPressed: () {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('Übung entfernen'),
|
|
||||||
content: const Text('Möchten Sie diese Übung wirklich entfernen?'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: const Text('Abbrechen'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
_removeExercise(event, exercise);
|
|
||||||
},
|
|
||||||
child: const Text('Entfernen', style: TextStyle(color: Colors.red)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -641,11 +727,148 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
})()
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _addOrEditTraining(DateTime date, String time, int duration, {bool isException = false}) async {
|
||||||
|
// Trainingsdatum als String
|
||||||
|
final dateString = DateTime(date.year, date.month, date.day).toIso8601String();
|
||||||
|
final userDoc = await FirebaseFirestore.instance.collection('User').doc(_currentUserId).get();
|
||||||
|
final data = userDoc.data() ?? {};
|
||||||
|
final trainingExercises = Map<String, dynamic>.from(data['trainingExercises'] ?? {});
|
||||||
|
final trainingTimes = Map<String, dynamic>.from(data['trainingTimes'] ?? {});
|
||||||
|
final trainingDurations = Map<String, dynamic>.from(data['trainingDurations'] ?? {});
|
||||||
|
|
||||||
|
// Entferne nur das Training für das konkrete Datum
|
||||||
|
trainingExercises.remove(dateString);
|
||||||
|
trainingTimes.remove(dateString);
|
||||||
|
trainingDurations.remove(dateString);
|
||||||
|
|
||||||
|
// Neues Training speichern (nur mit Datum als Key)
|
||||||
|
trainingExercises[dateString] = [];
|
||||||
|
trainingTimes[dateString] = time;
|
||||||
|
trainingDurations[dateString] = duration;
|
||||||
|
|
||||||
|
// cancelledTrainings bereinigen und ggf. Eintrag hinzufügen, wenn an diesem Tag ein wochentagsbasiertes Training existiert
|
||||||
|
final cancelledTrainings = List<Map<String, dynamic>>.from(data['cancelledTrainings'] ?? []);
|
||||||
|
cancelledTrainings.removeWhere((cancelled) =>
|
||||||
|
cancelled is Map<String, dynamic> &&
|
||||||
|
cancelled.containsKey('date') &&
|
||||||
|
cancelled['date'] == dateString
|
||||||
|
);
|
||||||
|
|
||||||
|
// Prüfe, ob für diesen Tag ein wochentagsbasiertes Training existiert und ob es eine Ausnahme ist
|
||||||
|
final weekdayNames = [
|
||||||
|
'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'
|
||||||
|
];
|
||||||
|
final weekdayKey = weekdayNames[date.weekday - 1];
|
||||||
|
if (isException && trainingTimes.containsKey(weekdayKey)) {
|
||||||
|
cancelledTrainings.add({
|
||||||
|
'date': dateString,
|
||||||
|
'day': weekdayKey,
|
||||||
|
'time': trainingTimes[weekdayKey],
|
||||||
|
'duration': trainingDurations[weekdayKey] ?? 60,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await FirebaseFirestore.instance.collection('User').doc(_currentUserId).update({
|
||||||
|
'trainingExercises': trainingExercises,
|
||||||
|
'trainingTimes': trainingTimes,
|
||||||
|
'trainingDurations': trainingDurations,
|
||||||
|
'cancelledTrainings': cancelledTrainings,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TrainingEditDialog extends StatefulWidget {
|
||||||
|
final DateTime date;
|
||||||
|
final String? initialTime;
|
||||||
|
final int? initialDuration;
|
||||||
|
const _TrainingEditDialog({required this.date, this.initialTime, this.initialDuration});
|
||||||
|
@override
|
||||||
|
State<_TrainingEditDialog> createState() => _TrainingEditDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TrainingEditDialogState extends State<_TrainingEditDialog> {
|
||||||
|
TimeOfDay? _selectedTime;
|
||||||
|
int _duration = 60;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
if (widget.initialTime != null) {
|
||||||
|
final parts = widget.initialTime!.split(':');
|
||||||
|
if (parts.length == 2) {
|
||||||
|
_selectedTime = TimeOfDay(hour: int.parse(parts[0]), minute: int.parse(parts[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (widget.initialDuration != null) {
|
||||||
|
_duration = widget.initialDuration!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('Training bearbeiten (${widget.date.day}.${widget.date.month}.${widget.date.year})'),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.access_time),
|
||||||
|
title: const Text('Uhrzeit wählen'),
|
||||||
|
subtitle: Text(_selectedTime != null ? _selectedTime!.format(context) : 'Keine Uhrzeit gewählt'),
|
||||||
|
onTap: () async {
|
||||||
|
final picked = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: _selectedTime ?? TimeOfDay.now(),
|
||||||
|
);
|
||||||
|
if (picked != null) {
|
||||||
|
setState(() => _selectedTime = picked);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
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: _selectedTime != null
|
||||||
|
? () {
|
||||||
|
final timeString = _selectedTime!.hour.toString().padLeft(2, '0') + ':' + _selectedTime!.minute.toString().padLeft(2, '0');
|
||||||
|
Navigator.pop(context, {'time': timeString, 'duration': _duration});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Text('Speichern'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,65 @@ class _ProfileTabState extends State<ProfileTab> {
|
||||||
|
|
||||||
final timeString = '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}';
|
final timeString = '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}';
|
||||||
|
|
||||||
|
// Update training times and durations
|
||||||
await FirebaseFirestore.instance.collection('User').doc(user.uid).update({
|
await FirebaseFirestore.instance.collection('User').doc(user.uid).update({
|
||||||
'trainingTimes.$day': timeString,
|
'trainingTimes.$day': timeString,
|
||||||
'trainingDurations.$day': duration,
|
'trainingDurations.$day': duration,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Trainings ab 1. Januar des aktuellen Jahres bis 52 Wochen in die Zukunft anlegen
|
||||||
|
final now = DateTime.now();
|
||||||
|
final yearStart = DateTime(now.year, 1, 1);
|
||||||
|
final weekdays = {
|
||||||
|
'Montag': 1,
|
||||||
|
'Dienstag': 2,
|
||||||
|
'Mittwoch': 3,
|
||||||
|
'Donnerstag': 4,
|
||||||
|
'Freitag': 5,
|
||||||
|
'Samstag': 6,
|
||||||
|
'Sonntag': 7,
|
||||||
|
};
|
||||||
|
final targetWeekday = weekdays[day] ?? 1;
|
||||||
|
|
||||||
|
// Finde das erste gewünschte Wochentags-Datum ab Jahresanfang
|
||||||
|
DateTime firstDate = yearStart;
|
||||||
|
while (firstDate.weekday != targetWeekday) {
|
||||||
|
firstDate = firstDate.add(const Duration(days: 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
final newTrainingDates = <String>[];
|
||||||
|
for (var i = 0; i < 52; i++) {
|
||||||
|
final date = firstDate.add(Duration(days: i * 7));
|
||||||
|
final normalizedDate = DateTime(date.year, date.month, date.day, time.hour, time.minute);
|
||||||
|
final dateString = DateTime(normalizedDate.year, normalizedDate.month, normalizedDate.day).toIso8601String();
|
||||||
|
newTrainingDates.add(dateString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load existing trainingExercises and cancelledTrainings
|
||||||
|
final userDoc = await FirebaseFirestore.instance.collection('User').doc(user.uid).get();
|
||||||
|
final data = userDoc.data() ?? {};
|
||||||
|
final trainingExercises = Map<String, dynamic>.from(data['trainingExercises'] ?? {});
|
||||||
|
final cancelledTrainings = List<Map<String, dynamic>>.from(data['cancelledTrainings'] ?? []);
|
||||||
|
|
||||||
|
// Add empty training only if not already present
|
||||||
|
for (final dateString in newTrainingDates) {
|
||||||
|
if (!trainingExercises.containsKey(dateString)) {
|
||||||
|
trainingExercises[dateString] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove cancelledTrainings for these dates
|
||||||
|
cancelledTrainings.removeWhere((cancelled) =>
|
||||||
|
cancelled is Map<String, dynamic> &&
|
||||||
|
cancelled.containsKey('date') &&
|
||||||
|
newTrainingDates.contains(cancelled['date'])
|
||||||
|
);
|
||||||
|
|
||||||
|
await FirebaseFirestore.instance.collection('User').doc(user.uid).update({
|
||||||
|
'cancelledTrainings': cancelledTrainings,
|
||||||
|
'trainingExercises': trainingExercises,
|
||||||
|
});
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_trainingTimes[day] = time;
|
_trainingTimes[day] = time;
|
||||||
_trainingDurations[day] = duration;
|
_trainingDurations[day] = duration;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue