From 9897c744438b9cab46bb2078666ab4705187da8e Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 4 Jul 2025 00:11:57 +0200 Subject: [PATCH 01/21] Updated createGameView ListBuilder --- lib/views/create_game_view.dart | 261 +++++++++++++++++--------------- pubspec.yaml | 2 +- 2 files changed, 137 insertions(+), 126 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index fd59529..0050ff0 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -130,28 +130,70 @@ class _CreateGameViewState extends State { ), Expanded( child: ListView.builder( - itemCount: _playerNameTextControllers.length + - 1, // +1 für den + Button + itemCount: _playerNameTextControllers.length + 2, itemBuilder: (context, index) { + if (index == _playerNameTextControllers.length + 1) { + return CupertinoButton( + padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context).create_game, + style: const TextStyle( + color: CupertinoColors.activeGreen, + ), + ), + ], + ), + onPressed: () { + _checkAllGameAttributes(); + }, + ); + } if (index == _playerNameTextControllers.length) { - // + Button als letztes Element return Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 5), child: CupertinoButton( padding: EdgeInsets.zero, child: Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, children: [ - const Icon( - CupertinoIcons.add_circled, - color: CupertinoColors.activeGreen, - size: 25, + Align( + alignment: Alignment.centerLeft, + child: CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + size: 25, + ), + ), ), - const SizedBox(width: 8), - Text( - AppLocalizations.of(context).add_player, - style: const TextStyle( - color: CupertinoColors.activeGreen, + Expanded( + child: Align( + alignment: Alignment.center, + child: Text( + AppLocalizations.of(context).add_player, + textAlign: TextAlign.center, + style: const TextStyle( + color: CupertinoColors.activeGreen, + ), + ), + ), + ), + const Align( + alignment: Alignment.centerLeft, + child: CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.add_circled_solid, + color: CupertinoColors.transparent, + size: 25, + ), ), ), ], @@ -187,7 +229,7 @@ class _CreateGameViewState extends State { // Spieler-Einträge return Padding( padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), + vertical: 4.0, horizontal: 5), child: Row( children: [ CupertinoButton( @@ -221,120 +263,89 @@ class _CreateGameViewState extends State { }, ), ), - Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ], - ), - onPressed: () async { - if (_gameTitleTextController.text == '') { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context).no_gameTitle_title), - content: Text( - AppLocalizations.of(context).no_gameTitle_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - if (_isPointsLimitEnabled == null) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).no_mode_title), - content: - Text(AppLocalizations.of(context).no_mode_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - if (_playerNameTextControllers.length < 2) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text( - AppLocalizations.of(context).min_players_title), - content: Text( - AppLocalizations.of(context).min_players_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - if (!everyPlayerHasAName()) { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).no_name_title), - content: - Text(AppLocalizations.of(context).no_name_message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - return; - } - - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); - } - GameSession gameSession = GameSession( - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: Globals.pointLimit, - caboPenalty: Globals.caboPenalty, - isPointsLimitEnabled: _isPointsLimitEnabled!, - ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; - if (context.mounted) { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView(gameSession: session))); - } - }, - ), - ), ], )))); } + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showDialog(( + AppLocalizations.of(context).no_gameTitle_title, + AppLocalizations.of(context).no_gameTitle_message + )); + return; + } + + if (_isPointsLimitEnabled == null) { + _showDialog( + ( + AppLocalizations.of(context).no_mode_title, + AppLocalizations.of(context).no_mode_message + ), + ); + return; + } + + if (_playerNameTextControllers.length < 2) { + _showDialog( + ( + AppLocalizations.of(context).min_players_title, + AppLocalizations.of(context).min_players_message + ), + ); + return; + } + + if (!everyPlayerHasAName()) { + _showDialog(( + AppLocalizations.of(context).no_name_title, + AppLocalizations.of(context).no_name_message + )); + return; + } + + _createGame(); + } + + void _showDialog((String, String) content) { + final (title, message) = content; + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(title), + content: Text(message), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ); + } + + Future _createGame() async { + List players = []; + for (var controller in _playerNameTextControllers) { + players.add(controller.text); + } + GameSession gameSession = GameSession( + createdAt: DateTime.now(), + gameTitle: _gameTitleTextController.text, + players: players, + pointLimit: Globals.pointLimit, + caboPenalty: Globals.caboPenalty, + isPointsLimitEnabled: _isPointsLimitEnabled!, + ); + final index = await gameManager.addGameSession(gameSession); + final session = gameManager.gameList[index]; + + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView(gameSession: session))); + } + bool everyPlayerHasAName() { for (var controller in _playerNameTextControllers) { if (controller.text == '') { diff --git a/pubspec.yaml b/pubspec.yaml index 56b89bc..607b026 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.3.6+318 +version: 0.3.6+321 environment: sdk: ^3.5.4 From 7d497e17fe2d1f3ba6cd70c3f05e0ad8cb9c5bd9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 4 Jul 2025 00:36:10 +0200 Subject: [PATCH 02/21] Added ReorderableListView --- lib/views/create_game_view.dart | 223 ++++++++++++++++---------------- pubspec.yaml | 2 +- 2 files changed, 113 insertions(+), 112 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 0050ff0..deb86cf 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -6,6 +6,7 @@ import 'package:cabo_counter/utility/globals.dart'; import 'package:cabo_counter/views/active_game_view.dart'; import 'package:cabo_counter/views/mode_selection_view.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; class CreateGameView extends StatefulWidget { final String? gameTitle; @@ -129,137 +130,137 @@ class _CreateGameViewState extends State { ), ), Expanded( - child: ListView.builder( + child: ReorderableListView.builder( + physics: const NeverScrollableScrollPhysics(), itemCount: _playerNameTextControllers.length + 2, - itemBuilder: (context, index) { - if (index == _playerNameTextControllers.length + 1) { - return CupertinoButton( - padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ], - ), - onPressed: () { - _checkAllGameAttributes(); - }, - ); + onReorder: (oldIndex, newIndex) { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + setState(() { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + }); } - if (index == _playerNameTextControllers.length) { - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 5), + }, + itemBuilder: (context, index) { + // Create game button + if (index == _playerNameTextControllers.length + 1) { + return Container( + key: const ValueKey('create_game_button'), child: CupertinoButton( - padding: EdgeInsets.zero, + padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), child: Row( - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Align( - alignment: Alignment.centerLeft, - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.add_circled_solid, - color: CustomTheme.primaryColor, - size: 25, - ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: CustomTheme.primaryColor, ), - ), - Expanded( - child: Align( - alignment: Alignment.center, - child: Text( - AppLocalizations.of(context).add_player, - textAlign: TextAlign.center, - style: const TextStyle( - color: CupertinoColors.activeGreen, - ), - ), - ), - ), - const Align( - alignment: Alignment.centerLeft, - child: CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.add_circled_solid, - color: CupertinoColors.transparent, - size: 25, + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 8), + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.backgroundColor, ), ), ), ], ), onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context) - .max_players_title), - content: Text(AppLocalizations.of(context) - .max_players_message), - actions: [ - CupertinoDialogAction( - child: - Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - } + _checkAllGameAttributes(); }, ), ); - } else { - // Spieler-Einträge - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 5), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { + } + // Add player button + if (index == _playerNameTextControllers.length) { + return Container( + key: const ValueKey('add_player_button'), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 10), + child: CupertinoButton( + padding: EdgeInsets.zero, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 6), + Text( + AppLocalizations.of(context).add_player, + style: + TextStyle(color: CustomTheme.primaryColor), + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < + maxPlayers) { setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); + _playerNameTextControllers + .add(TextEditingController()); }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), - ), - ], + } else { + _showDialog(( + AppLocalizations.of(context).max_players_title, + AppLocalizations.of(context).max_players_message + )); + } + }, + ), ), ); } + // Player name input field + return Padding( + key: ValueKey('player_${index + 1}'), + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 5), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), + ), + const SizedBox(width: 8), + ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + size: 20, + color: CupertinoColors.systemGrey, + ), + ), + ], + ), + ); }, ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 607b026..9d42205 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.3.6+321 +version: 0.3.6+323 environment: sdk: ^3.5.4 From 05f0a0011faf53ab8db4229d5f8ddd066d08b9ff Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 6 Jul 2025 00:01:09 +0200 Subject: [PATCH 03/21] Increment build no --- pubspec.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9d42205..6160db1 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.3.6+323 +version: 0.3.6+328 environment: sdk: ^3.5.4 @@ -27,6 +27,7 @@ dependencies: intl: any syncfusion_flutter_charts: ^30.1.37 uuid: ^4.5.1 + reorderables: ^0.4.2 dev_dependencies: flutter_test: From 651b3eab0f4716855e7a8be156a34920baebd03a Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:07:55 +0200 Subject: [PATCH 04/21] Fixed merge issues --- lib/presentation/views/create_game_view.dart | 301 +++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 184 insertions(+), 119 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 47251af..fcb50bc 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -137,127 +137,127 @@ class _CreateGameViewState extends State { ), ), Expanded( - child: ReorderableListView.builder( - physics: const NeverScrollableScrollPhysics(), - itemCount: _playerNameTextControllers.length + 2, - onReorder: (oldIndex, newIndex) { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - setState(() { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - }); - } - }, - itemBuilder: (context, index) { - // Create game button - if (index == _playerNameTextControllers.length + 1) { - return Container( - key: const ValueKey('create_game_button'), - child: CupertinoButton( - padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: CustomTheme.primaryColor, - ), - padding: const EdgeInsets.symmetric( - horizontal: 15, vertical: 8), - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.backgroundColor, + child: ReorderableListView.builder( + physics: const NeverScrollableScrollPhysics(), + itemCount: _playerNameTextControllers.length + 2, + onReorder: (oldIndex, newIndex) { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + setState(() { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + }); + } + }, + itemBuilder: (context, index) { + // Create game button + if (index == _playerNameTextControllers.length + 1) { + return Container( + key: const ValueKey('create_game_button'), + child: CupertinoButton( + padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: CustomTheme.primaryColor, + ), + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 8), + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.backgroundColor, + ), + ), ), - ), - ), - ], - ), - onPressed: () { - _checkAllGameAttributes(); - }, - ), - ); - } - // Add player button - if (index == _playerNameTextControllers.length) { - return Container( - key: const ValueKey('add_player_button'), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 10), - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.add_circled_solid, - color: CustomTheme.primaryColor, - ), - const SizedBox(width: 6), - Text( - AppLocalizations.of(context).add_player, - style: - TextStyle(color: CustomTheme.primaryColor), - ), - ), - ], - ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showFeedbackDialog(CreateStatus.maxPlayers); - } - }, - ), - ); - } else { - // Spieler-Einträge - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, + ], ), onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); + _checkAllGameAttributes(); }, ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), + ); + } + // Add player button + if (index == _playerNameTextControllers.length) { + return Container( + key: const ValueKey('add_player_button'), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 4.0, horizontal: 10), + child: CupertinoButton( + padding: EdgeInsets.zero, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + ), + const SizedBox(width: 6), + Text( + AppLocalizations.of(context) + .add_player, + style: TextStyle( + color: + CustomTheme.primaryColor), + ), + ]), + onPressed: () { + if (_playerNameTextControllers.length < + maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + }); + } else { + showFeedbackDialog( + CreateStatus.maxPlayers); + } + }))); + } else { + // Player entries + return Padding( + key: ValueKey(_playerNameTextControllers[index]), + padding: const EdgeInsets.symmetric( + vertical: 8.0, horizontal: 5), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), + ), + ], ), - ), - ], - ), - ); - }, - ), - ), + ); + } + })), Center( child: CupertinoButton( padding: EdgeInsets.zero, @@ -319,18 +319,26 @@ class _CreateGameViewState extends State { ), ], )))); + } + Future _createGame() async { + /*var uuid = const Uuid(); + id = uuid.v1();*/ + List players = []; for (var controller in _playerNameTextControllers) { players.add(controller.text); } + + bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + GameSession gameSession = GameSession( createdAt: DateTime.now(), gameTitle: _gameTitleTextController.text, players: players, - pointLimit: Globals.pointLimit, - caboPenalty: Globals.caboPenalty, - isPointsLimitEnabled: _isPointsLimitEnabled!, + pointLimit: ConfigService.getPointLimit(), + caboPenalty: ConfigService.getCaboPenalty(), + isPointsLimitEnabled: isPointsLimitEnabled, ); final index = await gameManager.addGameSession(gameSession); final session = gameManager.gameList[index]; @@ -361,6 +369,63 @@ class _CreateGameViewState extends State { }); } + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showDialog(( + AppLocalizations.of(context).no_gameTitle_title, + AppLocalizations.of(context).no_gameTitle_message + )); + return; + } + + if (gameMode == GameMode.none) { + _showDialog( + ( + AppLocalizations.of(context).no_mode_title, + AppLocalizations.of(context).no_mode_message + ), + ); + return; + } + + if (_playerNameTextControllers.length < 2) { + _showDialog( + ( + AppLocalizations.of(context).min_players_title, + AppLocalizations.of(context).min_players_message + ), + ); + return; + } + + if (!everyPlayerHasAName()) { + _showDialog(( + AppLocalizations.of(context).no_name_title, + AppLocalizations.of(context).no_name_message + )); + return; + } + + _createGame(); + } + + void _showDialog((String, String) content) { + final (title, message) = content; + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: Text(title), + content: Text(message), + actions: [ + CupertinoDialogAction( + child: Text(AppLocalizations.of(context).ok), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ); + } + /// Returns the title and message for the dialog based on the [CreateStatus]. (String, String) _getDialogContent(CreateStatus status) { switch (status) { diff --git a/pubspec.yaml b/pubspec.yaml index 956c747..9d13ace 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.5.0+554 +version: 0.5.0+556 environment: sdk: ^3.5.4 From 3c095e0f55e20d4c715d39ce2362754def4f4cdb Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:27:13 +0200 Subject: [PATCH 05/21] Added Custom button --- lib/presentation/widgets/custom_button.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/presentation/widgets/custom_button.dart diff --git a/lib/presentation/widgets/custom_button.dart b/lib/presentation/widgets/custom_button.dart new file mode 100644 index 0000000..0feb799 --- /dev/null +++ b/lib/presentation/widgets/custom_button.dart @@ -0,0 +1,19 @@ +import 'package:cabo_counter/core/custom_theme.dart'; +import 'package:flutter/cupertino.dart'; + +class CustomButton extends StatelessWidget { + final Widget child; + final VoidCallback? onPressed; + const CustomButton({super.key, required this.child, this.onPressed}); + + @override + Widget build(BuildContext context) { + return CupertinoButton( + sizeStyle: CupertinoButtonSize.medium, + borderRadius: BorderRadius.circular(12), + color: CustomTheme.buttonBackgroundColor, + onPressed: onPressed, + child: child, + ); + } +} From 5ebce36c125c17a104c20cae4babd9008db893b4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:27:21 +0200 Subject: [PATCH 06/21] Updated strings --- lib/l10n/arb/app_de.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index c5fae28..effbd96 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -55,7 +55,7 @@ "min_players_title": "Zu wenig Spieler:innen", "min_players_message": "Es müssen mindestens 2 Spieler:innen hinzugefügt werden", "no_name_title": "Kein Name", - "no_name_message": "Jeder Spieler muss einen Namen haben.", + "no_name_message": "Jede:r Spieler:in muss einen Namen haben.", "select_game_mode": "Spielmodus auswählen", "no_mode_selected": "Wähle einen Spielmodus", From a4693ccf399235c273326666771ba4b763f89f48 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 17:51:30 +0200 Subject: [PATCH 07/21] Updated buttons, implemented animatedOpacity --- lib/l10n/generated/app_localizations.dart | 2 +- lib/l10n/generated/app_localizations_de.dart | 2 +- lib/presentation/views/create_game_view.dart | 283 ++++++++----------- pubspec.yaml | 2 +- 4 files changed, 117 insertions(+), 172 deletions(-) diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index d821b28..9c64cb2 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -365,7 +365,7 @@ abstract class AppLocalizations { /// No description provided for @no_name_message. /// /// In de, this message translates to: - /// **'Jeder Spieler muss einen Namen haben.'** + /// **'Jede:r Spieler:in muss einen Namen haben.'** String get no_name_message; /// No description provided for @select_game_mode. diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 13dcf2a..c4849d8 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -149,7 +149,7 @@ class AppLocalizationsDe extends AppLocalizations { String get no_name_title => 'Kein Name'; @override - String get no_name_message => 'Jeder Spieler muss einen Namen haben.'; + String get no_name_message => 'Jede:r Spieler:in muss einen Namen haben.'; @override String get select_game_mode => 'Spielmodus auswählen'; diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index fcb50bc..ea7476f 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -4,6 +4,7 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:cabo_counter/presentation/views/active_game_view.dart'; import 'package:cabo_counter/presentation/views/mode_selection_view.dart'; +import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -136,185 +137,129 @@ class _CreateGameViewState extends State { style: CustomTheme.rowTitle, ), ), - Expanded( - child: ReorderableListView.builder( - physics: const NeverScrollableScrollPhysics(), - itemCount: _playerNameTextControllers.length + 2, - onReorder: (oldIndex, newIndex) { + Flexible( + child: ReorderableListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { if (oldIndex < _playerNameTextControllers.length && newIndex <= _playerNameTextControllers.length) { - setState(() { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - }); + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); } - }, - itemBuilder: (context, index) { - // Create game button - if (index == _playerNameTextControllers.length + 1) { - return Container( - key: const ValueKey('create_game_button'), - child: CupertinoButton( - padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: CustomTheme.primaryColor, - ), - padding: const EdgeInsets.symmetric( - horizontal: 15, vertical: 8), - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.backgroundColor, - ), - ), - ), - ], + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey( + 'player_${_playerNameTextControllers[index].hashCode}'), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, ), onPressed: () { - _checkAllGameAttributes(); + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); }, ), - ); - } - // Add player button - if (index == _playerNameTextControllers.length) { - return Container( - key: const ValueKey('add_player_button'), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, horizontal: 10), - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.add_circled_solid, - color: CustomTheme.primaryColor, - ), - const SizedBox(width: 6), - Text( - AppLocalizations.of(context) - .add_player, - style: TextStyle( - color: - CustomTheme.primaryColor), - ), - ]), - onPressed: () { - if (_playerNameTextControllers.length < - maxPlayers) { - setState(() { - _playerNameTextControllers - .add(TextEditingController()); - }); - } else { - showFeedbackDialog( - CreateStatus.maxPlayers); - } - }))); - } else { - // Player entries - return Padding( - key: ValueKey(_playerNameTextControllers[index]), - padding: const EdgeInsets.symmetric( - vertical: 8.0, horizontal: 5), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), - ), - ], + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), ), - ); - } - })), - Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - AppLocalizations.of(context).create_game, - style: const TextStyle( - color: CupertinoColors.activeGreen, + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration(milliseconds: 300), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, + ), + ), + ), + ) + ], ), - ), - ], + ); + }), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 0, 50), + child: Center( + child: CupertinoButton( + padding: EdgeInsets.zero, + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + onPressed: null, + child: Icon( + CupertinoIcons.plus_circle_fill, + color: CustomTheme.primaryColor, + size: 25, + )), + Stack(children: [ + Expanded( + child: Center( + child: Text( + AppLocalizations.of(context).add_player, + style: TextStyle(color: CustomTheme.primaryColor), + ), + ), + ), + ]), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < maxPlayers) { + setState(() { + _playerNameTextControllers.add(TextEditingController()); + }); + } else { + showFeedbackDialog(CreateStatus.maxPlayers); + } + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: Center( + key: const ValueKey('create_game_button'), + child: CustomButton( + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ), + onPressed: () { + _checkAllGameAttributes(); + }, ), - onPressed: () async { - if (_gameTitleTextController.text == '') { - showFeedbackDialog(CreateStatus.noGameTitle); - return; - } - if (gameMode == GameMode.none) { - showFeedbackDialog(CreateStatus.noModeSelected); - return; - } - if (_playerNameTextControllers.length < 2) { - showFeedbackDialog(CreateStatus.minPlayers); - return; - } - if (!everyPlayerHasAName()) { - showFeedbackDialog(CreateStatus.noPlayerName); - return; - } - - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); - } - - bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; - - GameSession gameSession = GameSession( - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: ConfigService.getPointLimit(), - caboPenalty: ConfigService.getCaboPenalty(), - isPointsLimitEnabled: isPointsLimitEnabled, - ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; - if (context.mounted) { - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => - ActiveGameView(gameSession: session))); - } - }, ), ), ], diff --git a/pubspec.yaml b/pubspec.yaml index 9d13ace..001d4f2 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.5.0+556 +version: 0.5.0+558 environment: sdk: ^3.5.4 From 68a1a5052eb27f91b92ec6147c36bef783617949 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 18:21:30 +0200 Subject: [PATCH 08/21] Keyboard still doesnt works --- lib/presentation/views/create_game_view.dart | 356 +++++++++---------- pubspec.yaml | 2 +- 2 files changed, 178 insertions(+), 180 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index ea7476f..faffe76 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -72,198 +72,196 @@ class _CreateGameViewState extends State { ), child: SafeArea( child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).game, - style: CustomTheme.rowTitle, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - maxLength: 16, - prefix: Text(AppLocalizations.of(context).name), - textAlign: TextAlign.right, - placeholder: AppLocalizations.of(context).game_title, - controller: _gameTitleTextController, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), - child: CupertinoTextField( - decoration: const BoxDecoration(), - readOnly: true, - prefix: Text(AppLocalizations.of(context).mode), - suffix: Row( - children: [ - Text( - gameMode == GameMode.none - ? AppLocalizations.of(context).no_mode_selected - : (gameMode == GameMode.pointLimit - ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' - : AppLocalizations.of(context).unlimited), - ), - const SizedBox(width: 3), - const CupertinoListTileChevron(), - ], + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).game, + style: CustomTheme.rowTitle, ), - onTap: () async { - final selectedMode = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => ModeSelectionMenu( - pointLimit: ConfigService.getPointLimit(), - showDeselection: false, - ), - ), - ); - - setState(() { - gameMode = selectedMode ?? gameMode; - }); - }, ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), - child: Text( - AppLocalizations.of(context).players, - style: CustomTheme.rowTitle, + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + maxLength: 16, + prefix: Text(AppLocalizations.of(context).name), + textAlign: TextAlign.right, + placeholder: AppLocalizations.of(context).game_title, + controller: _gameTitleTextController, + ), ), - ), - Flexible( - child: ReorderableListView.builder( - shrinkWrap: true, - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.all(8), - itemCount: _playerNameTextControllers.length, - onReorder: (oldIndex, newIndex) { - setState(() { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - } - }); - }, - itemBuilder: (context, index) { - return Padding( - key: ValueKey( - 'player_${_playerNameTextControllers[index].hashCode}'), - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, - ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), - ), - AnimatedOpacity( - opacity: _playerNameTextControllers.length > 1 - ? 1.0 - : 0.0, - duration: const Duration(milliseconds: 300), - child: Padding( - padding: const EdgeInsets.only(right: 8.0), - child: ReorderableDragStartListener( - index: index, - child: const Icon( - CupertinoIcons.line_horizontal_3, - color: CupertinoColors.systemGrey, - ), - ), - ), - ) - ], - ), - ); - }), - ), - Padding( - padding: const EdgeInsets.fromLTRB(8, 0, 0, 50), - child: Center( - child: CupertinoButton( - padding: EdgeInsets.zero, - child: Row( + Padding( + padding: const EdgeInsets.fromLTRB(15, 10, 10, 0), + child: CupertinoTextField( + decoration: const BoxDecoration(), + readOnly: true, + prefix: Text(AppLocalizations.of(context).mode), + suffix: Row( children: [ - CupertinoButton( - padding: EdgeInsets.zero, - onPressed: null, - child: Icon( - CupertinoIcons.plus_circle_fill, - color: CustomTheme.primaryColor, - size: 25, - )), - Stack(children: [ - Expanded( - child: Center( - child: Text( - AppLocalizations.of(context).add_player, - style: TextStyle(color: CustomTheme.primaryColor), - ), - ), - ), - ]), + Text( + gameMode == GameMode.none + ? AppLocalizations.of(context).no_mode_selected + : (gameMode == GameMode.pointLimit + ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' + : AppLocalizations.of(context).unlimited), + ), + const SizedBox(width: 3), + const CupertinoListTileChevron(), ], ), - onPressed: () { - if (_playerNameTextControllers.length < maxPlayers) { - setState(() { - _playerNameTextControllers.add(TextEditingController()); - }); - } else { - showFeedbackDialog(CreateStatus.maxPlayers); - } + onTap: () async { + final selectedMode = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => ModeSelectionMenu( + pointLimit: ConfigService.getPointLimit(), + showDeselection: false, + ), + ), + ); + + setState(() { + gameMode = selectedMode ?? gameMode; + }); }, ), ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), - child: Center( - key: const ValueKey('create_game_button'), - child: CustomButton( - child: Text( - AppLocalizations.of(context).create_game, - style: TextStyle( - color: CustomTheme.primaryColor, + Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 0, 0), + child: Text( + AppLocalizations.of(context).players, + style: CustomTheme.rowTitle, + ), + ), + Flexible( + child: ReorderableListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + } + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey( + 'player_${_playerNameTextControllers[index].hashCode}'), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, + ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), + ), + ), + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration(milliseconds: 300), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, + ), + ), + ), + ) + ], + ), + ); + }), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), + child: Center( + child: SizedBox( + width: double.infinity, + child: CupertinoButton( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + AppLocalizations.of(context).add_player, + style: TextStyle(color: CustomTheme.primaryColor), + ), + const SizedBox(width: 8), + Icon( + CupertinoIcons.add_circled_solid, + color: CustomTheme.primaryColor, + size: 25, + ), + ], + ), + onPressed: () { + if (_playerNameTextControllers.length < maxPlayers) { + setState(() { + _playerNameTextControllers + .add(TextEditingController()); + }); + } else { + showFeedbackDialog(CreateStatus.maxPlayers); + } + }, ), ), - onPressed: () { - _checkAllGameAttributes(); - }, ), ), - ), - ], - )))); + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 50), + child: Center( + key: const ValueKey('create_game_button'), + child: CustomButton( + child: Text( + AppLocalizations.of(context).create_game, + style: TextStyle( + color: CustomTheme.primaryColor, + ), + ), + onPressed: () { + _checkAllGameAttributes(); + }, + ), + ), + ), + ], + ), + ))); } Future _createGame() async { diff --git a/pubspec.yaml b/pubspec.yaml index 001d4f2..995d091 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.5.0+558 +version: 0.5.0+568 environment: sdk: ^3.5.4 From 59ff4df83c5f26656e2d57fbacfade57f7e7ac3d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 19:28:38 +0200 Subject: [PATCH 09/21] Fixed keyboard behaviour --- lib/presentation/views/create_game_view.dart | 162 ++++++++++--------- lib/presentation/views/tab_view.dart | 1 + 2 files changed, 90 insertions(+), 73 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index faffe76..880eb6f 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -8,6 +8,7 @@ import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; enum CreateStatus { noGameTitle, @@ -66,12 +67,13 @@ class _CreateGameViewState extends State { @override Widget build(BuildContext context) { return CupertinoPageScaffold( + resizeToAvoidBottomInset: false, navigationBar: CupertinoNavigationBar( previousPageTitle: AppLocalizations.of(context).overview, middle: Text(AppLocalizations.of(context).new_game), ), child: SafeArea( - child: Center( + child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -102,13 +104,7 @@ class _CreateGameViewState extends State { prefix: Text(AppLocalizations.of(context).mode), suffix: Row( children: [ - Text( - gameMode == GameMode.none - ? AppLocalizations.of(context).no_mode_selected - : (gameMode == GameMode.pointLimit - ? '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}' - : AppLocalizations.of(context).unlimited), - ), + _getDisplayedGameMode(), const SizedBox(width: 3), const CupertinoListTileChevron(), ], @@ -137,75 +133,73 @@ class _CreateGameViewState extends State { style: CustomTheme.rowTitle, ), ), - Flexible( - child: ReorderableListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: const EdgeInsets.all(8), - itemCount: _playerNameTextControllers.length, - onReorder: (oldIndex, newIndex) { - setState(() { - if (oldIndex < _playerNameTextControllers.length && - newIndex <= _playerNameTextControllers.length) { - if (newIndex > oldIndex) newIndex--; - final item = - _playerNameTextControllers.removeAt(oldIndex); - _playerNameTextControllers.insert(newIndex, item); - } - }); - }, - itemBuilder: (context, index) { - return Padding( - key: ValueKey( - 'player_${_playerNameTextControllers[index].hashCode}'), - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - children: [ - CupertinoButton( - padding: EdgeInsets.zero, - child: const Icon( - CupertinoIcons.minus_circle_fill, - color: CupertinoColors.destructiveRed, - size: 25, - ), - onPressed: () { - setState(() { - _playerNameTextControllers[index].dispose(); - _playerNameTextControllers.removeAt(index); - }); - }, + ReorderableListView.builder( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8), + itemCount: _playerNameTextControllers.length, + onReorder: (oldIndex, newIndex) { + setState(() { + if (oldIndex < _playerNameTextControllers.length && + newIndex <= _playerNameTextControllers.length) { + if (newIndex > oldIndex) newIndex--; + final item = + _playerNameTextControllers.removeAt(oldIndex); + _playerNameTextControllers.insert(newIndex, item); + } + }); + }, + itemBuilder: (context, index) { + return Padding( + key: ValueKey( + 'player_${_playerNameTextControllers[index].hashCode}'), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon( + CupertinoIcons.minus_circle_fill, + color: CupertinoColors.destructiveRed, + size: 25, ), - Expanded( - child: CupertinoTextField( - controller: _playerNameTextControllers[index], - maxLength: 12, - placeholder: - '${AppLocalizations.of(context).player} ${index + 1}', - padding: const EdgeInsets.all(12), - decoration: const BoxDecoration(), - ), + onPressed: () { + setState(() { + _playerNameTextControllers[index].dispose(); + _playerNameTextControllers.removeAt(index); + }); + }, + ), + Expanded( + child: CupertinoTextField( + controller: _playerNameTextControllers[index], + maxLength: 12, + placeholder: + '${AppLocalizations.of(context).player} ${index + 1}', + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration(), ), - AnimatedOpacity( - opacity: _playerNameTextControllers.length > 1 - ? 1.0 - : 0.0, - duration: const Duration(milliseconds: 300), - child: Padding( - padding: const EdgeInsets.only(right: 8.0), - child: ReorderableDragStartListener( - index: index, - child: const Icon( - CupertinoIcons.line_horizontal_3, - color: CupertinoColors.systemGrey, - ), + ), + AnimatedOpacity( + opacity: _playerNameTextControllers.length > 1 + ? 1.0 + : 0.0, + duration: const Duration(milliseconds: 300), + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: ReorderableDragStartListener( + index: index, + child: const Icon( + CupertinoIcons.line_horizontal_3, + color: CupertinoColors.systemGrey, ), ), - ) - ], - ), - ); - }), - ), + ), + ) + ], + ), + ); + }), Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 50), child: Center( @@ -259,6 +253,15 @@ class _CreateGameViewState extends State { ), ), ), + KeyboardVisibilityBuilder(builder: (context, visible) { + if (visible) { + return const SizedBox( + height: 250, + ); + } else { + return const SizedBox.shrink(); + } + }) ], ), ))); @@ -412,6 +415,19 @@ class _CreateGameViewState extends State { return true; } + Text _getDisplayedGameMode() { + if (gameMode == GameMode.none) { + return Text(AppLocalizations.of(context).no_mode_selected); + } else if (gameMode == GameMode.pointLimit) { + return Text( + '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', + style: TextStyle(color: CustomTheme.primaryColor)); + } else { + return Text(AppLocalizations.of(context).unlimited, + style: TextStyle(color: CustomTheme.primaryColor)); + } + } + @override void dispose() { _gameTitleTextController.dispose(); diff --git a/lib/presentation/views/tab_view.dart b/lib/presentation/views/tab_view.dart index 4b757fa..08b1790 100644 --- a/lib/presentation/views/tab_view.dart +++ b/lib/presentation/views/tab_view.dart @@ -16,6 +16,7 @@ class _TabViewState extends State { @override Widget build(BuildContext context) { return CupertinoTabScaffold( + resizeToAvoidBottomInset: false, tabBar: CupertinoTabBar( backgroundColor: CustomTheme.mainElementBackgroundColor, iconSize: 27, From 03ed2a22d50cb5969bf6a92890050ce2101cdd04 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 19:30:15 +0200 Subject: [PATCH 10/21] Changed keyboard height --- lib/presentation/views/create_game_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 880eb6f..0a679a5 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -255,8 +255,8 @@ class _CreateGameViewState extends State { ), KeyboardVisibilityBuilder(builder: (context, visible) { if (visible) { - return const SizedBox( - height: 250, + return SizedBox( + height: MediaQuery.of(context).viewInsets.bottom * 0.75, ); } else { return const SizedBox.shrink(); From 35cfba457da79c270e77d3b0e62bdd48c3066fe2 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:20:21 +0200 Subject: [PATCH 11/21] Added method getGameSessionById() --- lib/data/game_manager.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index b3a1933..3fc5e54 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -21,6 +21,10 @@ class GameManager extends ChangeNotifier { return gameList.indexOf(session); } + GameSession? getGameSessionById(String id) { + return gameList.firstWhere((session) => session.id.toString() == id); + } + /// Removes a game session from the list and sorts it by creation date. /// Takes a [index] as input. It then removes the session at the specified index from the `gameList`, /// sorts the list in descending order based on the creation date, and notifies listeners of the change. From d90b9b1bc206850936187946ed460984994bc5d8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:20:52 +0200 Subject: [PATCH 12/21] Updated gameSession class --- lib/data/game_session.dart | 5 ++--- test/data/game_session_test.dart | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index d1402e5..a9164be 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -13,7 +13,7 @@ import 'package:uuid/uuid.dart'; /// [isGameFinished] is a boolean indicating if the game has ended yet. /// [winner] is the name of the player who won the game. class GameSession extends ChangeNotifier { - late String id; + final String id; final DateTime createdAt; final String gameTitle; final List players; @@ -27,6 +27,7 @@ class GameSession extends ChangeNotifier { List roundList = []; GameSession({ + required this.id, required this.createdAt, required this.gameTitle, required this.players, @@ -35,8 +36,6 @@ class GameSession extends ChangeNotifier { required this.isPointsLimitEnabled, }) { playerScores = List.filled(players.length, 0); - var uuid = const Uuid(); - id = uuid.v1(); } @override diff --git a/test/data/game_session_test.dart b/test/data/game_session_test.dart index 4ca2158..9654bad 100644 --- a/test/data/game_session_test.dart +++ b/test/data/game_session_test.dart @@ -9,6 +9,7 @@ void main() { setUp(() { session = GameSession( + id: '1', createdAt: testDate, gameTitle: testTitle, players: testPlayers, From 1c70cbeb5ad20f51e2f296a321ade748814c0557 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:21:18 +0200 Subject: [PATCH 13/21] id gets added to gameSession class at creation --- lib/presentation/views/create_game_view.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 0a679a5..3817f0a 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -9,6 +9,7 @@ import 'package:cabo_counter/services/config_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; +import 'package:uuid/uuid.dart'; enum CreateStatus { noGameTitle, @@ -268,8 +269,8 @@ class _CreateGameViewState extends State { } Future _createGame() async { - /*var uuid = const Uuid(); - id = uuid.v1();*/ + var uuid = const Uuid(); + final String id = uuid.v1(); List players = []; for (var controller in _playerNameTextControllers) { @@ -279,6 +280,7 @@ class _CreateGameViewState extends State { bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; GameSession gameSession = GameSession( + id: id, createdAt: DateTime.now(), gameTitle: _gameTitleTextController.text, players: players, @@ -286,8 +288,8 @@ class _CreateGameViewState extends State { caboPenalty: ConfigService.getCaboPenalty(), isPointsLimitEnabled: isPointsLimitEnabled, ); - final index = await gameManager.addGameSession(gameSession); - final session = gameManager.gameList[index]; + gameManager.addGameSession(gameSession); + final session = gameManager.getGameSessionById(id)!; Navigator.pushReplacement( context, From cadaf4ce997c5ce900ce3dbc4678e4ba19ef2ec4 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:30:20 +0200 Subject: [PATCH 14/21] Cleaned up file --- lib/presentation/views/create_game_view.dart | 176 ++++++++----------- 1 file changed, 75 insertions(+), 101 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 3817f0a..d80d0fb 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -230,7 +230,7 @@ class _CreateGameViewState extends State { .add(TextEditingController()); }); } else { - showFeedbackDialog(CreateStatus.maxPlayers); + _showFeedbackDialog(CreateStatus.maxPlayers); } }, ), @@ -268,37 +268,60 @@ class _CreateGameViewState extends State { ))); } - Future _createGame() async { - var uuid = const Uuid(); - final String id = uuid.v1(); + /// Returns a widget that displays the currently selected game mode in the View. + Text _getDisplayedGameMode() { + if (gameMode == GameMode.none) { + return Text(AppLocalizations.of(context).no_mode_selected); + } else if (gameMode == GameMode.pointLimit) { + return Text( + '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', + style: TextStyle(color: CustomTheme.primaryColor)); + } else { + return Text(AppLocalizations.of(context).unlimited, + style: TextStyle(color: CustomTheme.primaryColor)); + } + } - List players = []; - for (var controller in _playerNameTextControllers) { - players.add(controller.text); + /// Checks all game attributes before creating a new game. + /// If any attribute is invalid, it shows a feedback dialog. + /// If all attributes are valid, it calls the `_createGame` method. + void _checkAllGameAttributes() { + if (_gameTitleTextController.text == '') { + _showFeedbackDialog(CreateStatus.noGameTitle); + return; } - bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + if (gameMode == GameMode.none) { + _showFeedbackDialog(CreateStatus.noModeSelected); + return; + } - GameSession gameSession = GameSession( - id: id, - createdAt: DateTime.now(), - gameTitle: _gameTitleTextController.text, - players: players, - pointLimit: ConfigService.getPointLimit(), - caboPenalty: ConfigService.getCaboPenalty(), - isPointsLimitEnabled: isPointsLimitEnabled, - ); - gameManager.addGameSession(gameSession); - final session = gameManager.getGameSessionById(id)!; + if (_playerNameTextControllers.length < 2) { + _showFeedbackDialog(CreateStatus.minPlayers); + return; + } - Navigator.pushReplacement( - context, - CupertinoPageRoute( - builder: (context) => ActiveGameView(gameSession: session))); + if (!_everyPlayerHasAName()) { + _showFeedbackDialog(CreateStatus.noPlayerName); + return; + } + + _createGame(); + } + + /// Checks if every player has a name. + /// Returns true if all players have a name, false otherwise. + bool _everyPlayerHasAName() { + for (var controller in _playerNameTextControllers) { + if (controller.text == '') { + return false; + } + } + return true; } /// Displays a feedback dialog based on the [CreateStatus]. - void showFeedbackDialog(CreateStatus status) { + void _showFeedbackDialog(CreateStatus status) { final (title, message) = _getDialogContent(status); showCupertinoDialog( @@ -317,63 +340,6 @@ class _CreateGameViewState extends State { }); } - void _checkAllGameAttributes() { - if (_gameTitleTextController.text == '') { - _showDialog(( - AppLocalizations.of(context).no_gameTitle_title, - AppLocalizations.of(context).no_gameTitle_message - )); - return; - } - - if (gameMode == GameMode.none) { - _showDialog( - ( - AppLocalizations.of(context).no_mode_title, - AppLocalizations.of(context).no_mode_message - ), - ); - return; - } - - if (_playerNameTextControllers.length < 2) { - _showDialog( - ( - AppLocalizations.of(context).min_players_title, - AppLocalizations.of(context).min_players_message - ), - ); - return; - } - - if (!everyPlayerHasAName()) { - _showDialog(( - AppLocalizations.of(context).no_name_title, - AppLocalizations.of(context).no_name_message - )); - return; - } - - _createGame(); - } - - void _showDialog((String, String) content) { - final (title, message) = content; - showCupertinoDialog( - context: context, - builder: (context) => CupertinoAlertDialog( - title: Text(title), - content: Text(message), - actions: [ - CupertinoDialogAction( - child: Text(AppLocalizations.of(context).ok), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ); - } - /// Returns the title and message for the dialog based on the [CreateStatus]. (String, String) _getDialogContent(CreateStatus status) { switch (status) { @@ -406,28 +372,36 @@ class _CreateGameViewState extends State { } } - /// Checks if every player has a name. - /// Returns true if all players have a name, false otherwise. - bool everyPlayerHasAName() { - for (var controller in _playerNameTextControllers) { - if (controller.text == '') { - return false; - } - } - return true; - } + /// Creates a new gameSession and navigates to the active game view. + /// This method creates a new gameSession object with the provided attributes in the text fields. + /// It then adds the game session to the game manager and navigates to the active game view. + void _createGame() { + var uuid = const Uuid(); + final String id = uuid.v1(); - Text _getDisplayedGameMode() { - if (gameMode == GameMode.none) { - return Text(AppLocalizations.of(context).no_mode_selected); - } else if (gameMode == GameMode.pointLimit) { - return Text( - '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}', - style: TextStyle(color: CustomTheme.primaryColor)); - } else { - return Text(AppLocalizations.of(context).unlimited, - style: TextStyle(color: CustomTheme.primaryColor)); + List players = []; + for (var controller in _playerNameTextControllers) { + players.add(controller.text); } + + bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; + + GameSession gameSession = GameSession( + id: id, + createdAt: DateTime.now(), + gameTitle: _gameTitleTextController.text, + players: players, + pointLimit: ConfigService.getPointLimit(), + caboPenalty: ConfigService.getCaboPenalty(), + isPointsLimitEnabled: isPointsLimitEnabled, + ); + gameManager.addGameSession(gameSession); + final session = gameManager.getGameSessionById(id)!; + + Navigator.pushReplacement( + context, + CupertinoPageRoute( + builder: (context) => ActiveGameView(gameSession: session))); } @override From fd79698b305b36544c501b56a3e1091d6dc05150 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:36:04 +0200 Subject: [PATCH 15/21] Added docs and dependency --- lib/data/game_manager.dart | 7 ++++++- pubspec.yaml | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 3fc5e54..687b0dd 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -1,5 +1,6 @@ import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; class GameManager extends ChangeNotifier { @@ -21,8 +22,12 @@ class GameManager extends ChangeNotifier { return gameList.indexOf(session); } + /// Retrieves a game session by its id. + /// Takes a String [id] as input. It searches the `gameList` for a session + /// with a matching id and returns it if found. + /// If no session is found, it returns null. GameSession? getGameSessionById(String id) { - return gameList.firstWhere((session) => session.id.toString() == id); + return gameList.firstWhereOrNull((session) => session.id.toString() == id); } /// Removes a game session from the list and sorts it by creation date. diff --git a/pubspec.yaml b/pubspec.yaml index 995d091..c9be09f 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.5.0+568 +version: 0.5.1+568 environment: sdk: ^3.5.4 @@ -29,6 +29,7 @@ dependencies: uuid: ^4.5.1 rate_my_app: ^2.3.2 reorderables: ^0.4.2 + collection: ^1.18.0 dev_dependencies: flutter_test: From fcdad2b6d290590ea64299630581b868948287da Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:38:31 +0200 Subject: [PATCH 16/21] Removed toString --- lib/data/game_manager.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 687b0dd..3ab9c09 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -27,7 +27,7 @@ class GameManager extends ChangeNotifier { /// with a matching id and returns it if found. /// If no session is found, it returns null. GameSession? getGameSessionById(String id) { - return gameList.firstWhereOrNull((session) => session.id.toString() == id); + return gameList.firstWhereOrNull((session) => session.id == id); } /// Removes a game session from the list and sorts it by creation date. From e1b42a547a6986e03b91b8e6e856e36a29eae3b9 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:42:06 +0200 Subject: [PATCH 17/21] Implemented null safety --- lib/presentation/views/create_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index d80d0fb..a1b5894 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -396,7 +396,7 @@ class _CreateGameViewState extends State { isPointsLimitEnabled: isPointsLimitEnabled, ); gameManager.addGameSession(gameSession); - final session = gameManager.getGameSessionById(id)!; + final session = gameManager.getGameSessionById(id) ?? gameSession; Navigator.pushReplacement( context, From 88f17fda6a77b45cf098e50226450911ee6ddc08 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:50:57 +0200 Subject: [PATCH 18/21] Added named parameter --- lib/presentation/views/create_game_view.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index a1b5894..5148537 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -46,6 +46,9 @@ class _CreateGameViewState extends State { /// Maximum number of players allowed in the game. final int maxPlayers = 5; + /// Factor to adjust the view length when the keyboard is visible. + final double keyboardHeightAdjustmentFactor = 0.75; + /// Variable to hold the selected game mode. late GameMode gameMode; @@ -152,8 +155,7 @@ class _CreateGameViewState extends State { }, itemBuilder: (context, index) { return Padding( - key: ValueKey( - 'player_${_playerNameTextControllers[index].hashCode}'), + key: UniqueKey(), padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ @@ -257,7 +259,8 @@ class _CreateGameViewState extends State { KeyboardVisibilityBuilder(builder: (context, visible) { if (visible) { return SizedBox( - height: MediaQuery.of(context).viewInsets.bottom * 0.75, + height: MediaQuery.of(context).viewInsets.bottom * + keyboardHeightAdjustmentFactor, ); } else { return const SizedBox.shrink(); From d93abe35df43f7c8a169636f8952ebdbb3880979 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:53:01 +0200 Subject: [PATCH 19/21] Replaced button with custom button --- lib/presentation/views/round_view.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/presentation/views/round_view.dart b/lib/presentation/views/round_view.dart index f99380e..d2a9da5 100644 --- a/lib/presentation/views/round_view.dart +++ b/lib/presentation/views/round_view.dart @@ -1,6 +1,7 @@ import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; +import 'package:cabo_counter/presentation/widgets/custom_button.dart'; import 'package:cabo_counter/services/local_storage_service.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -228,10 +229,7 @@ class _RoundViewState extends State { padding: const EdgeInsets.fromLTRB(0, 10, 0, 0), child: Center( heightFactor: 1, - child: CupertinoButton( - sizeStyle: CupertinoButtonSize.medium, - borderRadius: BorderRadius.circular(12), - color: CustomTheme.buttonBackgroundColor, + child: CustomButton( onPressed: () async { if (await _showKamikazeSheet(context)) { if (!context.mounted) return; From 5a5c279ea4594ae96539c5b83488e62ad96b9716 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:56:50 +0200 Subject: [PATCH 20/21] Updated key --- lib/presentation/views/create_game_view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/presentation/views/create_game_view.dart b/lib/presentation/views/create_game_view.dart index 5148537..870ea29 100644 --- a/lib/presentation/views/create_game_view.dart +++ b/lib/presentation/views/create_game_view.dart @@ -155,7 +155,7 @@ class _CreateGameViewState extends State { }, itemBuilder: (context, index) { return Padding( - key: UniqueKey(), + key: ValueKey(index), padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( children: [ From 0611154129e64af78dcda76e3cb36d5d0c9da8db Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 20 Jul 2025 20:57:40 +0200 Subject: [PATCH 21/21] Updated addGameSessionMethod --- lib/data/game_manager.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/data/game_manager.dart b/lib/data/game_manager.dart index 3ab9c09..502feb6 100644 --- a/lib/data/game_manager.dart +++ b/lib/data/game_manager.dart @@ -11,14 +11,14 @@ 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. /// Returns the index of the newly added session in the sorted list. - Future addGameSession(GameSession session) async { + int addGameSession(GameSession session) { session.addListener(() { notifyListeners(); // Propagate session changes }); gameList.add(session); gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt)); notifyListeners(); - await LocalStorageService.saveGameSessions(); + LocalStorageService.saveGameSessions(); return gameList.indexOf(session); }