Shuffle vorbereitungen

This commit is contained in:
MarcWieland
2025-12-10 23:14:38 +01:00
parent e636f282ee
commit 41a4b2481a
8 changed files with 423 additions and 11 deletions

View File

@@ -4,6 +4,7 @@ import '../../data/models/player_model.dart';
import '../provider/active_players_provider.dart';
import '../provider/player_provider.dart'; // für awardWinToPlayers
import '../widgets/volleyball_field_widget.dart';
import 'package:flutter/services.dart';
class FieldsScreen extends ConsumerWidget {
const FieldsScreen({super.key});
@@ -66,13 +67,14 @@ class FieldsScreen extends ConsumerWidget {
),
onPressed: teamA.isEmpty
? null
: () {
: () async {
await HapticFeedback.mediumImpact();
ref.read(playerListProvider.notifier).awardWinToPlayers(teamA);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Oben gewinnt! +1 Schleifchen für ${teamA.length} Spieler'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 2),
duration: const Duration(seconds: 1),
),
);
},
@@ -93,13 +95,14 @@ class FieldsScreen extends ConsumerWidget {
),
onPressed: teamB.isEmpty
? null
: () {
: () async{
HapticFeedback.mediumImpact();
ref.read(playerListProvider.notifier).awardWinToPlayers(teamB);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Unten gewinnt! +1 Schleifchen für ${teamB.length} Spieler'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 2),
duration: const Duration(seconds: 1),
),
);
},
@@ -144,7 +147,8 @@ class FieldsScreen extends ConsumerWidget {
child: ElevatedButton.icon(
icon: const Icon(Icons.shuffle),
label: const Text('Neu mischen', style: TextStyle(fontSize: 18)),
onPressed: () {
onPressed: () async{
HapticFeedback.mediumImpact();
ref.invalidate(activePlayersProvider);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Neue Teams gemischt!'), duration: Duration(milliseconds: 100)),

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:schleifchenturnier/features/tournament/presentation/screens/fields_screen.dart';
import 'package:schleifchenturnier/features/tournament/presentation/screens/stats_screen.dart';
import 'package:schleifchenturnier/features/tournament/presentation/screens/timer_setup_screen.dart';
import 'player_management_screen.dart'; // wird gleich erstellt
// Später: timer_screen.dart, fields_screen.dart, stats_screen.dart
import 'player_management_screen.dart';
import 'timer_setup_screen.dart';
import 'fields_screen.dart';
import 'stats_screen.dart';
import 'settings_screen.dart';
class HomeScreen extends ConsumerStatefulWidget {
const HomeScreen({super.key});
@@ -20,7 +20,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
PlayerManagementScreen(),
TimerSetupScreen(),
FieldsScreen(),
StatsScreen()
StatsScreen(),
];
void _onTabTapped(int index) {
@@ -29,6 +29,11 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
});
}
// Zeigt das Zahnrad nur auf Spieler- und Statistik-Tab
bool _showSettingsIcon() {
return _selectedIndex == 0 || _selectedIndex == 3;
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -36,12 +41,28 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
title: const Text('Schleifchenturnier'),
centerTitle: true,
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
foregroundColor: Theme.of(context).colorScheme.onPrimaryContainer,
elevation: 4,
actions: _showSettingsIcon()
? [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const SettingsScreen()),
);
},
),
]
: null,
),
body: _screens[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _selectedIndex,
onTap: _onTabTapped,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Colors.grey.shade600,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.people), label: 'Spieler'),
BottomNavigationBarItem(icon: Icon(Icons.timer), label: 'Timer'),

View File

@@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:schleifchenturnier/features/tournament/presentation/screens/shuffle_settings_screen.dart';
import '../provider/player_provider.dart';
class SettingsScreen extends ConsumerWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text('Einstellungen'),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const SizedBox(height: 40),
// Zurücksetzen der Siege
Card(
child: ListTile(
leading: const Icon(Icons.restore, color: Colors.orange, size: 32),
title: const Text(
'Alle Siege zurücksetzen',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
subtitle: const Text('Setzt die Schleifchen-Anzahl aller Spieler auf 0'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: () {
_showResetConfirmationDialog(context, ref);
},
),
),
Card(
child: ListTile(
leading: const Icon(Icons.shuffle, color: Colors.deepPurple, size: 32),
title: const Text('Shuffle-Einstellungen', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
subtitle: const Text('Modus und Balance-Optionen konfigurieren'),
trailing: const Icon(Icons.arrow_forward_ios),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => const ShuffleSettingsScreen()));
},
),
),
const Spacer(),
// Version oder Footer
const Text(
'Schleifchenturnier v1.0\nMade with ❤️ für die beste Volleyball-Crew',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey, fontSize: 14),
),
const SizedBox(height: 20),
],
),
),
);
}
void _showResetConfirmationDialog(BuildContext context, WidgetRef ref) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Wirklich alle Siege zurücksetzen?'),
content: const Text(
'Dadurch werden alle Schleifchen (Siege) aller Spieler auf 0 gesetzt.\n\nDas kann nicht rückgängig gemacht werden!',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('Abbrechen'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () {
ref.read(playerListProvider.notifier).resetAllWins();
Navigator.pop(ctx);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Alle Siege wurden zurückgesetzt!'),
backgroundColor: Colors.orange,
),
);
},
child: const Text('Zurücksetzen'),
),
],
),
);
}
}

View File

@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../provider/shuffle_settings_provider.dart';
class ShuffleSettingsScreen extends ConsumerWidget {
const ShuffleSettingsScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final settings = ref.watch(shuffleSettingsProvider);
return Scaffold(
appBar: AppBar(
title: const Text('Shuffle-Einstellungen'),
centerTitle: true,
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
const Text(
'Shuffle-Modus',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
RadioListTile<ShuffleMode>(
title: const Text('Random'),
subtitle: const Text('Einfach zufällig mischen'),
value: ShuffleMode.random,
groupValue: settings.mode,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(mode: val),
),
RadioListTile<ShuffleMode>(
title: const Text('Ausgewogen'),
subtitle: const Text('Gute Balance von Geschlecht und Level'),
value: ShuffleMode.balanced,
groupValue: settings.mode,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(mode: val),
),
RadioListTile<ShuffleMode>(
title: const Text('Aggressiv ausgewogen'),
subtitle: const Text('Strenge Regeln perfekte Teams oder gar nicht'),
value: ShuffleMode.aggressive,
groupValue: settings.mode,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(mode: val),
),
RadioListTile<ShuffleMode>(
title: const Text('Positionsbasiert'),
subtitle: const Text('Versucht ideale Aufstellung: 1 Zuspieler, 2 Außen, etc.'),
value: ShuffleMode.positionBased,
groupValue: settings.mode,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(mode: val),
),
const Divider(height: 40),
const Text(
'Zusätzliche Optionen',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
SwitchListTile(
title: const Text('Geschlechterbalance priorisieren'),
subtitle: const Text('Versucht 3M/3F pro Team'),
value: settings.prioritizeGenderBalance,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(prioritizeGenderBalance: val),
),
SwitchListTile(
title: const Text('Level-Balance priorisieren'),
subtitle: const Text('Ähnliche Spielstärke pro Team'),
value: settings.prioritizeLevelBalance,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(prioritizeLevelBalance: val),
),
SwitchListTile(
title: const Text('Positionsbesetzung beachten'),
subtitle: const Text('Ideale Aufstellung pro Team versuchen'),
value: settings.usePositions,
onChanged: (val) => ref.read(shuffleSettingsProvider.notifier).update(usePositions: val),
),
],
),
);
}
}