diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index b22ee65..94b6287 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -9,11 +9,21 @@ class GameManager extends ChangeNotifier { /// Takes a [GameSession] object as input. It then adds the session to the `gameList`, /// 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 addGameSession(GameSession session) { + /// Returns the index of the newly added session in the sorted list. + Future 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}'); gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt)); + print( + '[game_manager.dart] Sorted game sessions by creation date. Total sessions: ${gameList.length}'); notifyListeners(); - LocalStorageService.saveGameSessions(); + await LocalStorageService.saveGameSessions(); + print('[game_manager.dart] Saved game sessions to local storage.'); + return gameList.indexOf(session); } /// Removes a game session from the list and sorts it by creation date. @@ -21,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(); diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 1e3d96d..4896e02 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -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 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(); } } diff --git a/lib/services/local_storage_service.dart b/lib/services/local_storage_service.dart index a028127..e3fddcc 100644 --- a/lib/services/local_storage_service.dart +++ b/lib/services/local_storage_service.dart @@ -28,6 +28,7 @@ class LocalStorageService { /// Saves the game sessions to a local JSON file. static Future saveGameSessions() async { + print('[local_storage_service.dart] Versuche, Daten zu speichern...'); try { final file = await _getFilePath(); final jsonFile = getJsonFile(); diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 1baabe5..ae513d4 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -15,92 +15,98 @@ class ActiveGameView extends StatefulWidget { class _ActiveGameViewState extends State { @override Widget build(BuildContext context) { - List 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 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 diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 8b1cf37..565d68a 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -206,7 +206,7 @@ class _CreateGameState extends State { ), ], ), - onPressed: () { + onPressed: () async { if (_gameTitleTextController.text == '') { showCupertinoDialog( context: context, @@ -289,13 +289,14 @@ class _CreateGameState extends State { caboPenalty: Globals.caboPenalty, isPointsLimitEnabled: selectedMode!, ); - gameManager.addGameSession(gameSession); + final index = await gameManager.addGameSession(gameSession); + print('index des spiels: $index'); if (context.mounted) { Navigator.pushReplacement( context, CupertinoPageRoute( - builder: (context) => - ActiveGameView(gameSession: gameSession))); + builder: (context) => ActiveGameView( + gameSession: gameManager.gameList[index]))); } else { print('Context is not mounted'); } diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index f526e77..7c7e019 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -35,9 +35,6 @@ class _MainMenuViewState extends State { @override Widget build(BuildContext context) { - print('MainMenuView build'); - LocalStorageService.loadGameSessions(); - return ListenableBuilder( listenable: gameManager, builder: (context, _) { @@ -100,75 +97,83 @@ class _MainMenuViewState extends State { 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 { false; return shouldDelete; } + + @override + void dispose() { + gameManager.removeListener(_updateView); + super.dispose(); + } } diff --git a/pubspec.yaml b/pubspec.yaml index c025768..4791a55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.2.1+171 +version: 0.2.3+181 environment: sdk: ^3.5.4