Favoriten hinzufügen ermöglicht
parent
59b13d21e2
commit
a15259ecd2
|
@ -17,9 +17,9 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_selectedDay = DateTime.now();
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
_focusedDay = DateTime(now.year, now.month, now.day);
|
_focusedDay = DateTime(now.year, now.month, now.day);
|
||||||
_selectedDay = _focusedDay;
|
|
||||||
|
|
||||||
// Beispiel-Events
|
// Beispiel-Events
|
||||||
_events = {
|
_events = {
|
||||||
|
@ -43,8 +43,8 @@ class _CalendarTabState extends State<CalendarTab> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final firstDay = DateTime.utc(2024, 1, 1);
|
final firstDay = DateTime.utc(1900, 1, 1);
|
||||||
final lastDay = DateTime.utc(2024, 12, 31);
|
final lastDay = DateTime.utc(2999, 12, 31);
|
||||||
|
|
||||||
if (_focusedDay.isBefore(firstDay)) {
|
if (_focusedDay.isBefore(firstDay)) {
|
||||||
_focusedDay = firstDay;
|
_focusedDay = firstDay;
|
||||||
|
|
|
@ -1,179 +1,98 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||||
|
import 'package:firebase_auth/firebase_auth.dart';
|
||||||
|
|
||||||
class FavoritesTab extends StatelessWidget {
|
class FavoritesTab extends StatelessWidget {
|
||||||
const FavoritesTab({super.key});
|
const FavoritesTab({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Beispiel-Daten für favorisierte Trainings
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
final List<Map<String, dynamic>> favoriteWorkouts = [
|
if (user == null) {
|
||||||
{
|
return const Center(child: Text('Nicht eingeloggt'));
|
||||||
'title': 'Ganzkörper Workout',
|
}
|
||||||
'duration': '45 Minuten',
|
|
||||||
'level': 'Fortgeschritten',
|
|
||||||
'category': 'Krafttraining',
|
|
||||||
'isFavorite': true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Yoga Flow',
|
|
||||||
'duration': '30 Minuten',
|
|
||||||
'level': 'Anfänger',
|
|
||||||
'category': 'Yoga',
|
|
||||||
'isFavorite': true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'HIIT Session',
|
|
||||||
'duration': '20 Minuten',
|
|
||||||
'level': 'Mittel',
|
|
||||||
'category': 'HIIT',
|
|
||||||
'isFavorite': true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Favoriten'),
|
title: const Text('Favoriten'),
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.sort),
|
|
||||||
onPressed: () {
|
|
||||||
// TODO: Implement sorting functionality
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
body: StreamBuilder<DocumentSnapshot>(
|
||||||
),
|
stream: FirebaseFirestore.instance.collection('User').doc(user.uid).snapshots(),
|
||||||
body:
|
builder: (context, snapshot) {
|
||||||
favoriteWorkouts.isEmpty
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
? const Center(
|
return const Center(child: CircularProgressIndicator());
|
||||||
child: Column(
|
}
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
if (!snapshot.hasData || !snapshot.data!.exists) {
|
||||||
children: [
|
return const Center(child: Text('Keine Favoriten gefunden'));
|
||||||
Icon(Icons.favorite_border, size: 64, color: Colors.grey),
|
}
|
||||||
SizedBox(height: 16),
|
final data = snapshot.data!.data() as Map<String, dynamic>;
|
||||||
Text(
|
final favorites = List<String>.from(data['favorites'] ?? []);
|
||||||
'Noch keine Favoriten',
|
|
||||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
if (favorites.isEmpty) {
|
||||||
),
|
return const Center(child: Text('Keine Favoriten gefunden'));
|
||||||
SizedBox(height: 8),
|
}
|
||||||
Text(
|
|
||||||
'Füge Trainings zu deinen Favoriten hinzu',
|
return ListView.builder(
|
||||||
style: TextStyle(fontSize: 14, color: Colors.grey),
|
itemCount: favorites.length,
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: ListView.builder(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
itemCount: favoriteWorkouts.length,
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final workout = favoriteWorkouts[index];
|
return FutureBuilder<DocumentSnapshot>(
|
||||||
|
future: FirebaseFirestore.instance.collection('Training').doc(favorites[index]).get(),
|
||||||
|
builder: (context, trainingSnapshot) {
|
||||||
|
if (!trainingSnapshot.hasData || !trainingSnapshot.data!.exists) {
|
||||||
|
return const ListTile(title: Text('Training nicht gefunden'));
|
||||||
|
}
|
||||||
|
final trainingData = trainingSnapshot.data!.data() as Map<String, dynamic>;
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.only(bottom: 16),
|
margin: const EdgeInsets.all(8.0),
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
// TODO: Navigate to workout details
|
|
||||||
},
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: 80,
|
|
||||||
height: 80,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey[200],
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.fitness_center,
|
|
||||||
size: 32,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
workout['title'],
|
trainingData['title'] ?? 'Unbekannt',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
workout['duration'],
|
trainingData['description'] ?? 'Keine Beschreibung',
|
||||||
style: TextStyle(color: Colors.grey[600]),
|
style: TextStyle(color: Colors.grey[600]),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'Dauer: ${trainingData['duration'] ?? '-'} Minuten',
|
||||||
|
style: TextStyle(color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Text(
|
||||||
padding: const EdgeInsets.symmetric(
|
'Level: ${trainingData['year'] ?? '-'}',
|
||||||
horizontal: 8,
|
style: TextStyle(color: Colors.grey[600]),
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.blue[100],
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
workout['level'],
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.blue[700],
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.green[100],
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
workout['category'],
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.green[700],
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: const Icon(Icons.favorite, color: Colors.red),
|
||||||
workout['isFavorite']
|
onPressed: () async {
|
||||||
? Icons.favorite
|
await FirebaseFirestore.instance.collection('User').doc(user.uid).update({
|
||||||
: Icons.favorite_border,
|
'favorites': FieldValue.arrayRemove([favorites[index]]),
|
||||||
color:
|
});
|
||||||
workout['isFavorite']
|
|
||||||
? Colors.red
|
|
||||||
: Colors.grey,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
// TODO: Implement favorite toggle
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,25 +76,6 @@ class ProfileTab extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildInfoCard(
|
|
||||||
title: 'Statistiken',
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
_buildStatisticRow(
|
|
||||||
'Trainings absolviert',
|
|
||||||
userData['workoutsCompleted'].toString(),
|
|
||||||
Icons.fitness_center,
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
_buildStatisticRow(
|
|
||||||
'Gesamtzeit',
|
|
||||||
'${userData['totalMinutes']} Minuten',
|
|
||||||
Icons.timer,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
_buildInfoCard(
|
_buildInfoCard(
|
||||||
title: 'Persönliche Informationen',
|
title: 'Persönliche Informationen',
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -183,20 +164,6 @@ class ProfileTab extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatisticRow(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: const TextStyle(fontWeight: FontWeight.bold)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildInfoRow(String label, String value, IconData icon) {
|
Widget _buildInfoRow(String label, String value, IconData icon) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
||||||
|
|
|
@ -12,17 +12,18 @@ class SearchTab extends StatefulWidget {
|
||||||
class _SearchTabState extends State<SearchTab> {
|
class _SearchTabState extends State<SearchTab> {
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
final List<String> _categories = [
|
final List<String> _categories = [
|
||||||
'Krafttraining',
|
'Aufwärmen & Mobilisation',
|
||||||
'Ausdauer',
|
'Wurf- & Torabschluss',
|
||||||
'Yoga',
|
'Torwarttraining',
|
||||||
'HIIT',
|
'Athletik',
|
||||||
'Mobility',
|
'Pass',
|
||||||
'Rehabilitation',
|
'Koordination',
|
||||||
];
|
];
|
||||||
String? _selectedCategory;
|
String? _selectedCategory;
|
||||||
String _searchTerm = '';
|
String _searchTerm = '';
|
||||||
bool _isTrainer = false;
|
bool _isTrainer = false;
|
||||||
bool _trainerChecked = false;
|
bool _trainerChecked = false;
|
||||||
|
Set<String> _favorites = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -33,6 +34,7 @@ class _SearchTabState extends State<SearchTab> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
_checkIfTrainer();
|
_checkIfTrainer();
|
||||||
|
_loadFavorites();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _checkIfTrainer() async {
|
Future<void> _checkIfTrainer() async {
|
||||||
|
@ -45,6 +47,18 @@ class _SearchTabState extends State<SearchTab> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _loadFavorites() async {
|
||||||
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
if (user == null) return;
|
||||||
|
final doc = await FirebaseFirestore.instance.collection('User').doc(user.uid).get();
|
||||||
|
final data = doc.data();
|
||||||
|
if (data != null && data['favorites'] != null) {
|
||||||
|
setState(() {
|
||||||
|
_favorites = Set<String>.from(data['favorites']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _showCreateTrainingDialog() {
|
void _showCreateTrainingDialog() {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -52,6 +66,21 @@ class _SearchTabState extends State<SearchTab> {
|
||||||
).then((_) => setState(() {})); // Refresh nach Hinzufügen
|
).then((_) => setState(() {})); // Refresh nach Hinzufügen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _toggleFavorite(String trainingId, bool isFavorite) async {
|
||||||
|
final user = FirebaseAuth.instance.currentUser;
|
||||||
|
if (user == null) return;
|
||||||
|
if (isFavorite) {
|
||||||
|
await FirebaseFirestore.instance.collection('User').doc(user.uid).update({
|
||||||
|
'favorites': FieldValue.arrayRemove([trainingId]),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await FirebaseFirestore.instance.collection('User').doc(user.uid).update({
|
||||||
|
'favorites': FieldValue.arrayUnion([trainingId]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await _loadFavorites(); // Aktualisiere die Favoriten nach dem Toggle
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -148,6 +177,7 @@ class _SearchTabState extends State<SearchTab> {
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate((context, index) {
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
final data = docs[index].data() as Map<String, dynamic>;
|
final data = docs[index].data() as Map<String, dynamic>;
|
||||||
|
final isFavorite = _favorites.contains(docs[index].id);
|
||||||
return Card(
|
return Card(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -207,6 +237,17 @@ class _SearchTabState extends State<SearchTab> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text('Level: ${data['year'] ?? '-'}'),
|
Text('Level: ${data['year'] ?? '-'}'),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.bottomRight,
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
isFavorite ? Icons.favorite : Icons.favorite_border,
|
||||||
|
color: isFavorite ? Colors.red : null,
|
||||||
|
),
|
||||||
|
onPressed: () => _toggleFavorite(docs[index].id, isFavorite),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue