ruleset is now a required game enum parameter
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m1s
Pull Request Pipeline / lint (pull_request) Successful in 2m7s

This commit is contained in:
gelbeinhalb
2026-01-23 11:54:37 +01:00
parent 118b316a35
commit b0cb385756
15 changed files with 94 additions and 40 deletions

View File

@@ -29,24 +29,27 @@ enum ImportResult {
/// - [ExportResult.unknownException]: An exception occurred during export.
enum ExportResult { success, canceled, unknownException }
/// Different rulesets available for matches
/// - [Ruleset.singleWinner]: The match is won by a single player
/// - [Ruleset.singleLoser]: The match is lost by a single player
/// - [Ruleset.mostPoints]: The player with the most points wins.
/// - [Ruleset.leastPoints]: The player with the fewest points wins.
enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints }
/// Different rulesets available for games
/// - [Ruleset.highestScore]: The player with the highest score wins.
/// - [Ruleset.lowestScore]: The player with the lowest score wins.
/// - [Ruleset.singleWinner]: The match is won by a single player.
/// - [Ruleset.singleLoser]: The match has a single loser.
/// - [Ruleset.multipleWinners]: Multiple players can be winners.
enum Ruleset { highestScore, lowestScore, singleWinner, singleLoser, multipleWinners }
/// Translates a [Ruleset] enum value to its corresponding localized string.
String translateRulesetToString(Ruleset ruleset, BuildContext context) {
final loc = AppLocalizations.of(context);
switch (ruleset) {
case Ruleset.highestScore:
return loc.highest_score;
case Ruleset.lowestScore:
return loc.lowest_score;
case Ruleset.singleWinner:
return loc.single_winner;
case Ruleset.singleLoser:
return loc.single_loser;
case Ruleset.mostPoints:
return loc.most_points;
case Ruleset.leastPoints:
return loc.least_points;
case Ruleset.multipleWinners:
return loc.multiple_winners;
}
}

View File

@@ -2,6 +2,7 @@ import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/game_table.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/core/enums.dart';
part 'game_dao.g.dart';
@@ -18,7 +19,7 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
(row) => Game(
id: row.id,
name: row.name,
ruleset: row.ruleset,
ruleset: Ruleset.values.firstWhere((e) => e.name == row.ruleset),
description: row.description,
color: row.color,
icon: row.icon,
@@ -35,7 +36,7 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
return Game(
id: result.id,
name: result.name,
ruleset: result.ruleset,
ruleset: Ruleset.values.firstWhere((e) => e.name == result.ruleset),
description: result.description,
color: result.color,
icon: result.icon,
@@ -52,7 +53,7 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
GameTableCompanion.insert(
id: game.id,
name: game.name,
ruleset: game.ruleset ?? '',
ruleset: game.ruleset.name,
description: game.description,
color: game.color,
icon: Value(game.icon),
@@ -78,7 +79,7 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
(game) => GameTableCompanion.insert(
id: game.id,
name: game.name,
ruleset: game.ruleset ?? '',
ruleset: game.ruleset.name,
description: game.description,
color: game.color,
icon: Value(game.icon),
@@ -122,10 +123,10 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
/// Updates the ruleset of the game with the given [gameId].
Future<void> updateGameRuleset({
required String gameId,
required String newRuleset,
required Ruleset newRuleset,
}) async {
await (update(gameTable)..where((g) => g.id.equals(gameId))).write(
GameTableCompanion(ruleset: Value(newRuleset)),
GameTableCompanion(ruleset: Value(newRuleset.name)),
);
}

View File

@@ -127,7 +127,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
(game) => GameTableCompanion.insert(
id: game.id,
name: game.name,
ruleset: game.ruleset ?? '',
ruleset: game.ruleset.name,
description: game.description,
color: game.color,
icon: Value(game.icon),

View File

@@ -1,11 +1,12 @@
import 'package:clock/clock.dart';
import 'package:uuid/uuid.dart';
import 'package:game_tracker/core/enums.dart';
class Game {
final String id;
final DateTime createdAt;
final String name;
final String? ruleset;
final Ruleset ruleset;
final String description;
final String color;
final String? icon;
@@ -14,7 +15,7 @@ class Game {
String? id,
DateTime? createdAt,
required this.name,
this.ruleset,
required this.ruleset,
required this.description,
required this.color,
this.icon,
@@ -31,7 +32,7 @@ class Game {
: id = json['id'],
createdAt = DateTime.parse(json['createdAt']),
name = json['name'],
ruleset = json['ruleset'],
ruleset = Ruleset.values.firstWhere((e) => e.name == json['ruleset']),
description = json['description'],
color = json['color'],
icon = json['icon'];
@@ -41,7 +42,7 @@ class Game {
'id': id,
'createdAt': createdAt.toIso8601String(),
'name': name,
'ruleset': ruleset,
'ruleset': ruleset.name,
'description': description,
'color': color,
'icon': icon,

View File

@@ -82,6 +82,9 @@
"settings": "Einstellungen",
"single_loser": "Ein:e Verlierer:in",
"single_winner": "Ein:e Gewinner:in",
"highest_score": "Höchste Punkte",
"lowest_score": "Niedrigste Punkte",
"multiple_winners": "Mehrere Gewinner:innen",
"statistics": "Statistiken",
"stats": "Statistiken",
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",

View File

@@ -380,6 +380,9 @@
"settings": "Settings",
"single_loser": "Single Loser",
"single_winner": "Single Winner",
"highest_score": "Highest Score",
"lowest_score": "Lowest Score",
"multiple_winners": "Multiple Winners",
"statistics": "Statistics",
"stats": "Stats",
"successfully_added_player": "Successfully added player {playerName}",

View File

@@ -590,6 +590,24 @@ abstract class AppLocalizations {
/// **'Single Winner'**
String get single_winner;
/// No description provided for @highest_score.
///
/// In en, this message translates to:
/// **'Highest Score'**
String get highest_score;
/// No description provided for @lowest_score.
///
/// In en, this message translates to:
/// **'Lowest Score'**
String get lowest_score;
/// No description provided for @multiple_winners.
///
/// In en, this message translates to:
/// **'Multiple Winners'**
String get multiple_winners;
/// Statistics tab label
///
/// In en, this message translates to:

View File

@@ -266,6 +266,15 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get single_winner => 'Ein:e Gewinner:in';
@override
String get highest_score => 'Höchste Punkte';
@override
String get lowest_score => 'Niedrigste Punkte';
@override
String get multiple_winners => 'Mehrere Gewinner:innen';
@override
String get statistics => 'Statistiken';

View File

@@ -266,6 +266,15 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get single_winner => 'Single Winner';
@override
String get highest_score => 'Highest Score';
@override
String get lowest_score => 'Lowest Score';
@override
String get multiple_winners => 'Multiple Winners';
@override
String get statistics => 'Statistics';

View File

@@ -100,7 +100,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
}
List<(String, String, Ruleset)> games = [
('Example Game 1', 'This is a description', Ruleset.leastPoints),
('Example Game 1', 'This is a description', Ruleset.lowestScore),
('Example Game 2', '', Ruleset.singleWinner),
];
@@ -201,7 +201,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
gameToUse = Game(
name: selectedGame.$1,
description: selectedGame.$2,
ruleset: selectedGame.$3.name,
ruleset: selectedGame.$3,
color: '0xFF000000',
);
} else {
@@ -210,7 +210,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
gameToUse = Game(
name: selectedGame.$1,
description: selectedGame.$2,
ruleset: selectedGame.$3.name,
ruleset: selectedGame.$3,
color: '0xFF000000',
);
}

View File

@@ -4,6 +4,7 @@ import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/core/enums.dart';
void main() {
late AppDatabase database;
@@ -24,7 +25,7 @@ void main() {
withClock(fakeClock, () {
testGame1 = Game(
name: 'Chess',
ruleset: 'winner.single',
ruleset: Ruleset.singleWinner,
description: 'A classic strategy game',
color: '0xFF0000FF',
icon: 'chess_icon',
@@ -32,14 +33,15 @@ void main() {
testGame2 = Game(
id: 'game2',
name: 'Poker',
ruleset: 'Texas Hold\'em rules',
description: 'winner.multiple',
ruleset: Ruleset.multipleWinners,
description: 'Card game with multiple winners',
color: '0xFFFF0000',
icon: 'poker_icon',
);
testGame3 = Game(
id: 'game3',
name: 'Monopoly',
ruleset: Ruleset.highestScore,
description: 'A board game about real estate',
color: '0xFF000000',
);
@@ -131,7 +133,7 @@ void main() {
// Verifies that a game with null optional fields can be added and retrieved.
test('addGame handles game with null optional fields', () async {
final gameWithNulls = Game(name: 'Simple Game', description: 'A simple game', color: '0xFF000000');
final gameWithNulls = Game(name: 'Simple Game', ruleset: Ruleset.lowestScore, description: 'A simple game', color: '0xFF000000');
final result = await database.gameDao.addGame(game: gameWithNulls);
expect(result, true);
@@ -269,13 +271,13 @@ void main() {
await database.gameDao.updateGameRuleset(
gameId: testGame1.id,
newRuleset: 'New ruleset for chess',
newRuleset: Ruleset.highestScore,
);
final updatedGame = await database.gameDao.getGameById(
gameId: testGame1.id,
);
expect(updatedGame.ruleset, 'New ruleset for chess');
expect(updatedGame.ruleset, Ruleset.highestScore);
expect(updatedGame.name, testGame1.name);
});
@@ -283,7 +285,7 @@ void main() {
test('updateGameRuleset does nothing for non-existent game', () async {
await database.gameDao.updateGameRuleset(
gameId: 'non-existent-id',
newRuleset: 'New Ruleset',
newRuleset: Ruleset.lowestScore,
);
final allGames = await database.gameDao.getAllGames();
@@ -455,6 +457,7 @@ void main() {
test('Game with special characters in name is stored correctly', () async {
final specialGame = Game(
name: 'Game\'s & "Special" <Name>',
ruleset: Ruleset.multipleWinners,
description: 'Description with émojis 🎮🎲',
color: '0xFF000000',
);
@@ -471,7 +474,7 @@ void main() {
test('Game with empty string fields is stored correctly', () async {
final emptyGame = Game(
name: '',
ruleset: '',
ruleset: Ruleset.singleWinner,
description: '',
icon: '',
color: '0xFF000000',
@@ -482,7 +485,7 @@ void main() {
gameId: emptyGame.id,
);
expect(fetchedGame.name, '');
expect(fetchedGame.ruleset, '');
expect(fetchedGame.ruleset, Ruleset.singleWinner);
expect(fetchedGame.description, '');
expect(fetchedGame.icon, '');
});
@@ -493,7 +496,7 @@ void main() {
final longGame = Game(
name: longString,
description: longString,
ruleset: longString,
ruleset: Ruleset.multipleWinners,
color: '0xFF000000',
);
await database.gameDao.addGame(game: longGame);
@@ -503,7 +506,7 @@ void main() {
);
expect(fetchedGame.name.length, 10000);
expect(fetchedGame.description.length, 10000);
expect(fetchedGame.ruleset?.length, 10000);
expect(fetchedGame.ruleset, Ruleset.multipleWinners);
});
// Verifies that multiple sequential updates to the same game work correctly.

View File

@@ -7,6 +7,7 @@ import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/core/enums.dart';
void main() {
late AppDatabase database;
@@ -48,7 +49,7 @@ void main() {
name: 'Test Group 2',
members: [testPlayer4, testPlayer5],
);
testGame = Game(name: 'Test Game', description: 'A test game', color: '0xFF000000');
testGame = Game(name: 'Test Game', ruleset: Ruleset.singleWinner, description: 'A test game', color: '0xFF000000');
testMatch1 = Match(
name: 'First Test Match',
game: testGame,

View File

@@ -8,6 +8,7 @@ import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/data/dto/team.dart';
import 'package:game_tracker/core/enums.dart';
void main() {
late AppDatabase database;
@@ -46,7 +47,7 @@ void main() {
name: 'Test Group',
members: [testPlayer1, testPlayer2, testPlayer3],
);
testGame = Game(name: 'Test Game', description: 'A test game', color: '0xFF000000');
testGame = Game(name: 'Test Game', ruleset: Ruleset.singleWinner, description: 'A test game', color: '0xFF000000');
testMatchOnlyGroup = Match(
name: 'Test Match with Group',
game: testGame,

View File

@@ -6,6 +6,7 @@ import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/core/enums.dart';
void main() {
late AppDatabase database;
@@ -31,7 +32,7 @@ void main() {
testPlayer1 = Player(name: 'Alice');
testPlayer2 = Player(name: 'Bob');
testPlayer3 = Player(name: 'Charlie');
testGame = Game(name: 'Test Game', description: 'A test game', color: '0xFF000000');
testGame = Game(name: 'Test Game', ruleset: Ruleset.singleWinner, description: 'A test game', color: '0xFF000000');
testMatch1 = Match(
name: 'Test Match 1',
game: testGame,

View File

@@ -7,6 +7,7 @@ import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/data/dto/team.dart';
import 'package:game_tracker/core/enums.dart';
void main() {
late AppDatabase database;
@@ -48,8 +49,8 @@ void main() {
name: 'Team Gamma',
members: [testPlayer1, testPlayer3],
);
testGame1 = Game(name: 'Game 1', description: 'Test game 1', color: '0xFF000000');
testGame2 = Game(name: 'Game 2', description: 'Test game 2', color: '0xFF000000');
testGame1 = Game(name: 'Game 1', ruleset: Ruleset.singleWinner, description: 'Test game 1', color: '0xFF000000');
testGame2 = Game(name: 'Game 2', ruleset: Ruleset.highestScore, description: 'Test game 2', color: '0xFF000000');
});
await database.playerDao.addPlayersAsList(