From d71585b58598b17122aa5dfffe76d0fcf76160a9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 8 Jun 2025 00:48:30 +0200 Subject: [PATCH] Implemented 2 possibilites of deleting game --- ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- lib/services/local_storage_service.dart | 13 + lib/views/create_game_view.dart | 4 +- lib/views/main_menu_view.dart | 328 ++++++++++++------ 5 files changed, 246 insertions(+), 103 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 138b281..804f441 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -215,7 +215,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1620; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C8080294A63A400263BE5 = { diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 51c28c5..fa4cdb6 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ deleteAllGames() async { + try { + Globals.gameList.clear(); + await saveGameSessions(); + logger.i('Alle Runden wurden erfolgreich gelöscht.'); + return true; + } catch (e) { + logger.e('Fehler beim Löschen aller Runden: $e', + error: 'Löschen fehlgeschlagen'); + return false; + } + } } diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 9150a22..7bbeefa 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -289,7 +289,9 @@ class _CreateGameState extends State { caboPenalty: Globals.caboPenalty, isPointsLimitEnabled: selectedMode!, ); - Globals.addGameSession(gameSession); + setState(() { + Globals.addGameSession(gameSession); + }); LocalStorageService.saveGameSessions(); if (context.mounted) { Navigator.pushReplacement( diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index e5a1039..58cb0f0 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -17,6 +17,7 @@ class MainMenuView extends StatefulWidget { class _MainMenuViewState extends State { bool _isLoading = true; + bool _isDeletionModeEnabled = false; @override initState() { @@ -34,112 +35,239 @@ class _MainMenuViewState extends State { LocalStorageService.loadGameSessions(); return CupertinoPageScaffold( - resizeToAvoidBottomInset: false, - navigationBar: CupertinoNavigationBar( - leading: IconButton( - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const SettingsView(), - ), - ); - }, - icon: const Icon( - CupertinoIcons.settings, - size: 30, - )), - middle: const Text('Cabo Counter'), - trailing: IconButton( - onPressed: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => const CreateGame(), - ), - ); - }, - icon: const Icon(CupertinoIcons.add)), - ), - child: CupertinoPageScaffold( - child: SafeArea( - child: _isLoading - ? const Center(child: CupertinoActivityIndicator()) - : Globals.gameList.isEmpty - ? Column( - mainAxisAlignment: - MainAxisAlignment.center, // Oben ausrichten - children: [ - const SizedBox(height: 30), // Abstand von oben - Center( - child: GestureDetector( - onTap: () => setState(() {}), - child: Icon( - CupertinoIcons.plus, - size: 60, - color: CustomTheme.primaryColor, - ), - )), - const SizedBox(height: 10), // Abstand von oben - const Padding( - padding: EdgeInsets.symmetric(horizontal: 70), - child: Text( - 'Ganz schön leer hier...\nFüge über den Button oben rechts eine neue Runde hinzu.', - textAlign: TextAlign.center, - style: TextStyle(fontSize: 16), - ), + resizeToAvoidBottomInset: false, + navigationBar: CupertinoNavigationBar( + leading: IconButton( + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const SettingsView(), + ), + ); + }, + icon: _isDeletionModeEnabled + ? const Icon(null) + : const Icon(CupertinoIcons.settings, size: 30)), + middle: const Text('Cabo Counter'), + trailing: IconButton( + onPressed: () => _isDeletionModeEnabled + ? _showDeleteAllGamesPopup() + : { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const CreateGame(), ), - ], - ) - : ListView.builder( - itemCount: Globals.gameList.length, - itemBuilder: (context, index) { - final session = Globals.gameList[index]; - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: CupertinoListTile( - 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: Globals.gameList[index]), - ), - ); - setState(() {}); - }, - )); - }), + ) + }, + icon: _isDeletionModeEnabled + ? const Icon(CupertinoIcons.trash, size: 25) + : const Icon(CupertinoIcons.add)), ), - ), - ); + child: CupertinoPageScaffold( + child: SafeArea( + child: _isLoading + ? const Center(child: CupertinoActivityIndicator()) + : Globals.gameList.isEmpty + ? Column( + mainAxisAlignment: + MainAxisAlignment.center, // Oben ausrichten + children: [ + const SizedBox(height: 30), // Abstand von oben + Center( + child: GestureDetector( + onTap: () => setState(() {}), + child: Icon( + CupertinoIcons.plus, + size: 60, + color: CustomTheme.primaryColor, + ), + )), + const SizedBox(height: 10), // Abstand von oben + const Padding( + padding: EdgeInsets.symmetric(horizontal: 70), + child: Text( + 'Ganz schön leer hier...\nFüge über den Button oben rechts eine neue Runde hinzu.', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 16), + ), + ), + ], + ) + : GestureDetector( + onTap: () => { + if (_isDeletionModeEnabled) + { + setState(() { + _isDeletionModeEnabled = false; + }), + print('Deletion mode: $_isDeletionModeEnabled') + } + }, + onLongPress: () => { + setState(() { + _isDeletionModeEnabled = true; + }), + print('Deletion mode: $_isDeletionModeEnabled') + }, + child: ListView.builder( + itemCount: Globals.gameList.length, + itemBuilder: (context, index) { + final session = Globals.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 { + if (_isDeletionModeEnabled) return false; + return await _showDeleteSingleGamePopup(index); + }, + onDismissed: (direction) { + _deleteSpecificGame(index); + }, + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 10.0), + child: CupertinoListTile( + 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: () => _isDeletionModeEnabled + ? _showDeleteSingleGamePopup(index) + : () async { + //ignore: unused_local_variable + final val = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + ActiveGameView( + gameSession: Globals + .gameList[index]), + ), + ); + setState(() {}); + }, + ), + ), + ); + }, + ), + ), + ), + )); } + /// Translates the game mode boolean into the corresponding String. + /// If [pointLimit] is true, it returns '101 Punkte', otherwise it returns 'Unbegrenzt'. String _translateGameMode(bool pointLimit) { if (pointLimit) return '101 Punkte'; return 'Unbegrenzt'; } + + /// Shows a confirmation dialog to delete all game sessions. + void _showDeleteAllGamesPopup() { + showCupertinoDialog( + context: context, + builder: (context) { + return CupertinoAlertDialog( + title: const Text('Alle Spiele löschen?'), + content: const Text( + 'Bist du sicher, dass du alle Spiele löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'), + actions: [ + CupertinoDialogAction( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Abbrechen'), + ), + CupertinoDialogAction( + onPressed: () { + setState(() { + _deleteAllGames(); + _isDeletionModeEnabled = false; + }); + Navigator.pop(context); + }, + child: const Text('Löschen'), + ), + ], + ); + }, + ); + } + + /// Shows a confirmation dialog to delete all game sessions. + Future _showDeleteSingleGamePopup(int gameIndex) async { + final String title = Globals.gameList[gameIndex].gameTitle; + bool? shouldDelete = await showCupertinoDialog( + context: context, + builder: (context) { + return CupertinoAlertDialog( + title: const Text('Spiel löschen?'), + content: Text( + 'Bist du sicher, dass du die Runde "$title" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'), + actions: [ + CupertinoDialogAction( + onPressed: () { + Navigator.pop(context, false); + }, + child: const Text('Abbrechen'), + ), + CupertinoDialogAction( + onPressed: () { + Navigator.pop(context, true); + }, + child: const Text('Löschen'), + ), + ], + ); + }, + ); + return shouldDelete ?? false; + } // + + /// Deletes all game sessions. + /// This functions clears the global games lists and triggers a save to the + /// local storage. This overwrites the existing game data so that both the + /// local json file and the global variable are empty. + void _deleteAllGames() { + Globals.gameList.clear(); + LocalStorageService.saveGameSessions(); + } + + /// Deletes a specific game session by its index. + /// This function takes an [index] as parameter and removes the game session at + /// that index from the global game list, + void _deleteSpecificGame(int index) { + Globals.gameList.removeAt(index); + LocalStorageService.saveGameSessions(); + } }