Fixed bug for games showing round number 1 in main menu after creating

This commit is contained in:
2025-06-11 15:27:34 +02:00
parent c7c48d6022
commit 0374678b91
4 changed files with 184 additions and 156 deletions

View File

@@ -11,6 +11,9 @@ class GameManager extends ChangeNotifier {
/// It also saves the updated game sessions to local storage.
/// Returns the index of the newly added session in the sorted list.
Future<int> addGameSession(GameSession session) async {
session.addListener(() {
notifyListeners(); // Propagate session changes
});
gameList.add(session);
print(
'[game_manager.dart] Added game session: ${session.gameTitle} at ${session.createdAt}');
@@ -28,6 +31,7 @@ class GameManager extends ChangeNotifier {
/// sorts the list in descending order based on the creation date, and notifies listeners of the change.
/// It also saves the updated game sessions to local storage.
void removeGameSession(int index) {
gameList[index].removeListener(notifyListeners);
gameList.removeAt(index);
notifyListeners();
LocalStorageService.saveGameSessions();

View File

@@ -11,7 +11,7 @@ import 'package:flutter/cupertino.dart';
/// [roundNumber] is the current round number.
/// [isGameFinished] is a boolean indicating if the game has ended yet.
/// [winner] is the name of the player who won the game.
class GameSession {
class GameSession extends ChangeNotifier {
final DateTime createdAt;
final String gameTitle;
final List<String> players;
@@ -222,6 +222,7 @@ class GameSession {
} else {
roundList[roundNum - 1] = newRound;
}
notifyListeners();
}
/// This method updates the points of each player after a round.
@@ -248,6 +249,7 @@ class GameSession {
}
}
}
notifyListeners();
}
@visibleForTesting
@@ -262,6 +264,7 @@ class GameSession {
playerScores[i] += roundList[j].scoreUpdates[i];
}
}
notifyListeners();
}
/// Checks if a player has reached 100 points in the current round.
@@ -291,10 +294,14 @@ class GameSession {
}
}
winner = lowestPlayer;
notifyListeners();
}
/// Increases the round number by 1.
void increaseRound() {
roundNumber++;
print('roundNumber erhöht: $roundNumber — Hash: ${identityHashCode(this)}');
notifyListeners();
}
}

View File

@@ -15,92 +15,98 @@ class ActiveGameView extends StatefulWidget {
class _ActiveGameViewState extends State<ActiveGameView> {
@override
Widget build(BuildContext context) {
List<int> sortedPlayerIndices = _getSortedPlayerIndices();
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(widget.gameSession.gameTitle),
),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Text(
'Spieler:innen',
style: CustomTheme.rowTitle,
return ListenableBuilder(
listenable: widget.gameSession,
builder: (context, _) {
List<int> sortedPlayerIndices = _getSortedPlayerIndices();
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(widget.gameSession.gameTitle),
),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Text(
'Spieler:innen',
style: CustomTheme.rowTitle,
),
),
ListView.builder(
shrinkWrap: true,
itemCount: widget.gameSession.players.length,
itemBuilder: (BuildContext context, int index) {
int playerIndex = sortedPlayerIndices[index];
return CupertinoListTile(
title: Row(
children: [
_getPlacementPrefix(index),
const SizedBox(width: 5),
Text(
widget.gameSession.players[playerIndex],
style:
const TextStyle(fontWeight: FontWeight.bold),
),
],
),
trailing: Row(
children: [
const SizedBox(width: 5),
Text(
'${widget.gameSession.playerScores[playerIndex]} '
'Punkte')
],
),
);
},
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Text(
'Runden',
style: CustomTheme.rowTitle,
),
),
ListView.builder(
shrinkWrap: true,
itemCount: widget.gameSession.roundNumber,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(1),
child: CupertinoListTile(
title: Text(
'Runde ${index + 1}',
),
trailing: index + 1 !=
widget.gameSession.roundNumber ||
widget.gameSession.isGameFinished == true
? (const Text('\u{2705}',
style: TextStyle(fontSize: 22)))
: const Text('\u{23F3}',
style: TextStyle(fontSize: 22)),
onTap: () async {
// ignore: unused_local_variable
final val = await Navigator.of(context,
rootNavigator: true)
.push(
CupertinoPageRoute(
fullscreenDialog: true,
builder: (context) => RoundView(
gameSession: widget.gameSession,
roundNumber: index + 1),
),
);
},
));
},
),
],
),
),
ListView.builder(
shrinkWrap: true,
itemCount: widget.gameSession.players.length,
itemBuilder: (BuildContext context, int index) {
int playerIndex = sortedPlayerIndices[index];
return CupertinoListTile(
title: Row(
children: [
_getPlacementPrefix(index),
const SizedBox(width: 5),
Text(
widget.gameSession.players[playerIndex],
style: const TextStyle(fontWeight: FontWeight.bold),
),
],
),
trailing: Row(
children: [
const SizedBox(width: 5),
Text('${widget.gameSession.playerScores[playerIndex]} '
'Punkte')
],
),
);
},
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Text(
'Runden',
style: CustomTheme.rowTitle,
),
),
ListView.builder(
shrinkWrap: true,
itemCount: widget.gameSession.roundNumber,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(1),
child: CupertinoListTile(
title: Text(
'Runde ${index + 1}',
),
trailing: index + 1 != widget.gameSession.roundNumber ||
widget.gameSession.isGameFinished == true
? (const Text('\u{2705}',
style: TextStyle(fontSize: 22)))
: const Text('\u{23F3}',
style: TextStyle(fontSize: 22)),
onTap: () async {
// ignore: unused_local_variable
final val =
await Navigator.of(context, rootNavigator: true)
.push(
CupertinoPageRoute(
fullscreenDialog: true,
builder: (context) => RoundView(
gameSession: widget.gameSession,
roundNumber: index + 1),
),
);
setState(() {});
},
));
},
),
],
),
),
);
);
});
}
/// Returns a list of player indices sorted by their scores in

View File

@@ -35,9 +35,6 @@ class _MainMenuViewState extends State<MainMenuView> {
@override
Widget build(BuildContext context) {
print('MainMenuView build');
LocalStorageService.loadGameSessions();
return ListenableBuilder(
listenable: gameManager,
builder: (context, _) {
@@ -100,75 +97,83 @@ class _MainMenuViewState extends State<MainMenuView> {
itemCount: gameManager.gameList.length,
itemBuilder: (context, index) {
final session = gameManager.gameList[index];
return Dismissible(
key: Key(session.gameTitle),
background: Container(
color: CupertinoColors.destructiveRed,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(left: 20.0),
child: const Icon(
CupertinoIcons.delete,
color: CupertinoColors.white,
),
),
direction: DismissDirection.startToEnd,
confirmDismiss: (direction) async {
final String gameTitle =
gameManager.gameList[index].gameTitle;
return await _showDeleteGamePopup(gameTitle);
},
onDismissed: (direction) {
gameManager.removeGameSession(index);
},
dismissThresholds: const {
DismissDirection.startToEnd: 0.6
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0),
child: CupertinoListTile(
backgroundColorActivated:
CustomTheme.backgroundColor,
title: Text(session.gameTitle),
subtitle: session.isGameFinished == true
? Text(
'\u{1F947} ${session.winner}',
style:
const TextStyle(fontSize: 14),
)
: Text(
'Modus: ${_translateGameMode(session.isPointsLimitEnabled)}',
style:
const TextStyle(fontSize: 14),
),
trailing: Row(
children: [
Text('${session.roundNumber}'),
const SizedBox(width: 3),
const Icon(CupertinoIcons
.arrow_2_circlepath_circle_fill),
const SizedBox(width: 15),
Text('${session.players.length}'),
const SizedBox(width: 3),
const Icon(
CupertinoIcons.person_2_fill),
],
),
onTap: () async {
//ignore: unused_local_variable
final val = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => ActiveGameView(
gameSession:
gameManager.gameList[index]),
return ListenableBuilder(
listenable: session,
builder: (context, _) {
return Dismissible(
key: Key(session.gameTitle),
background: Container(
color: CupertinoColors.destructiveRed,
alignment: Alignment.centerLeft,
padding:
const EdgeInsets.only(left: 20.0),
child: const Icon(
CupertinoIcons.delete,
color: CupertinoColors.white,
),
);
setState(() {});
},
),
),
);
),
direction: DismissDirection.startToEnd,
confirmDismiss: (direction) async {
final String gameTitle = gameManager
.gameList[index].gameTitle;
return await _showDeleteGamePopup(
gameTitle);
},
onDismissed: (direction) {
gameManager.removeGameSession(index);
},
dismissThresholds: const {
DismissDirection.startToEnd: 0.6
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0),
child: CupertinoListTile(
backgroundColorActivated:
CustomTheme.backgroundColor,
title: Text(session.gameTitle),
subtitle:
session.isGameFinished == true
? Text(
'\u{1F947} ${session.winner}',
style: const TextStyle(
fontSize: 14),
)
: Text(
'Modus: ${_translateGameMode(session.isPointsLimitEnabled)}',
style: const TextStyle(
fontSize: 14),
),
trailing: Row(
children: [
Text('${session.roundNumber}'),
const SizedBox(width: 3),
const Icon(CupertinoIcons
.arrow_2_circlepath_circle_fill),
const SizedBox(width: 15),
Text('${session.players.length}'),
const SizedBox(width: 3),
const Icon(
CupertinoIcons.person_2_fill),
],
),
onTap: () async {
//ignore: unused_local_variable
final val = await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) =>
ActiveGameView(
gameSession: gameManager
.gameList[index]),
),
);
setState(() {});
},
),
),
);
});
},
),
),
@@ -215,4 +220,10 @@ class _MainMenuViewState extends State<MainMenuView> {
false;
return shouldDelete;
}
@override
void dispose() {
gameManager.removeListener(_updateView);
super.dispose();
}
}