First version of inserting into db

This commit is contained in:
2025-08-22 14:09:09 +02:00
parent 7a420e909a
commit 6b2651a396
19 changed files with 365 additions and 152 deletions

View File

@@ -0,0 +1,88 @@
import 'package:cabo_counter/data/db/database.dart';
import 'package:cabo_counter/data/db/tables/game_session_table.dart';
import 'package:cabo_counter/data/dto/game_session.dart';
import 'package:cabo_counter/data/dto/player.dart';
import 'package:cabo_counter/data/dto/round.dart';
import 'package:drift/drift.dart';
part 'game_session_dao.g.dart';
@DriftAccessor(tables: [GameSessionTable])
class GameSessionDao extends DatabaseAccessor<AppDatabase>
with _$GameSessionDaoMixin {
GameSessionDao(super.db);
/// Retrieves a game session by its ID.
Future<GameSession> getGameSession(String id) async {
final query = select(gameSessionTable)..where((tbl) => tbl.id.equals(id));
final gameSessionResult = await query.getSingle();
List<Player> playerList = await db.playerDao.getPlayersByGameId(id);
List<Round> roundList = await db.roundsDao.getRoundsByGameId(id);
GameSession gameSession = GameSession(
id: gameSessionResult.id,
createdAt: gameSessionResult.createdAt,
gameTitle: gameSessionResult.gameTitle,
players: playerList,
pointLimit: gameSessionResult.pointLimit,
caboPenalty: gameSessionResult.caboPenalty,
isPointsLimitEnabled: gameSessionResult.isPointsLimitEnabled,
isGameFinished: gameSessionResult.isGameFinished,
winner: gameSessionResult.winner ?? '',
roundNumber: gameSessionResult.roundNumber,
roundList: roundList);
return gameSession;
}
/// Retrieves all game sessions from the database.
Future<List<GameSession>> getAllGameSessions() async {
final query = select(gameSessionTable);
final gameSessionResults = await query.get();
List<GameSession> gameSessions = await Future.wait(
gameSessionResults.map((row) async {
List<Player> playerList = await db.playerDao.getPlayersByGameId(row.id);
List<Round> roundList = await db.roundsDao.getRoundsByGameId(row.id);
return GameSession(
id: row.id,
createdAt: row.createdAt,
gameTitle: row.gameTitle,
players: playerList,
pointLimit: row.pointLimit,
caboPenalty: row.caboPenalty,
isPointsLimitEnabled: row.isPointsLimitEnabled,
isGameFinished: row.isGameFinished,
winner: row.winner ?? '',
roundNumber: row.roundNumber,
roundList: roundList,
);
}),
);
return gameSessions;
}
Future<void> insertGameSession(GameSession gameSession) async {
await into(gameSessionTable).insert(
GameSessionTableCompanion.insert(
id: gameSession.id,
createdAt: gameSession.createdAt,
gameTitle: gameSession.gameTitle,
pointLimit: gameSession.pointLimit,
caboPenalty: gameSession.caboPenalty,
isPointsLimitEnabled: gameSession.isPointsLimitEnabled,
isGameFinished: gameSession.isGameFinished,
winner: Value(gameSession.winner),
roundNumber: gameSession.roundNumber,
),
);
db.playerDao.insertPlayers(gameSession.id, gameSession.players);
db.roundsDao.insertMultipleRounds(
gameSession.id, gameSession.roundList, gameSession.players);
}
}

View File

@@ -35,4 +35,22 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
return result.position; return result.position;
} }
/// Inserts a new player into the database.
Future<void> insertPlayers(String gameId, List<Player> players) async {
await batch((batch) {
for (int i = 0; i < players.length; i++) {
batch.insert(
playerTable,
PlayerTableCompanion.insert(
playerId: players[i].playerId,
gameId: gameId,
name: players[i].name,
position: i,
totalScore: players[i].totalScore,
),
);
}
});
}
} }

View File

@@ -11,7 +11,9 @@ class RoundScoresDao extends DatabaseAccessor<AppDatabase>
RoundScoresDao(super.db); RoundScoresDao(super.db);
/// Retrieves all scores for a specific round by its ID. /// Retrieves all scores for a specific round by its ID.
Future<List<RoundScore>> getRoundScoresByRoundId(String roundId) async { /// This method returns a list of [RoundScore] objects sorted by player
/// position in the corresponding gameSession
Future<List<RoundScore>> _getRoundScoresByRoundId(String roundId) async {
final query = select(roundScoresTable) final query = select(roundScoresTable)
..where((tbl) => tbl.roundId.equals(roundId)); ..where((tbl) => tbl.roundId.equals(roundId));
@@ -37,14 +39,20 @@ class RoundScoresDao extends DatabaseAccessor<AppDatabase>
}).toList(); }).toList();
} }
/// Retrieves all scores for a specific round by its ID.
/// This method returns a list of scores sorted by player position in the
/// corresponding gameSession.
Future<List<int>> getScoresByRoundId(String roundId) async { Future<List<int>> getScoresByRoundId(String roundId) async {
List<RoundScore> roundScores = await getRoundScoresByRoundId(roundId); List<RoundScore> roundScores = await _getRoundScoresByRoundId(roundId);
return roundScores.map((score) => score.score).toList(); return roundScores.map((score) => score.score).toList();
} }
/// Retrieves all score updates for a specific round by its ID.
/// This method returns a list of score updates sorted by player position in
/// the corresponding gameSession.
Future<List<int>> getScoreUpdatesByRoundId(String roundId) async { Future<List<int>> getScoreUpdatesByRoundId(String roundId) async {
List<RoundScore> roundScores = await getRoundScoresByRoundId(roundId); List<RoundScore> roundScores = await _getRoundScoresByRoundId(roundId);
return roundScores.map((score) => score.scoreUpdate).toList(); return roundScores.map((score) => score.scoreUpdate).toList();
} }

View File

@@ -0,0 +1,140 @@
import 'package:cabo_counter/data/db/database.dart';
import 'package:cabo_counter/data/db/tables/round_scores_table.dart';
import 'package:cabo_counter/data/db/tables/rounds_table.dart';
import 'package:cabo_counter/data/dto/player.dart';
import 'package:cabo_counter/data/dto/round.dart';
import 'package:drift/drift.dart';
import 'package:uuid/uuid.dart';
part 'rounds_dao.g.dart';
@DriftAccessor(tables: [RoundsTable, RoundScoresTable])
class RoundsDao extends DatabaseAccessor<AppDatabase> with _$RoundsDaoMixin {
RoundsDao(super.db);
/// Retrieves all rounds for a specific game session by its ID.
Future<List<Round>> getRoundsByGameId(String gameId) async {
final query = select(roundsTable)
..where((tbl) => tbl.gameId.equals(gameId));
final roundResult = await query.get();
final roundList = await Future.wait(
roundResult.map((row) async {
final scores = await db.roundScoresDao.getScoresByRoundId(row.roundId);
final roundScores =
await db.roundScoresDao.getScoreUpdatesByRoundId(row.roundId);
return Round(
roundId: row.roundId,
gameId: row.gameId,
roundNum: row.roundNumber,
caboPlayerIndex: row.caboPlayerIndex,
kamikazePlayerIndex: row.kamikazePlayerIndex,
scores: scores,
scoreUpdates: roundScores,
);
}),
);
return roundList;
}
/// Retrieves a specific round by its [gameId] and [roundNumber].
/// Returns null if the round does not exist.
Future<Round?> getRoundByGameIdAndRoundNumber(
String gameId, int roundNumber) async {
final query = select(roundsTable)
..where((tbl) =>
tbl.gameId.equals(gameId) & tbl.roundNumber.equals(roundNumber));
final roundResult = await query.getSingleOrNull();
if (roundResult == null) return null;
final scoreResult = await Future.wait([
db.roundScoresDao.getScoresByRoundId(roundResult.roundId),
db.roundScoresDao.getScoreUpdatesByRoundId(roundResult.roundId),
]);
return Round(
roundId: roundResult.roundId,
gameId: roundResult.gameId,
roundNum: roundResult.roundNumber,
caboPlayerIndex: roundResult.caboPlayerIndex,
kamikazePlayerIndex: roundResult.kamikazePlayerIndex,
scores: scoreResult[0],
scoreUpdates: scoreResult[1],
);
}
/// Inserts a new round into the database.
/// This method creates a new round with a unique ID and inserts it
/// along with the scores for each player in the round.
/// [gameId] is the ID of the game session this round belongs to.
/// [round] is the round data to be inserted.
/// [players] is the list of players in the game session.
Future<void> insertOneRound(
String gameId, Round round, List<Player> players) async {
var uuid = const Uuid();
String roundId = uuid.v1();
final roundEntry = RoundsTableCompanion.insert(
roundId: roundId,
gameId: gameId,
roundNumber: round.roundNum,
caboPlayerIndex: round.caboPlayerIndex,
kamikazePlayerIndex: Value(round.kamikazePlayerIndex),
);
await into(roundsTable).insert(roundEntry);
for (int i = 0; i < players.length; i++) {
final player = players[i];
final roundScoreEntry = RoundScoresTableCompanion.insert(
roundId: roundId,
playerId: player.playerId,
score: round.scores[i],
scoreUpdate: round.scoreUpdates[i],
);
await into(roundScoresTable).insert(roundScoreEntry);
}
}
/// Inserts multiple rounds into the database.
/// This method uses a batch operation to insert all rounds and their scores
/// in a single transaction.
/// [gameId] is the ID of the game session these rounds belong to.
/// [rounds] is the list of rounds to be inserted.
/// [players] is the list of players in the game session.
Future<void> insertMultipleRounds(
String gameId, List<Round> rounds, List<Player> players) async {
var uuid = const Uuid();
await batch((batch) {
final roundEntries = <RoundsTableCompanion>[];
final roundScoreEntries = <RoundScoresTableCompanion>[];
for (final round in rounds) {
final roundId = uuid.v1();
roundEntries.add(RoundsTableCompanion.insert(
roundId: roundId,
gameId: gameId,
roundNumber: round.roundNum,
caboPlayerIndex: round.caboPlayerIndex,
kamikazePlayerIndex: Value(round.kamikazePlayerIndex),
));
for (int i = 0; i < players.length; i++) {
roundScoreEntries.add(RoundScoresTableCompanion.insert(
roundId: roundId,
playerId: players[i].playerId,
score: round.scores[i],
scoreUpdate: round.scoreUpdates[i],
));
}
}
batch.insertAll(roundsTable, roundEntries);
batch.insertAll(roundScoresTable, roundScoreEntries);
});
}
}

View File

@@ -7,4 +7,6 @@ mixin _$RoundsDaoMixin on DatabaseAccessor<AppDatabase> {
$GameSessionTableTable get gameSessionTable => $GameSessionTableTable get gameSessionTable =>
attachedDatabase.gameSessionTable; attachedDatabase.gameSessionTable;
$RoundsTableTable get roundsTable => attachedDatabase.roundsTable; $RoundsTableTable get roundsTable => attachedDatabase.roundsTable;
$RoundScoresTableTable get roundScoresTable =>
attachedDatabase.roundScoresTable;
} }

View File

@@ -1,39 +0,0 @@
import 'package:cabo_counter/data/db/database.dart';
import 'package:cabo_counter/data/db/tables/game_session_table.dart';
import 'package:cabo_counter/data/dto/game_session.dart';
import 'package:cabo_counter/data/dto/player.dart';
import 'package:cabo_counter/data/dto/round.dart';
import 'package:drift/drift.dart';
part 'game_session_dao.g.dart';
@DriftAccessor(tables: [GameSessionTable])
class GameSessionDao extends DatabaseAccessor<AppDatabase>
with _$GameSessionDaoMixin {
GameSessionDao(super.db);
/// Retrieves a game session by its ID.
Future<GameSession> getGameSession(String id) async {
final query = select(gameSessionTable)..where((tbl) => tbl.id.equals(id));
final gameSessionResult = await query.getSingle();
List<Player> playerList = await db.playerDao.getPlayersByGameId(id);
List<Round> roundList = await db.roundsDao.getRoundsByGameId(id);
GameSession gameSession = GameSession(
id: gameSessionResult.id,
createdAt: gameSessionResult.createdAt,
gameTitle: gameSessionResult.gameTitle,
players: playerList.map((player) => player.name).toList(),
pointLimit: gameSessionResult.pointLimit,
caboPenalty: gameSessionResult.caboPenalty,
isPointsLimitEnabled: gameSessionResult.isPointsLimitEnabled,
isGameFinished: gameSessionResult.isGameFinished,
winner: gameSessionResult.winner ?? '',
roundNumber: gameSessionResult.roundNumber,
playerScores: playerList.map((player) => player.totalScore).toList(),
roundList: roundList);
return gameSession;
}
}

View File

@@ -1,39 +0,0 @@
import 'package:cabo_counter/data/db/database.dart';
import 'package:cabo_counter/data/db/tables/rounds_table.dart';
import 'package:cabo_counter/data/dto/round.dart';
import 'package:drift/drift.dart';
part 'rounds_dao.g.dart';
@DriftAccessor(tables: [RoundsTable])
class RoundsDao extends DatabaseAccessor<AppDatabase> with _$RoundsDaoMixin {
RoundsDao(super.db);
/// Retrieves all rounds for a specific game session by its ID.
Future<List<Round>> getRoundsByGameId(String gameId) async {
final query = select(roundsTable)
..where((tbl) => tbl.gameId.equals(gameId));
final roundResult = await query.get();
final roundList = await Future.wait(
roundResult.map((row) async {
final scores = await db.roundScoresDao.getScoresByRoundId(row.roundId);
final roundScores =
await db.roundScoresDao.getScoreUpdatesByRoundId(row.roundId);
return Round(
roundId: row.roundId,
gameId: row.gameId,
roundNum: row.roundNumber,
caboPlayerIndex: row.caboPlayerIndex,
kamikazePlayerIndex: row.kamikazePlayerIndex,
scores: scores,
scoreUpdates: roundScores,
);
}),
);
return roundList;
}
}

View File

@@ -1,7 +1,7 @@
import 'package:cabo_counter/data/db/dao/game_session_dao.dart'; import 'package:cabo_counter/data/dao/game_session_dao.dart';
import 'package:cabo_counter/data/db/dao/player_dao.dart'; import 'package:cabo_counter/data/dao/player_dao.dart';
import 'package:cabo_counter/data/db/dao/round_scores_dao.dart'; import 'package:cabo_counter/data/dao/round_scores_dao.dart';
import 'package:cabo_counter/data/db/dao/rounds_dao.dart'; import 'package:cabo_counter/data/dao/rounds_dao.dart';
import 'package:cabo_counter/data/db/tables/game_session_table.dart'; import 'package:cabo_counter/data/db/tables/game_session_table.dart';
import 'package:cabo_counter/data/db/tables/player_table.dart'; import 'package:cabo_counter/data/db/tables/player_table.dart';
import 'package:cabo_counter/data/db/tables/round_scores_table.dart'; import 'package:cabo_counter/data/db/tables/round_scores_table.dart';

View File

@@ -1,3 +1,4 @@
import 'package:cabo_counter/data/dto/player.dart';
import 'package:cabo_counter/data/dto/round.dart'; import 'package:cabo_counter/data/dto/round.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@@ -16,14 +17,13 @@ class GameSession extends ChangeNotifier {
final String id; final String id;
final DateTime createdAt; final DateTime createdAt;
final String gameTitle; final String gameTitle;
final List<String> players; final List<Player> players;
final int pointLimit; final int pointLimit;
final int caboPenalty; final int caboPenalty;
final bool isPointsLimitEnabled; final bool isPointsLimitEnabled;
bool isGameFinished; bool isGameFinished;
String winner; String winner;
int roundNumber; int roundNumber;
List<int> playerScores;
List<Round> roundList; List<Round> roundList;
GameSession( GameSession(
@@ -37,16 +37,13 @@ class GameSession extends ChangeNotifier {
this.isGameFinished = false, this.isGameFinished = false,
this.winner = '', this.winner = '',
this.roundNumber = 1, this.roundNumber = 1,
this.playerScores = const [], this.roundList = const []});
this.roundList = const []}) {
playerScores = List.filled(players.length, 0);
}
@override @override
toString() { toString() {
return ('GameSession: [id: $id, createdAt: $createdAt, gameTitle: $gameTitle, ' return 'GameSession: [id: $id, createdAt: $createdAt, gameTitle: $gameTitle, '
'isPointsLimitEnabled: $isPointsLimitEnabled, pointLimit: $pointLimit, caboPenalty: $caboPenalty,' 'isPointsLimitEnabled: $isPointsLimitEnabled, pointLimit: $pointLimit, caboPenalty: $caboPenalty,'
' players: $players, playerScores: $playerScores, roundList: $roundList, winner: $winner]'); ' players: $players, roundList: $roundList, winner: $winner]';
} }
/// Converts the GameSession object to a JSON map. /// Converts the GameSession object to a JSON map.
@@ -61,7 +58,6 @@ class GameSession extends ChangeNotifier {
'isGameFinished': isGameFinished, 'isGameFinished': isGameFinished,
'winner': winner, 'winner': winner,
'roundNumber': roundNumber, 'roundNumber': roundNumber,
'playerScores': playerScores,
'roundList': roundList.map((e) => e.toJson()).toList() 'roundList': roundList.map((e) => e.toJson()).toList()
}; };
@@ -70,14 +66,13 @@ class GameSession extends ChangeNotifier {
: id = json['id'] ?? const Uuid().v1(), : id = json['id'] ?? const Uuid().v1(),
createdAt = DateTime.parse(json['createdAt']), createdAt = DateTime.parse(json['createdAt']),
gameTitle = json['gameTitle'], gameTitle = json['gameTitle'],
players = List<String>.from(json['players']), players = List<Player>.from(json['players']),
pointLimit = json['pointLimit'], pointLimit = json['pointLimit'],
caboPenalty = json['caboPenalty'], caboPenalty = json['caboPenalty'],
isPointsLimitEnabled = json['isPointsLimitEnabled'], isPointsLimitEnabled = json['isPointsLimitEnabled'],
isGameFinished = json['isGameFinished'], isGameFinished = json['isGameFinished'],
winner = json['winner'], winner = json['winner'],
roundNumber = json['roundNumber'], roundNumber = json['roundNumber'],
playerScores = List<int>.from(json['playerScores']),
roundList = roundList =
(json['roundList'] as List).map((e) => Round.fromJson(e)).toList(); (json['roundList'] as List).map((e) => Round.fromJson(e)).toList();
@@ -247,8 +242,8 @@ class GameSession extends ChangeNotifier {
bonusPlayers = _checkHundredPointsReached(); bonusPlayers = _checkHundredPointsReached();
bool limitExceeded = false; bool limitExceeded = false;
for (int i = 0; i < playerScores.length; i++) { for (int i = 0; i < players.length; i++) {
if (playerScores[i] > pointLimit) { if (players[i].totalScore > pointLimit) {
isGameFinished = true; isGameFinished = true;
limitExceeded = true; limitExceeded = true;
print('${players[i]} hat die 100 Punkte ueberschritten, ' print('${players[i]} hat die 100 Punkte ueberschritten, '
@@ -271,9 +266,9 @@ class GameSession extends ChangeNotifier {
/// playerScores list. /// playerScores list.
void _sumPoints() { void _sumPoints() {
for (int i = 0; i < players.length; i++) { for (int i = 0; i < players.length; i++) {
playerScores[i] = 0; players[i].totalScore = 0;
for (int j = 0; j < roundList.length; j++) { for (int j = 0; j < roundList.length; j++) {
playerScores[i] += roundList[j].scoreUpdates[i]; players[i].totalScore += roundList[j].scoreUpdates[i];
} }
} }
notifyListeners(); notifyListeners();
@@ -285,7 +280,7 @@ class GameSession extends ChangeNotifier {
List<int> _checkHundredPointsReached() { List<int> _checkHundredPointsReached() {
List<int> bonusPlayers = []; List<int> bonusPlayers = [];
for (int i = 0; i < players.length; i++) { for (int i = 0; i < players.length; i++) {
if (playerScores[i] == pointLimit) { if (players[i].totalScore == pointLimit) {
bonusPlayers.add(i); bonusPlayers.add(i);
print('${players[i]} hat genau 100 Punkte erreicht und bekommt ' print('${players[i]} hat genau 100 Punkte erreicht und bekommt '
'deswegen ${(pointLimit / 2).round()} Punkte abgezogen'); 'deswegen ${(pointLimit / 2).round()} Punkte abgezogen');
@@ -296,15 +291,23 @@ class GameSession extends ChangeNotifier {
return bonusPlayers; return bonusPlayers;
} }
List<int> getPlayerScoresAsList() {
return players.map((player) => player.totalScore).toList();
}
List<String> getPlayerNamesAsList() {
return players.map((player) => player.name).toList();
}
/// Determines the winner of the game session. /// Determines the winner of the game session.
/// It iterates through the player scores and finds the player /// It iterates through the player scores and finds the player
/// with the lowest score. /// with the lowest score.
void setWinner() { void setWinner() {
int minScore = playerScores.reduce((a, b) => a < b ? a : b); int minScore = getPlayerScoresAsList().reduce((a, b) => a < b ? a : b);
List<String> lowestPlayers = []; List<String> lowestPlayers = [];
for (int i = 0; i < players.length; i++) { for (int i = 0; i < players.length; i++) {
if (playerScores[i] == minScore) { if (players[i].totalScore == minScore) {
lowestPlayers.add(players[i]); lowestPlayers.add(players[i].name);
} }
} }
if (lowestPlayers.length > 1) { if (lowestPlayers.length > 1) {

View File

@@ -14,7 +14,7 @@ class Player {
@override @override
String toString() { String toString() {
return '(playerId: $playerId, gameId: $gameId, name: $name, position: $position)'; return 'Player: [playerId: $playerId, gameId: $gameId, name: $name, position: $position]';
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View File

@@ -62,7 +62,7 @@ class _ActiveGameViewState extends State<ActiveGameView> {
builder: (context, _) { builder: (context, _) {
sortedPlayerIndices = _getSortedPlayerIndices(); sortedPlayerIndices = _getSortedPlayerIndices();
denseRanks = _calculateDenseRank( denseRanks = _calculateDenseRank(
gameSession.playerScores, sortedPlayerIndices); gameSession.getPlayerScoresAsList(), sortedPlayerIndices);
return CupertinoPageScaffold( return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar( navigationBar: CupertinoNavigationBar(
previousPageTitle: AppLocalizations.of(context).games, previousPageTitle: AppLocalizations.of(context).games,
@@ -117,7 +117,7 @@ class _ActiveGameViewState extends State<ActiveGameView> {
_getPlacementTextWidget(index), _getPlacementTextWidget(index),
const SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
gameSession.players[playerIndex], gameSession.players[playerIndex].name,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
), ),
@@ -127,7 +127,7 @@ class _ActiveGameViewState extends State<ActiveGameView> {
children: [ children: [
const SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
'${gameSession.playerScores[playerIndex]} ' '${gameSession.getPlayerScoresAsList()[playerIndex]} '
'${AppLocalizations.of(context).points}') '${AppLocalizations.of(context).points}')
], ],
), ),
@@ -258,15 +258,14 @@ class _ActiveGameViewState extends State<ActiveGameView> {
context, context,
CupertinoPageRoute( CupertinoPageRoute(
builder: (_) => CreateGameView( builder: (_) => CreateGameView(
gameTitle: gameTitle: gameSession.gameTitle,
gameSession.gameTitle, gameMode: widget.gameSession
gameMode: widget.gameSession .isPointsLimitEnabled ==
.isPointsLimitEnabled == true
true ? GameMode.pointLimit
? GameMode.pointLimit : GameMode.unlimited,
: GameMode.unlimited, players: gameSession
players: gameSession.players, .getPlayerNamesAsList())));
)));
}, },
), ),
CupertinoListTile( CupertinoListTile(
@@ -374,8 +373,8 @@ class _ActiveGameViewState extends State<ActiveGameView> {
List<int>.generate(gameSession.players.length, (index) => index); List<int>.generate(gameSession.players.length, (index) => index);
// Sort the indices based on the summed points // Sort the indices based on the summed points
playerIndices.sort((a, b) { playerIndices.sort((a, b) {
int scoreA = gameSession.playerScores[a]; int scoreA = gameSession.getPlayerScoresAsList()[a];
int scoreB = gameSession.playerScores[b]; int scoreB = gameSession.getPlayerScoresAsList()[b];
if (scoreA != scoreB) { if (scoreA != scoreB) {
return scoreA.compareTo(scoreB); return scoreA.compareTo(scoreB);
} }
@@ -515,7 +514,8 @@ class _ActiveGameViewState extends State<ActiveGameView> {
/// Plays the confetti animation and shows a dialog with the winner's information. /// Plays the confetti animation and shows a dialog with the winner's information.
Future<void> _playFinishAnimation(BuildContext context) async { Future<void> _playFinishAnimation(BuildContext context) async {
String winner = widget.gameSession.winner; String winner = widget.gameSession.winner;
int winnerPoints = widget.gameSession.playerScores.min;
int winnerPoints = widget.gameSession.getPlayerScoresAsList().min;
int winnerAmount = winner.contains('&') ? 2 : 1; int winnerAmount = winner.contains('&') ? 2 : 1;
confettiController.play(); confettiController.play();

View File

@@ -94,7 +94,7 @@ class _GraphViewState extends State<GraphView> {
List<LineSeries<(int, num), int>> getCumulativeScores() { List<LineSeries<(int, num), int>> getCumulativeScores() {
final rounds = widget.gameSession.roundList; final rounds = widget.gameSession.roundList;
final playerCount = widget.gameSession.players.length; final playerCount = widget.gameSession.players.length;
final playerNames = widget.gameSession.players; final playerNames = widget.gameSession.getPlayerNamesAsList();
List<List<int>> cumulativeScores = List.generate(playerCount, (_) => []); List<List<int>> cumulativeScores = List.generate(playerCount, (_) => []);
List<int> runningTotals = List.filled(playerCount, 0); List<int> runningTotals = List.filled(playerCount, 0);

View File

@@ -68,7 +68,7 @@ class _PointsViewState extends State<PointsView> {
padding: padding:
const EdgeInsets.symmetric(horizontal: 8), const EdgeInsets.symmetric(horizontal: 8),
child: Text( child: Text(
player, player.name,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -120,7 +120,7 @@ class _PointsViewState extends State<PointsView> {
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8), horizontal: 8),
child: Text( child: Text(
player, player.name,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -236,18 +236,20 @@ class _PointsViewState extends State<PointsView> {
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
), ),
)), )),
...widget.gameSession.playerScores.map( ...widget.gameSession
(score) => DataCell( .getPlayerScoresAsList()
Center( .map(
child: Text( (score) => DataCell(
'$score', Center(
style: const TextStyle( child: Text(
fontSize: 20, '$score',
fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
), ),
), ),
),
),
], ],
), ),
], ],

View File

@@ -146,7 +146,7 @@ class _RoundViewState extends State<RoundView> {
.entries .entries
.map((entry) { .map((entry) {
final index = entry.key; final index = entry.key;
final name = entry.value; final player = entry.value;
return MapEntry( return MapEntry(
index, index,
Padding( Padding(
@@ -157,7 +157,7 @@ class _RoundViewState extends State<RoundView> {
child: FittedBox( child: FittedBox(
fit: BoxFit.scaleDown, fit: BoxFit.scaleDown,
child: Text( child: Text(
name, player.name,
textAlign: TextAlign.center, textAlign: TextAlign.center,
maxLines: 1, maxLines: 1,
style: const TextStyle( style: const TextStyle(
@@ -210,7 +210,7 @@ class _RoundViewState extends State<RoundView> {
])) ]))
]), ]),
subtitle: Text( subtitle: Text(
'${widget.gameSession.playerScores[originalIndex]}' '${widget.gameSession.getPlayerScoresAsList()[originalIndex]}'
' ${AppLocalizations.of(context).points}'), ' ${AppLocalizations.of(context).points}'),
trailing: SizedBox( trailing: SizedBox(
width: 100, width: 100,
@@ -329,10 +329,11 @@ class _RoundViewState extends State<RoundView> {
/// Rotates the players list based on the previous round's winner. /// Rotates the players list based on the previous round's winner.
List<String> _getRotatedPlayers() { List<String> _getRotatedPlayers() {
final winnerIndex = _getPreviousRoundWinnerIndex(); final winnerIndex = _getPreviousRoundWinnerIndex();
final playerList = widget.gameSession.getPlayerNamesAsList();
return [ return [
widget.gameSession.players[winnerIndex], playerList[winnerIndex],
...widget.gameSession.players.sublist(winnerIndex + 1), ...playerList.sublist(winnerIndex + 1),
...widget.gameSession.players.sublist(0, winnerIndex) ...playerList.sublist(0, winnerIndex)
]; ];
} }
@@ -358,14 +359,14 @@ class _RoundViewState extends State<RoundView> {
message: Text(AppLocalizations.of(context).who_has_kamikaze), message: Text(AppLocalizations.of(context).who_has_kamikaze),
actions: widget.gameSession.players.asMap().entries.map((entry) { actions: widget.gameSession.players.asMap().entries.map((entry) {
final index = entry.key; final index = entry.key;
final name = entry.value; final player = entry.value;
return CupertinoActionSheetAction( return CupertinoActionSheetAction(
onPressed: () { onPressed: () {
_kamikazePlayerIndex = index; _kamikazePlayerIndex = index;
Navigator.pop(context, true); Navigator.pop(context, true);
}, },
child: Text( child: Text(
name, player.name,
style: TextStyle(color: CustomTheme.kamikazeColor), style: TextStyle(color: CustomTheme.kamikazeColor),
), ),
); );
@@ -494,7 +495,7 @@ class _RoundViewState extends State<RoundView> {
String _getBonusPopupMessageString( String _getBonusPopupMessageString(
int pointLimit, int bonusPoints, List<int> bonusPlayers) { int pointLimit, int bonusPoints, List<int> bonusPlayers) {
List<String> nameList = List<String> nameList =
bonusPlayers.map((i) => widget.gameSession.players[i]).toList(); bonusPlayers.map((i) => widget.gameSession.players[i].name).toList();
String resultText = ''; String resultText = '';
if (nameList.length == 1) { if (nameList.length == 1) {
resultText = AppLocalizations.of(context).bonus_points_message( resultText = AppLocalizations.of(context).bonus_points_message(

View File

@@ -2,6 +2,7 @@ import 'package:cabo_counter/core/constants.dart';
import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/core/custom_theme.dart';
import 'package:cabo_counter/data/dto/game_manager.dart'; import 'package:cabo_counter/data/dto/game_manager.dart';
import 'package:cabo_counter/data/dto/game_session.dart'; import 'package:cabo_counter/data/dto/game_session.dart';
import 'package:cabo_counter/data/dto/player.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/home/active_game/active_game_view.dart'; import 'package:cabo_counter/presentation/views/home/active_game/active_game_view.dart';
import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart'; import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart';
@@ -448,26 +449,38 @@ class _CreateGameViewState extends State<CreateGameView> {
/// It then adds the game session to the game manager and navigates to the active game view. /// It then adds the game session to the game manager and navigates to the active game view.
void _createGame() { void _createGame() {
var uuid = const Uuid(); var uuid = const Uuid();
final String id = uuid.v1(); final String gameId = uuid.v1();
List<String> players = []; // Collect player names from the text controllers.
List<String> playerNames = [];
for (var controller in _playerNameTextControllers) { for (var controller in _playerNameTextControllers) {
players.add(controller.text); playerNames.add(controller.text);
}
// Create a list of Player objects with unique IDs and the corresponding attributes
List<Player> playerList = [];
for (int i = 0; i < playerNames.length; i++) {
playerList.add(Player(
playerId: uuid.v1(),
gameId: gameId,
name: playerNames[i],
position: i,
));
} }
bool isPointsLimitEnabled = gameMode == GameMode.pointLimit; bool isPointsLimitEnabled = gameMode == GameMode.pointLimit;
GameSession gameSession = GameSession( GameSession gameSession = GameSession(
id: id, id: gameId,
createdAt: DateTime.now(), createdAt: DateTime.now(),
gameTitle: _gameTitleTextController.text, gameTitle: _gameTitleTextController.text,
players: players, players: playerList,
pointLimit: ConfigService.getPointLimit(), pointLimit: ConfigService.getPointLimit(),
caboPenalty: ConfigService.getCaboPenalty(), caboPenalty: ConfigService.getCaboPenalty(),
isPointsLimitEnabled: isPointsLimitEnabled, isPointsLimitEnabled: isPointsLimitEnabled,
isGameFinished: false); isGameFinished: false);
gameManager.addGameSession(gameSession); gameManager.addGameSession(gameSession);
final session = gameManager.getGameSessionById(id) ?? gameSession; final session = gameManager.getGameSessionById(gameId) ?? gameSession;
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,

View File

@@ -1,9 +1,25 @@
import 'package:cabo_counter/data/dto/game_session.dart'; import 'package:cabo_counter/data/dto/game_session.dart';
import 'package:cabo_counter/data/dto/player.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
late GameSession session; late GameSession session;
final testPlayers = ['Alice', 'Bob', 'Charlie']; final testPlayers = [
Player(
name: 'Alice',
totalScore: 0,
playerId: '0',
gameId: 'abc',
position: 0),
Player(
name: 'Bob', totalScore: 0, playerId: '1', gameId: 'abc', position: 1),
Player(
name: 'Charlie',
totalScore: 0,
playerId: '2',
gameId: 'abc',
position: 2)
];
final testDate = DateTime(2023, 1, 1); final testDate = DateTime(2023, 1, 1);
const testTitle = 'Test Game'; const testTitle = 'Test Game';
@@ -23,7 +39,7 @@ void main() {
test('Initialization', () { test('Initialization', () {
expect(session.gameTitle, testTitle); expect(session.gameTitle, testTitle);
expect(session.players, testPlayers); expect(session.players, testPlayers);
expect(session.playerScores, [0, 0, 0]); expect(session.getPlayerScoresAsList(), [0, 0, 0]);
expect(session.roundNumber, 1); expect(session.roundNumber, 1);
expect(session.isGameFinished, isFalse); expect(session.isGameFinished, isFalse);
expect(session.winner, isEmpty); expect(session.winner, isEmpty);
@@ -141,14 +157,14 @@ void main() {
session.addRoundScoresToList(1, [10, 20, 30], [10, 20, 30], 0); session.addRoundScoresToList(1, [10, 20, 30], [10, 20, 30], 0);
session.addRoundScoresToList(2, [5, 5, 5], [5, 5, 5], 1); session.addRoundScoresToList(2, [5, 5, 5], [5, 5, 5], 1);
session.testingSumPoints(); session.testingSumPoints();
expect(session.playerScores, [15, 25, 35]); expect(session.getPlayerScoresAsList(), [15, 25, 35]);
}); });
test('_checkHundredPointsReached via updatePoints', () { test('_checkHundredPointsReached via updatePoints', () {
session.addRoundScoresToList(1, [50, 5, 15], [50, 0, 15], 1); session.addRoundScoresToList(1, [50, 5, 15], [50, 0, 15], 1);
session.addRoundScoresToList(2, [50, 5, 15], [50, 0, 15], 1); session.addRoundScoresToList(2, [50, 5, 15], [50, 0, 15], 1);
session.updatePoints(); session.updatePoints();
expect(session.playerScores, equals([50, 0, 30])); expect(session.getPlayerScoresAsList(), equals([50, 0, 30]));
}); });
test('_setWinner via updatePoints', () { test('_setWinner via updatePoints', () {