Merge pull request #79 from flixcoo/enhance/34-improvement-for-visual-hierachy
Improvement for visual hierarchy
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import 'package:cabo_counter/data/game_session.dart';
|
import 'package:cabo_counter/data/game_session.dart';
|
||||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
class GameManager extends ChangeNotifier {
|
class GameManager extends ChangeNotifier {
|
||||||
@@ -10,17 +11,25 @@ class GameManager extends ChangeNotifier {
|
|||||||
/// sorts the list in descending order based on the creation date, and notifies listeners of the change.
|
/// 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.
|
/// It also saves the updated game sessions to local storage.
|
||||||
/// Returns the index of the newly added session in the sorted list.
|
/// Returns the index of the newly added session in the sorted list.
|
||||||
Future<int> addGameSession(GameSession session) async {
|
int addGameSession(GameSession session) {
|
||||||
session.addListener(() {
|
session.addListener(() {
|
||||||
notifyListeners(); // Propagate session changes
|
notifyListeners(); // Propagate session changes
|
||||||
});
|
});
|
||||||
gameList.add(session);
|
gameList.add(session);
|
||||||
gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
gameList.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await LocalStorageService.saveGameSessions();
|
LocalStorageService.saveGameSessions();
|
||||||
return gameList.indexOf(session);
|
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.firstWhereOrNull((session) => session.id == id);
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes a game session from the list and sorts it by creation date.
|
/// 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`,
|
/// 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.
|
/// sorts the list in descending order based on the creation date, and notifies listeners of the change.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
/// [isGameFinished] is a boolean indicating if the game has ended yet.
|
/// [isGameFinished] is a boolean indicating if the game has ended yet.
|
||||||
/// [winner] is the name of the player who won the game.
|
/// [winner] is the name of the player who won the game.
|
||||||
class GameSession extends ChangeNotifier {
|
class GameSession extends ChangeNotifier {
|
||||||
late String id;
|
final String id;
|
||||||
final DateTime createdAt;
|
final DateTime createdAt;
|
||||||
final String gameTitle;
|
final String gameTitle;
|
||||||
final List<String> players;
|
final List<String> players;
|
||||||
@@ -27,6 +27,7 @@ class GameSession extends ChangeNotifier {
|
|||||||
List<Round> roundList = [];
|
List<Round> roundList = [];
|
||||||
|
|
||||||
GameSession({
|
GameSession({
|
||||||
|
required this.id,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.gameTitle,
|
required this.gameTitle,
|
||||||
required this.players,
|
required this.players,
|
||||||
@@ -35,8 +36,6 @@ class GameSession extends ChangeNotifier {
|
|||||||
required this.isPointsLimitEnabled,
|
required this.isPointsLimitEnabled,
|
||||||
}) {
|
}) {
|
||||||
playerScores = List.filled(players.length, 0);
|
playerScores = List.filled(players.length, 0);
|
||||||
var uuid = const Uuid();
|
|
||||||
id = uuid.v1();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
"min_players_title": "Zu wenig Spieler:innen",
|
"min_players_title": "Zu wenig Spieler:innen",
|
||||||
"min_players_message": "Es müssen mindestens 2 Spieler:innen hinzugefügt werden",
|
"min_players_message": "Es müssen mindestens 2 Spieler:innen hinzugefügt werden",
|
||||||
"no_name_title": "Kein Name",
|
"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",
|
"select_game_mode": "Spielmodus auswählen",
|
||||||
"no_mode_selected": "Wähle einen Spielmodus",
|
"no_mode_selected": "Wähle einen Spielmodus",
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ abstract class AppLocalizations {
|
|||||||
/// No description provided for @no_name_message.
|
/// No description provided for @no_name_message.
|
||||||
///
|
///
|
||||||
/// In de, this message translates to:
|
/// 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;
|
String get no_name_message;
|
||||||
|
|
||||||
/// No description provided for @select_game_mode.
|
/// No description provided for @select_game_mode.
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get no_name_title => 'Kein Name';
|
String get no_name_title => 'Kein Name';
|
||||||
|
|
||||||
@override
|
@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
|
@override
|
||||||
String get select_game_mode => 'Spielmodus auswählen';
|
String get select_game_mode => 'Spielmodus auswählen';
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ import 'package:cabo_counter/data/game_session.dart';
|
|||||||
import 'package:cabo_counter/l10n/generated/app_localizations.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/active_game_view.dart';
|
||||||
import 'package:cabo_counter/presentation/views/mode_selection_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:cabo_counter/services/config_service.dart';
|
||||||
import 'package:flutter/cupertino.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 {
|
enum CreateStatus {
|
||||||
noGameTitle,
|
noGameTitle,
|
||||||
@@ -42,6 +46,9 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
/// Maximum number of players allowed in the game.
|
/// Maximum number of players allowed in the game.
|
||||||
final int maxPlayers = 5;
|
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.
|
/// Variable to hold the selected game mode.
|
||||||
late GameMode gameMode;
|
late GameMode gameMode;
|
||||||
|
|
||||||
@@ -64,120 +71,92 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
previousPageTitle: AppLocalizations.of(context).overview,
|
previousPageTitle: AppLocalizations.of(context).overview,
|
||||||
middle: Text(AppLocalizations.of(context).new_game),
|
middle: Text(AppLocalizations.of(context).new_game),
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Center(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
|
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
|
||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(context).game,
|
AppLocalizations.of(context).game,
|
||||||
style: CustomTheme.rowTitle,
|
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(),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
onTap: () async {
|
|
||||||
final selectedMode = await Navigator.push(
|
|
||||||
context,
|
|
||||||
CupertinoPageRoute(
|
|
||||||
builder: (context) => ModeSelectionMenu(
|
|
||||||
pointLimit: ConfigService.getPointLimit(),
|
|
||||||
showDeselection: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
gameMode = selectedMode ?? gameMode;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
|
||||||
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
|
child: CupertinoTextField(
|
||||||
child: Text(
|
decoration: const BoxDecoration(),
|
||||||
AppLocalizations.of(context).players,
|
maxLength: 16,
|
||||||
style: CustomTheme.rowTitle,
|
prefix: Text(AppLocalizations.of(context).name),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
placeholder: AppLocalizations.of(context).game_title,
|
||||||
|
controller: _gameTitleTextController,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Expanded(
|
padding: const EdgeInsets.fromLTRB(15, 10, 10, 0),
|
||||||
child: ListView.builder(
|
child: CupertinoTextField(
|
||||||
itemCount: _playerNameTextControllers.length + 1,
|
decoration: const BoxDecoration(),
|
||||||
itemBuilder: (context, index) {
|
readOnly: true,
|
||||||
if (index == _playerNameTextControllers.length) {
|
prefix: Text(AppLocalizations.of(context).mode),
|
||||||
return Padding(
|
suffix: Row(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
children: [
|
||||||
child: CupertinoButton(
|
_getDisplayedGameMode(),
|
||||||
padding: EdgeInsets.zero,
|
const SizedBox(width: 3),
|
||||||
child: Row(
|
const CupertinoListTileChevron(),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
],
|
||||||
children: [
|
),
|
||||||
const Icon(
|
onTap: () async {
|
||||||
CupertinoIcons.add_circled,
|
final selectedMode = await Navigator.push(
|
||||||
color: CupertinoColors.activeGreen,
|
context,
|
||||||
size: 25,
|
CupertinoPageRoute(
|
||||||
),
|
builder: (context) => ModeSelectionMenu(
|
||||||
const SizedBox(width: 8),
|
pointLimit: ConfigService.getPointLimit(),
|
||||||
Text(
|
showDeselection: false,
|
||||||
AppLocalizations.of(context).add_player,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: CupertinoColors.activeGreen,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
onPressed: () {
|
|
||||||
if (_playerNameTextControllers.length < maxPlayers) {
|
|
||||||
setState(() {
|
|
||||||
_playerNameTextControllers
|
|
||||||
.add(TextEditingController());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
showFeedbackDialog(CreateStatus.maxPlayers);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
// Spieler-Einträge
|
setState(() {
|
||||||
|
gameMode = selectedMode ?? gameMode;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context).players,
|
||||||
|
style: CustomTheme.rowTitle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
key: ValueKey(index),
|
||||||
vertical: 8.0, horizontal: 5),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
CupertinoButton(
|
CupertinoButton(
|
||||||
@@ -204,78 +183,148 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
decoration: const BoxDecoration(),
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Center(
|
padding: const EdgeInsets.fromLTRB(0, 0, 0, 50),
|
||||||
child: CupertinoButton(
|
child: Center(
|
||||||
padding: EdgeInsets.zero,
|
key: const ValueKey('create_game_button'),
|
||||||
child: Row(
|
child: CustomButton(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Text(
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
AppLocalizations.of(context).create_game,
|
AppLocalizations.of(context).create_game,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: CupertinoColors.activeGreen,
|
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<String> 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)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
KeyboardVisibilityBuilder(builder: (context, visible) {
|
||||||
],
|
if (visible) {
|
||||||
))));
|
return SizedBox(
|
||||||
|
height: MediaQuery.of(context).viewInsets.bottom *
|
||||||
|
keyboardHeightAdjustmentFactor,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameMode == GameMode.none) {
|
||||||
|
_showFeedbackDialog(CreateStatus.noModeSelected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_playerNameTextControllers.length < 2) {
|
||||||
|
_showFeedbackDialog(CreateStatus.minPlayers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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].
|
/// Displays a feedback dialog based on the [CreateStatus].
|
||||||
void showFeedbackDialog(CreateStatus status) {
|
void _showFeedbackDialog(CreateStatus status) {
|
||||||
final (title, message) = _getDialogContent(status);
|
final (title, message) = _getDialogContent(status);
|
||||||
|
|
||||||
showCupertinoDialog(
|
showCupertinoDialog(
|
||||||
@@ -326,15 +375,36 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if every player has a name.
|
/// Creates a new gameSession and navigates to the active game view.
|
||||||
/// Returns true if all players have a name, false otherwise.
|
/// This method creates a new gameSession object with the provided attributes in the text fields.
|
||||||
bool everyPlayerHasAName() {
|
/// 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();
|
||||||
|
|
||||||
|
List<String> players = [];
|
||||||
for (var controller in _playerNameTextControllers) {
|
for (var controller in _playerNameTextControllers) {
|
||||||
if (controller.text == '') {
|
players.add(controller.text);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
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) ?? gameSession;
|
||||||
|
|
||||||
|
Navigator.pushReplacement(
|
||||||
|
context,
|
||||||
|
CupertinoPageRoute(
|
||||||
|
builder: (context) => ActiveGameView(gameSession: session)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:cabo_counter/core/custom_theme.dart';
|
import 'package:cabo_counter/core/custom_theme.dart';
|
||||||
import 'package:cabo_counter/data/game_session.dart';
|
import 'package:cabo_counter/data/game_session.dart';
|
||||||
import 'package:cabo_counter/l10n/generated/app_localizations.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:cabo_counter/services/local_storage_service.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@@ -228,10 +229,7 @@ class _RoundViewState extends State<RoundView> {
|
|||||||
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
|
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
|
||||||
child: Center(
|
child: Center(
|
||||||
heightFactor: 1,
|
heightFactor: 1,
|
||||||
child: CupertinoButton(
|
child: CustomButton(
|
||||||
sizeStyle: CupertinoButtonSize.medium,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
color: CustomTheme.buttonBackgroundColor,
|
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (await _showKamikazeSheet(context)) {
|
if (await _showKamikazeSheet(context)) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class _TabViewState extends State<TabView> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoTabScaffold(
|
return CupertinoTabScaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
tabBar: CupertinoTabBar(
|
tabBar: CupertinoTabBar(
|
||||||
backgroundColor: CustomTheme.mainElementBackgroundColor,
|
backgroundColor: CustomTheme.mainElementBackgroundColor,
|
||||||
iconSize: 27,
|
iconSize: 27,
|
||||||
|
|||||||
19
lib/presentation/widgets/custom_button.dart
Normal file
19
lib/presentation/widgets/custom_button.dart
Normal file
@@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ name: cabo_counter
|
|||||||
description: "Mobile app for the card game Cabo"
|
description: "Mobile app for the card game Cabo"
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.5.0+544
|
version: 0.5.1+568
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@@ -28,6 +28,8 @@ dependencies:
|
|||||||
syncfusion_flutter_charts: ^30.1.37
|
syncfusion_flutter_charts: ^30.1.37
|
||||||
uuid: ^4.5.1
|
uuid: ^4.5.1
|
||||||
rate_my_app: ^2.3.2
|
rate_my_app: ^2.3.2
|
||||||
|
reorderables: ^0.4.2
|
||||||
|
collection: ^1.18.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
session = GameSession(
|
session = GameSession(
|
||||||
|
id: '1',
|
||||||
createdAt: testDate,
|
createdAt: testDate,
|
||||||
gameTitle: testTitle,
|
gameTitle: testTitle,
|
||||||
players: testPlayers,
|
players: testPlayers,
|
||||||
|
|||||||
Reference in New Issue
Block a user