Compare commits
2 Commits
fe7a788a9d
...
bebb10e4c2
Author | SHA1 | Date |
---|---|---|
|
bebb10e4c2 | |
|
55c01a68a4 |
|
@ -0,0 +1,4 @@
|
||||||
|
@echo off
|
||||||
|
git add .
|
||||||
|
git commit -m "Implementiere alle Tabs der App: Search, Favorites, Calendar und Profile"
|
||||||
|
git push
|
|
@ -1,17 +1,174 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:table_calendar/table_calendar.dart';
|
||||||
|
|
||||||
class CalendarTab extends StatelessWidget {
|
class CalendarTab extends StatefulWidget {
|
||||||
const CalendarTab({super.key});
|
const CalendarTab({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CalendarTab> createState() => _CalendarTabState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CalendarTabState extends State<CalendarTab> {
|
||||||
|
CalendarFormat _calendarFormat = CalendarFormat.month;
|
||||||
|
DateTime _focusedDay = DateTime.now();
|
||||||
|
DateTime? _selectedDay;
|
||||||
|
Map<DateTime, List<Map<String, dynamic>>> _events = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final now = DateTime.now();
|
||||||
|
_focusedDay = DateTime(now.year, now.month, now.day);
|
||||||
|
_selectedDay = _focusedDay;
|
||||||
|
|
||||||
|
// 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'},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> _getEventsForDay(DateTime day) {
|
||||||
|
return _events[DateTime(day.year, day.month, day.day)] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
final firstDay = DateTime.utc(2024, 1, 1);
|
||||||
child: Center(
|
final lastDay = DateTime.utc(2024, 12, 31);
|
||||||
child: Text(
|
|
||||||
'Kalender',
|
if (_focusedDay.isBefore(firstDay)) {
|
||||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
_focusedDay = firstDay;
|
||||||
),
|
} else if (_focusedDay.isAfter(lastDay)) {
|
||||||
|
_focusedDay = lastDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Trainingsplan'),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement add workout to calendar
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,176 @@ class FavoritesTab extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
// Beispiel-Daten für favorisierte Trainings
|
||||||
child: Center(
|
final List<Map<String, dynamic>> favoriteWorkouts = [
|
||||||
child: Text(
|
{
|
||||||
'Favoriten',
|
'title': 'Ganzkörper Workout',
|
||||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
'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(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Favoriten'),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.sort),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement sorting functionality
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
body:
|
||||||
|
favoriteWorkouts.isEmpty
|
||||||
|
? const Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.favorite_border, size: 64, color: Colors.grey),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'Noch keine Favoriten',
|
||||||
|
style: TextStyle(fontSize: 18, color: Colors.grey),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'Füge Trainings zu deinen Favoriten hinzu',
|
||||||
|
style: TextStyle(fontSize: 14, color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ListView.builder(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
itemCount: favoriteWorkouts.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final workout = favoriteWorkouts[index];
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
// TODO: Navigate to workout details
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
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(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
workout['title'],
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
workout['duration'],
|
||||||
|
style: TextStyle(color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
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(
|
||||||
|
icon: Icon(
|
||||||
|
workout['isFavorite']
|
||||||
|
? Icons.favorite
|
||||||
|
: Icons.favorite_border,
|
||||||
|
color:
|
||||||
|
workout['isFavorite']
|
||||||
|
? Colors.red
|
||||||
|
: Colors.grey,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement favorite toggle
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,10 +72,7 @@ class HomeTab extends StatelessWidget {
|
||||||
title: 'Passen',
|
title: 'Passen',
|
||||||
icon: Icons.sports_volleyball,
|
icon: Icons.sports_volleyball,
|
||||||
),
|
),
|
||||||
CategoryCircle(
|
CategoryCircle(title: 'Torhüter', icon: Icons.sports_soccer),
|
||||||
title: 'Torhüter',
|
|
||||||
icon: Icons.sports_soccer,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -118,4 +115,4 @@ class HomeTab extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,180 @@ class ProfileTab extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
// Beispiel-Benutzerdaten
|
||||||
child: Center(
|
final Map<String, dynamic> userData = {
|
||||||
child: Text(
|
'name': 'Max Mustermann',
|
||||||
'Profil',
|
'email': 'max.mustermann@example.com',
|
||||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
'level': 'Fortgeschritten',
|
||||||
),
|
'joinedDate': '01.01.2024',
|
||||||
|
'workoutsCompleted': 42,
|
||||||
|
'totalMinutes': 1260,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
body: 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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
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(
|
||||||
|
title: 'Persönliche Informationen',
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildInfoRow('E-Mail', userData['email'], Icons.email),
|
||||||
|
const Divider(),
|
||||||
|
_buildInfoRow('Level', userData['level'], Icons.star),
|
||||||
|
const Divider(),
|
||||||
|
_buildInfoRow(
|
||||||
|
'Mitglied seit',
|
||||||
|
userData['joinedDate'],
|
||||||
|
Icons.calendar_today,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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) {
|
||||||
|
// TODO: Implement notification settings
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.dark_mode),
|
||||||
|
title: const Text('Dark Mode'),
|
||||||
|
trailing: Switch(
|
||||||
|
value: false,
|
||||||
|
onChanged: (value) {
|
||||||
|
// TODO: Implement dark mode
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.language),
|
||||||
|
title: const Text('Sprache'),
|
||||||
|
trailing: const Text('Deutsch'),
|
||||||
|
onTap: () {
|
||||||
|
// TODO: Implement language selection
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Center(
|
||||||
|
child: TextButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement logout
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.logout),
|
||||||
|
label: const Text('Abmelden'),
|
||||||
|
style: TextButton.styleFrom(foregroundColor: Colors.red),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
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 _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) {
|
||||||
|
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])),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,17 +1,131 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SearchTab extends StatelessWidget {
|
class SearchTab extends StatefulWidget {
|
||||||
const SearchTab({super.key});
|
const SearchTab({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SearchTab> createState() => _SearchTabState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchTabState extends State<SearchTab> {
|
||||||
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
final List<String> _categories = [
|
||||||
|
'Krafttraining',
|
||||||
|
'Ausdauer',
|
||||||
|
'Yoga',
|
||||||
|
'HIIT',
|
||||||
|
'Mobility',
|
||||||
|
'Rehabilitation',
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
return Scaffold(
|
||||||
child: Center(
|
body: CustomScrollView(
|
||||||
child: Text(
|
slivers: [
|
||||||
'Suche',
|
SliverAppBar(
|
||||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
floating: true,
|
||||||
),
|
title: TextField(
|
||||||
|
controller: _searchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Suche nach Training...',
|
||||||
|
border: InputBorder.none,
|
||||||
|
prefixIcon: const Icon(Icons.search),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
onPressed: () => _searchController.clear(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Kategorien',
|
||||||
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children:
|
||||||
|
_categories.map((category) {
|
||||||
|
return FilterChip(
|
||||||
|
label: Text(category),
|
||||||
|
onSelected: (bool selected) {
|
||||||
|
// TODO: Implement category filtering
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
sliver: SliverGrid(
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
mainAxisSpacing: 16,
|
||||||
|
crossAxisSpacing: 16,
|
||||||
|
childAspectRatio: 0.75,
|
||||||
|
),
|
||||||
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
|
return Card(
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
child: const Center(
|
||||||
|
child: Icon(Icons.fitness_center, size: 40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Training ${index + 1}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
'${30 + index * 5} Minuten',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, childCount: 6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_searchController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -104,6 +104,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
intl:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.20.2"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -176,6 +184,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
version: "2.1.8"
|
||||||
|
simple_gesture_detector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: simple_gesture_detector
|
||||||
|
sha256: ba2cd5af24ff20a0b8d609cec3f40e5b0744d2a71804a2616ae086b9c19d19a3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -213,6 +229,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.4.1"
|
||||||
|
table_calendar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: table_calendar
|
||||||
|
sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -35,6 +35,7 @@ dependencies:
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
firebase_core: ^3.13.0
|
firebase_core: ^3.13.0
|
||||||
|
table_calendar: ^3.0.9
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -59,9 +60,9 @@ flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
assets:
|
||||||
# - images/a_dot_burr.jpeg
|
- images/
|
||||||
# - images/a_dot_ham.jpeg
|
- images/prototype/
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/to/resolution-aware-images
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
Loading…
Reference in New Issue